<?xml version="1.0"?>
<paste-with-annotations>
  <paste>
    <number>
      <integer>96722</integer>
    </number>
    <user>
      <string>lue</string>
    </user>
    <title>
      <string>Radix conversion fix</string>
    </title>
    <contents>
      <string>From cc5f6714a7acfab5c18eef2da04cec92e964f3be Mon Sep 17 00:00:00 2001
From: Lue &lt;lue@twigil.drangle.com&gt;
Date: Sun, 21 Mar 2010 13:31:24 -0700
Subject: [PATCH] Put in support for fractional numbers (:16&lt;A.4&gt;) and other base scanning (:2&lt;0o10&gt;) into the radcalc function.

---
 src/Perl6/Actions.pm |    3 +-
 src/builtins/Num.pir |  176 ++++++++++++++++++++++++++++++++------------------
 2 files changed, 114 insertions(+), 65 deletions(-)

diff --git a/src/Perl6/Actions.pm b/src/Perl6/Actions.pm
index a277932..94fc988 100644
--- a/src/Perl6/Actions.pm
+++ b/src/Perl6/Actions.pm
@@ -2136,11 +2136,12 @@ method rad_number($/) {
     } else {
         my $intpart  := $&lt;intpart&gt;.Str;
         my $fracpart := $&lt;fracpart&gt; ?? $&lt;fracpart&gt;.Str !! &quot;0&quot;;
+        my $intfrac  := $intpart ~ $fracpart; #the dot is a part of $fracpart, so no need for ~ &quot;.&quot; ~
         my $base     := $&lt;base&gt; ?? +($&lt;base&gt;[0].Str) !! 0;
         my $exp      := $&lt;exp&gt; ?? +($&lt;exp&gt;[0].Str) !! 0;
 
         make PAST::Op.new( :name('&amp;radcalc'), :pasttype('call'),
-            $radix, $intpart, $fracpart, $base, $exp
+            $radix, $intfrac, $base, $exp
         );
     }
 }
diff --git a/src/builtins/Num.pir b/src/builtins/Num.pir
index 6c9167b..f5d502b 100644
--- a/src/builtins/Num.pir
+++ b/src/builtins/Num.pir
@@ -124,74 +124,122 @@ Value type, so return self.
 .namespace []
 
 .sub '&amp;radcalc'
-    .param int radix
-    .param string intpart
-    .param string fracpart     :optional
-    .param int    has_fracpart :opt_flag
-    .param num    base         :optional
+    #this code was rewritten &amp; optimized to be as dumb as possible. --lue
+    .param int    radix #to all mathematicians, I know fractional radixes are possible. We programmers are taking baby steps :)
+    .param string number
+    .param num    base         :optional #as in exponents, not as in radixes
     .param int    has_base     :opt_flag
-    .param num    exp          :optional
-    .param int    has_exp      :opt_flag
-    .local num    result, fracdivisor, magnitude
-    .local pmc    it
-
-    if radix &lt;= 1 goto err_range
-    if radix &gt; 36 goto err_range
-
-    result       = 0.0
-    fracdivisor = 1.0
-
-    $P0 = split '', intpart
-    it = iter $P0
-
-  lp1: # Accumulate over decimal part
-    unless it goto ex1
-    $S0 = shift it
-    $S0 = downcase $S0
-    if $S0 == &quot;_&quot; goto lp1
-    $I0 = index &quot;0123456789abcdefghijklmnopqrstuvwxyz&quot;, $S0
-    if $I0 == -1 goto err_char
-    $N0 = $I0
-    result *= radix
-    result += $N0
-    goto lp1
-
-  ex1:
-    unless has_fracpart goto nofracpart
-    $I0 = length fracpart
-    unless $I0 goto nofracpart
-    $P0 = split '', fracpart
-    $P99 = shift $P0                             # remove the radix point
-
-  lp2: # Accumulate over fractional part, keep length
-    unless it goto ex2
-    $S0 = shift it
-    $S0 = downcase $S0
-    if $S0 == &quot;_&quot; goto lp2
-    $I0 = index &quot;0123456789abcdefghijklmnopqrstuvwxyz&quot;, $S0
-    if $I0 == -1 goto err_char
-    $N0 = $I0
-
-    result *= radix
-    result += $N0
-    fracdivisor *= radix
-    goto lp2
-
-  ex2:
-    result /= fracdivisor
-
-  nofracpart:
-    unless has_base goto ret
-    magnitude = base ** exp
-    result *= magnitude
-  ret:
+    .param num    exponent     :optional
+    .param int    has_exponent :opt_flag
+    .local int    iresult, fresult, fdivide
+    .local num    result
+
+    if radix &lt;= 1 goto ERANGE 
+    if radix &gt; 36 goto ERANGE #at least until we know how to represent bases &gt; 36...
+#magcheck:
+    if has_base goto magcheck2 #if you hasn't a base, go on
+        if has_exponent goto EEXPNOBASE #if you have an exponent but no base, ERROR!
+            base = 1.0
+            exponent = 1.0 #if you have no exponent and no base, then allow dumb coding to not affect the results.
+            goto magcheckdone
+
+magcheck2:
+    if has_exponent goto magcheckdone #base+exponent? Continue
+    goto EBASENOEXP #wait, you has a base, but no exponent? No way!
+magcheckdone:
+    $S99 = substr number, 0, 1
+    if $S99 == &quot;0&quot; goto checkradix #maybe they entered :8&lt;0x3F&gt; ?
+    goto allchecksdone
+    
+    #below is the nightmare of checking for radix conversion
+checkradix:
+    $S99 = substr number, 1, 1 #will they convert?
+    $S99 = upcase $S99
+    $I10 = index &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, $S99
+    if $I10 &gt;= radix goto changeradix #is the character beyond the range of the specified radix
+    goto allchecksdone #false alarm
+changeradix:
+    if $S99 == &quot;B&quot; goto changeto2  #is it a binary number?
+    if $S99 == &quot;O&quot; goto changeto8  #octal?
+    if $S99 == &quot;X&quot; goto changeto16 #hex?
+    if $S99 == &quot;D&quot; goto changeto10 #decimal?
+    goto allchecksdone
+changeto2:
+    radix=2 #the actual radix change
+    number = substr number, 2 #this is to remove what changed the radix (0x, 0b, etc.)
+    goto allchecksdone #and, relax! The checks be over
+changeto8:
+    radix=8
+    number = substr number, 2
+    goto allchecksdone
+changeto10:
+    radix=10
+    number = substr number, 2
+    goto allchecksdone
+changeto16:
+    radix=16
+    number = substr number, 2
+    #above is the nightmare of checking for radix conversion
+
+allchecksdone:  
+    iresult     = 0
+    fresult     = 0
+    fdivide     = 1
+    $I99        = 0 #I don't want to hear about the Iter object. We DON'T NEED PMCs for a radix conversion.
+
+iloop:
+    $S0 = substr number, $I99, 1
+    $S0 = upcase $S0 #I prefer uppercase when it comes to numbers in other bases, so that's how it's going to be.
+    if $S0 == &quot;_&quot; goto iskip #if you seperate words, ex. DEAD_BEEF
+    if $S0 == &quot;.&quot; goto fbefore #fraction time!
+    if $S0 == &quot;&quot; goto finish #all done
+    $I0 = index &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, $S0
+    if $I0 == -1 goto EINVALIDCHAR #say, you tried to pass off the number '3Z&#xC3;&#xB8;A5'. Jerk.
+    if $I0 &gt;= radix goto EINVALIDCHAR #if you try passing '2' with a radix of 2
+    iresult *= radix
+    iresult += $I0
+iskip:  
+    $I99 += 1
+    goto iloop #aaaand-a 1, 2, 3, 4...
+
+fbefore:
+    $I99 += 1 #we wouldn't want to read the . again, now do we?
+    
+floop:
+    $S0 = substr number, $I99, 1 #no, we DO NOT reset the $I99 loop var.
+    $S0 = upcase $S0
+    if $S0 == &quot;_&quot; goto fskip #sepearation of words, again (could also be dwords, qwords...)
+    if $S0 == &quot;.&quot; goto EINVALIDCHAR #The IMU has yet to say you can write fractions of a fraction as 3.6.8 :)
+    if $S0 == &quot;&quot; goto finish #all done!
+    $I0 = index &quot;0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;, $S0
+    if $I0 == -1 goto EINVALIDCHAR #we do not know if 3@8 is a valid number. Especially considering we don't allow a radix that would have @ as a digit.
+    if $I0 &gt;= radix goto EINVALIDCHAR #remember kids, octals can't take the number 8
+    fresult *= radix
+    fresult += $I0
+    fdivide *= radix #each place value of the fraction increases the denominator. If this is confusing, try converting any old decimal (say, .141592) into a fraction BY HAND.
+fskip:  
+    $I99 += 1
+    goto floop #and repeat
+
+finish:
+    $N0 = fresult / fdivide #for the fractional part
+    result = iresult + $N0
+    $N1 = pow base, exponent #for the magnitude. If no magnitude, then it's 1 pow 1
+    result = result * $N1 #if no magnitude, then it's result * 1. Pefect :)
+    
     .return (result)
 
-  err_range:
-    die &quot;radix out of range (2-36)&quot;
-  err_char:
-    $S0 = concat &quot;unrecognized character: &quot;, $S0
+#errors
+ERANGE: 
+    die &quot;DON'T PANIC! The radix is out of range (2..36 only)&quot;
+EINVALIDCHAR:   
+    $S0 = concat &quot;DON'T PANIC! Invalid character (&quot;, $S0
+    $S0 = concat $S0, &quot;)! Please try again :) &quot;
     die $S0
+EBASENOEXP:
+    die &quot;DON'T PANIC! You gave us a base for the magnitude, but you forgot the exponent.&quot;
+EEXPNOBASE:
+    die &quot;DON'T PANIC! You gave us an exponent for the magnitude, but you forgot the base.&quot;
 .end
 
 
-- 
1.6.0.4

</string>
    </contents>
    <universal-time>
      <integer>3478193348</integer>
    </universal-time>
    <channel>
      <string>#perl6</string>
    </channel>
    <colorization-mode>
      <string>None</string>
    </colorization-mode>
    <maybe-spam>
      <null/>
    </maybe-spam>
    <is-unicode>
      <keyword>TRUE</keyword>
    </is-unicode>
    <deletion-requested>
      <null/>
    </deletion-requested>
    <deletion-requested-email>
      <null/>
    </deletion-requested-email>
    <expiration-time>
      <null/>
    </expiration-time>
  </paste>
</paste-with-annotations>
