Though Maple provides routines to express integers or floating in different
integer bases the output looks not as nice as I want to have it.
And for example it does not work as expected using the 'simple ways' (while
for hex there is no simple way for floats):
Digits:=16; # for all the following
x:=frac(evalf(Pi)):
x:= x* SFloat(1,-14);
-14
x := 0.141592653589793 10
xxx:=convert(x, octal);
`error`[absolute, relative] = x -xxx, 1 - xxx/x;
-16
xxx := 0.3000000000000000 10
-14
error[absolute, relative] = 0.1385926535897930 10 , 0.9788124600822068
Very messy and for smaller values that would give 0 :-)
And (working with the classical interface) I always wanted a multiplication
in outputs, which I find more easy to read for humans (those who do not want
that will just omit the according step).
convert([183], 'bytes'): # ASCII 183
theDot:=parse(%); #lprint(%);
theDot := ·
Now (currently using Maple 12) the following seems to give me what I want,
converting a number (in base=10) into its presentation in a new base 'b'
in nice form (well, if it is not too long ... positives are enough):
convert_base:=proc(X::And(nonnegative,{float, integer, fraction}), b::posint)
global theDot;
local bName, L, intPart, fracPart, k, x, oldBase, newBase, n, p,m,M;
if b=1 then error "invalid base = %1 (must be larger than 2)", b end if;
bName:=convert(b, name);
# integer part
L:=convert(trunc(X), base, b);
intPart:= sum( 'L'[k]* bName^(k-1),k=1.. nops(L));
# convert first (=left) argument in multiplications to a name,
# then concatenate with theDot, finally multiply again
intPart:= subsindets(intPart, '`*`',
't -> cat(convert(op(1,t),name), theDot) * op(2,t)');
# fractional part
x:=frac(X);
if (x=0) then return intPart end if;
oldBase:=10;
newBase:=b;
n := ceil(ln(oldBase^Digits)/ln(newBase)); # new Digit length for new base
p:=floor( log[b](x/b^(n-1)) );
m:= floor( x/b^(p) );
M:=convert(m, base, b);
# here add gives the better sorting
fracPart:=bName^p * add( M[k]*bName^(k-1),k=1.. nops(M));
return intPart + sort(expand(fracPart));
end proc; #maplemint(%);
Converting such expressions back to decimal notation then is done by
convert_decimal:=proc(x_in_some_BASE)
global theDot;
convert(x_in_some_BASE, string):
StringTools:-SubstituteAll(%, theDot, ""):
StringTools:-SubstituteAll(%, "`", ""):
parse(%);
end proc;
For the above example that gives a correct transform:
convert_base(x, 8);
convert_decimal(%);
xx:=evalf(%);
`error`[absolute, relative] = x -xx, 1 - xx/x;
-14
xx := 0.1415926535897930 10
error[absolute, relative] = 0., 0.
Some more examples:
x:=3;
convert_base(x, 2);
convert_decimal(%);
x := 3
1 + 2
3
This is, because convert/name is used, so 1+2 not immediately gives 3
x:=0.125+10.^5-1;
convert_base(x, 32);
convert_decimal(%);
xx:=evalf(%);
`error`[absolute, relative] = x -xx, 1 - xx/x;
x := 99999.125
2 3 4
31 + 20· 32 + 32 + 3· 32 + ----
32
One sees some multiplication sign (but only, if it is not 1*term),
the error is zero (in that precision).
x:=frac(evalf(Pi));
convert_base(x, 16);
convert_decimal(%);
xx:=evalf(%);
`error`[absolute, relative] = x -xx, 1 - xx/x;
-15 -15
error[absolute, relative] = 0.1 10 , 0.7 10
Note that convert(x,hex) here would result in an error message.
And it works on fractions
x:=3 + 1/2^51;
convert_base(x, 2);
convert_decimal(%);
xx:=evalf(%);
`error`[absolute, relative] = x -xx, 1 - xx/x;
6755399441055745
x := ----------------
2251799813685248
1
1 + 2 + ---
51
2
6755399441055745
----------------
2251799813685248
xx := 3.000000000000000
-15
error[absolute, relative] = 0., 0.2 10