Generalised floating point multiplication: Difference between revisions
Content added Content deleted
m (→{{header|ALGOL 68}}: remove broken optimsation) |
|||
Line 237: | Line 237: | ||
</pre> |
</pre> |
||
=={{header|Phix}}== |
|||
Note regarding requirement #5: While this meets my definition of "reasonably efficient", |
|||
it should not shock anyone that this kind of "string maths" which works digit-by-digit |
|||
and uses repeated addition (eg *999 performs 27 additions) could easily be 10,000 times |
|||
slower than raw hardware or a carefully optimised library such as gmp. |
|||
Deviation from task description: |
|||
b_add() only copes with negative parameters when using balanced number bases, hence I |
|||
changed the test slightly to remove the signs, or you could just omit the b-c part of |
|||
the test by setting b to -501.7034897119342 (ie -436.436 - 65.26748971193418) and then |
|||
do a*b rather than a*(b-c), or you could fix b_add() and/or write a brand new b_sub(). |
|||
<lang Phix>-- demo\rosetta\Generic_multiplication.exw |
|||
constant MAX_DP = 81 |
|||
constant binary = "01", |
|||
ternary = "012", |
|||
balancedternary = "-0+", |
|||
decimal = "0123456789", |
|||
hexadecimal = "0123456789ABCDEF", |
|||
septemvigesimal = "0123456789ABCDEFGHIJKLMNOPQ", |
|||
-- heptavintimal = "0123456789ABCDEFGHKMNPRTVXZ", -- ?? |
|||
-- wonky_donkey_26 = "0ABCDEFGHIJKLMNOPQRSTUVWXY", |
|||
-- wonky_donkey_27 = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ", |
|||
balanced_base27 = "ZYXWVUTSRQPON0ABCDEFGHIJKLM", |
|||
base37 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
|||
-- |
|||
--Note: I have seen some schemes where balanced-base-27 uses |
|||
--==== the same character set as septemvigesimal, with 'D' |
|||
-- representing 0, and wonky_donkey_27 with 'M'==0(!). |
|||
-- These routines do not support that directly, except |
|||
-- (perhaps) via a simple mapping on all inputs/outputs. |
|||
-- It may be possible to add a defaulted parameter such |
|||
-- as zero='0' - left as an exercise for the reader. |
|||
-- Admittedly that balanced_base27 is entirely my own |
|||
-- invention, just for this specific task. |
|||
-- |
|||
function b2dec(string b, alphabet) |
|||
-- |
|||
-- convert string b back into a normal (decimal) atom, |
|||
-- eg b2dec("+0-",balancedternary) yields 8 |
|||
-- |
|||
atom res = 0 |
|||
integer base = length(alphabet), |
|||
zdx = find('0',alphabet) |
|||
bool signed = (zdx=1 and b[1]='-') |
|||
if signed then b = b[2..$] end if |
|||
integer len = length(b), |
|||
ndp = find('.',b) |
|||
if ndp!=0 then |
|||
b[ndp..ndp] = "" -- remove '.' |
|||
ndp = len-ndp |
|||
end if |
|||
for i=1 to length(b) do |
|||
res = base*res+find(b[i],alphabet)-zdx |
|||
end for |
|||
if ndp!=0 then res /= power(base,ndp) end if |
|||
if signed then res = -res end if |
|||
return res |
|||
end function |
|||
function negate(string b, alphabet) |
|||
-- |
|||
-- negate b (can be balanced or unbalanced) |
|||
-- |
|||
if alphabet[1]='0' then |
|||
-- traditional: add/remove a leading '-' |
|||
-- eg "-123" <==> "123" |
|||
if b!="0" then |
|||
if b[1]='-' then |
|||
b = b[2..$] |
|||
else |
|||
b = "-"&b |
|||
end if |
|||
end if |
|||
else |
|||
-- balanced: mirror [non-0] digits |
|||
-- eg "-0+" (ie -8) <==> "+0-" (ie +8) |
|||
for i=1 to length(b) do |
|||
if b[i]!='.' then |
|||
b[i] = alphabet[-find(b[i],alphabet)] |
|||
end if |
|||
end for |
|||
end if |
|||
return b |
|||
end function |
|||
function b_trim(string b) |
|||
-- (common code) |
|||
-- trim trailing ".000" |
|||
if find('.',b) then |
|||
b = trim_tail(trim_tail(b,'0'),'.') |
|||
end if |
|||
-- trim leading zeroes, but not "0.nnn" -> ".nnn" |
|||
-- [hence we cannot use the standard trim_head()] |
|||
while length(b)>1 and b[1]='0' and b[2]!='.' do |
|||
b = b[2..$] |
|||
end while |
|||
return b |
|||
end function |
|||
function b_carry(integer digit, base, idx, string n, alphabet) |
|||
-- (common code, for balanced number systems only) |
|||
integer carry = iff(digit>base?+1:iff(digit<1?-1:0)) |
|||
if carry then |
|||
for i=idx to 0 by -1 do |
|||
if n[i]!='.' then |
|||
integer k = find(n[i],alphabet) |
|||
if k<base then |
|||
n[i] = alphabet[k+1] |
|||
exit |
|||
end if |
|||
n[i]=alphabet[1] |
|||
end if |
|||
end for |
|||
digit -= base*carry |
|||
end if |
|||
return {digit,n} |
|||
end function |
|||
function b2b(string n, alphabet, alphabet2) |
|||
-- |
|||
-- convert a string from alphabet to alphabet2, |
|||
-- eg b2b("8",decimal,balancedternary) yields "+0-", |
|||
-- & b2b("+0-",balancedternary,decimal) yields "8", |
|||
-- |
|||
string res = "0", m = "" |
|||
if n!="0" then |
|||
integer base = length(alphabet), |
|||
base2 = length(alphabet2), |
|||
zdx = find('0',alphabet), |
|||
zdx2 = find('0',alphabet2), |
|||
carry = 0, q, r, digit |
|||
bool negative = (zdx=1 and n[1]='-') |
|||
if negative then n = n[2..$] end if |
|||
integer ndp = find('.',n) |
|||
if ndp!=0 then |
|||
{n,m} = {n[1..ndp-1],n[ndp+1..$]} |
|||
end if |
|||
res = "" |
|||
while length(n) do |
|||
q = 0 |
|||
for i=1 to length(n) do |
|||
-- |
|||
-- this is a digit-by-digit divide (/mod) loop |
|||
-- eg for hex->decimal we would want: |
|||
-- this loop/modrem("FFFF",10) --> "1999" rem 5, |
|||
-- this loop/modrem("1999",10) --> "28F" rem 3, |
|||
-- this loop/modrem("28F",10) --> "41" rem 5, |
|||
-- this loop/modrem("41",10) --> "6" rem 5, |
|||
-- this loop/modrem("6",10) --> "0" rem 6, |
|||
-- ==> res:="65535" (in 5 full iterations over n). |
|||
-- |
|||
digit = find(n[i],alphabet)-zdx |
|||
q = q*base+digit |
|||
r = mod(q,base2) |
|||
digit = floor(q/base2)+zdx |
|||
if zdx!=1 then |
|||
{digit,n} = b_carry(digit,base,i-1,n,alphabet) |
|||
end if |
|||
n[i] = alphabet[digit] |
|||
q = r |
|||
end for |
|||
r += zdx2 |
|||
if zdx2!=1 then |
|||
r += carry |
|||
carry = iff(r>base2?+1:iff(r<1?-1:0)) |
|||
r -= base2*carry |
|||
end if |
|||
res = alphabet2[r]&res |
|||
n = trim_head(n,'0') |
|||
end while |
|||
if carry then |
|||
res = alphabet2[carry+zdx2]&res |
|||
end if |
|||
if length(m) then |
|||
res &= '.' |
|||
ndp = 0 |
|||
if zdx!=1 then |
|||
-- convert fraction to unbalanced, to simplify the (other-base) multiply. |
|||
integer lm = length(m) |
|||
string alphanew = base37[1..length(alphabet)] |
|||
m = b2b(m,alphabet,alphanew) -- (nb: no fractional part!) |
|||
m = repeat('0',lm-length(m))&m -- zero-pad if required |
|||
alphabet = alphanew |
|||
zdx = 1 |
|||
end if |
|||
while length(m) and ndp<MAX_DP do |
|||
q = 0 |
|||
for i=length(m) to 1 by -1 do |
|||
-- |
|||
-- this is a digit-by-digit multiply loop |
|||
-- eg for [.]"1415" decimal->decimal we |
|||
-- would repeatedly multiply by 10, giving |
|||
-- 1 and "4150", then 4 and "1500", then |
|||
-- 1 and "5000", then 5 and "0000". We |
|||
-- strip zeroes between each output digit |
|||
-- & obviously normally alphabet in!=out. |
|||
-- |
|||
digit = find(m[i],alphabet)-zdx |
|||
q += digit*base2 |
|||
r = mod(q,base)+zdx |
|||
q = floor(q/base) |
|||
m[i] = alphabet[r] |
|||
end for |
|||
digit = q + zdx2 |
|||
if zdx2!=1 then |
|||
{digit,res} = b_carry(digit,base2,length(res),res,alphabet2) |
|||
end if |
|||
res &= alphabet2[digit] |
|||
m = trim_tail(m,'0') |
|||
ndp += 1 |
|||
end while |
|||
end if |
|||
res = b_trim(res) |
|||
if negative then res = negate(res,alphabet2) end if |
|||
end if |
|||
return res |
|||
end function |
|||
function atm2b(atom d, string alphabet) |
|||
-- |
|||
-- convert d to a string in the specified base, |
|||
-- eg atm2b(65535,hexadecimal) => "FFFF" |
|||
-- |
|||
-- As a standard feature of phix, you can actually specify |
|||
-- d in any number base between 2 and 36, eg 0(13)168 is |
|||
-- equivalent to 255 (see test\t37misc.exw for more), but |
|||
-- not (yet) in balanced number bases, or with fractions, |
|||
-- except (of course) for normal decimal fractions. |
|||
-- |
|||
-- Note that eg b2b("-436.436",decimal,balancedternary) is |
|||
-- more acccurate that atm2b(-436.436,balancedternary) due |
|||
-- to standard IEEE 754 floating point limitations. |
|||
-- For integers, discrepancies only creep in for values |
|||
-- outside the range +/-9,007,199,254,740,992 (on 32-bit). |
|||
-- However, this is much simpler and faster than b2b(). |
|||
-- |
|||
integer base = length(alphabet), |
|||
zdx = find('0',alphabet), |
|||
carry = 0 |
|||
bool neg = d<0 |
|||
if neg then d = -d end if |
|||
string res = "" |
|||
integer whole = floor(d) |
|||
d -= whole |
|||
while true do |
|||
integer ch = mod(whole,base) + zdx |
|||
if zdx!=1 then |
|||
ch += carry |
|||
carry = iff(ch>base?+1:iff(ch<1?-1:0)) |
|||
ch -= base*carry |
|||
end if |
|||
res = alphabet[ch]&res |
|||
whole = floor(whole/base) |
|||
if whole=0 then exit end if |
|||
end while |
|||
if carry then |
|||
res = alphabet[carry+zdx]&res |
|||
carry = 0 |
|||
end if |
|||
if d!=0 then |
|||
res &= '.' |
|||
integer ndp = 0 |
|||
while d!=0 and ndp<MAX_DP do |
|||
d *= base |
|||
integer digit = floor(d) + zdx |
|||
d -= digit |
|||
if zdx!=1 then |
|||
{digit,res} = b_carry(digit,base,length(res),res,alphabet) |
|||
end if |
|||
res &= alphabet[digit] |
|||
ndp += 1 |
|||
end while |
|||
end if |
|||
if neg then res = negate(res,alphabet) end if |
|||
return res |
|||
end function |
|||
function b_add(string a, b, alphabet) |
|||
integer base = length(alphabet), |
|||
zdx = find('0',alphabet), |
|||
carry = 0, da, db, digit |
|||
if zdx=1 then |
|||
-- (let me know if you can fix this for me!) |
|||
if a[1]='-' or b[1]='-' then ?9/0 end if -- +ve only |
|||
end if |
|||
integer adt = find('.',a), |
|||
bdt = find('.',b) |
|||
if adt or bdt then |
|||
-- remove the '.'s and zero-pad the shorter as needed |
|||
-- (thereafter treat them as two whole integers) |
|||
-- eg "1.23"+"4.5" -> "123"+"450" (leaving adt==2) |
|||
if adt then adt = length(a)-adt+1; a[-adt..-adt] = "" end if |
|||
if bdt then bdt = length(b)-bdt+1; b[-bdt..-bdt] = "" end if |
|||
if bdt>adt then |
|||
a &= repeat('0',bdt-adt) |
|||
adt = bdt |
|||
elsif adt>bdt then |
|||
b &= repeat('0',adt-bdt) |
|||
end if |
|||
end if |
|||
if length(a)<length(b) then |
|||
{a,b} = {b,a} -- ensure b is the shorter |
|||
end if |
|||
for i=-1 to -length(a) by -1 do |
|||
da = iff(i<-length(a)?0:find(a[i],alphabet)-zdx) |
|||
db = iff(i<-length(b)?0:find(b[i],alphabet)-zdx) |
|||
digit = da + db + carry + zdx |
|||
carry = iff(digit>base?+1:iff(digit<1?-1:0)) |
|||
a[i] = alphabet[digit-carry*base] |
|||
if i<-length(b) and carry=0 then exit end if |
|||
end for |
|||
if carry then |
|||
a = alphabet[carry+zdx]&a |
|||
end if |
|||
if adt then |
|||
a[-adt+1..-adt] = "." |
|||
end if |
|||
a = b_trim(a) |
|||
return a |
|||
end function |
|||
function b_mul(string a, b, alphabet) |
|||
integer base = length(alphabet), |
|||
zdx = find('0',alphabet), |
|||
dpa = find('.',a), |
|||
dpb = find('.',b), |
|||
ndp = 0 |
|||
if dpa then ndp += length(a)-dpa; a[dpa..dpa] = "" end if |
|||
if dpb then ndp += length(b)-dpb; b[dpb..dpb] = "" end if |
|||
string pos = a, res = "0" |
|||
if zdx!=1 then |
|||
-- balanced number systems |
|||
string neg = negate(pos,alphabet) |
|||
for i=length(b) to 1 by -1 do |
|||
integer m = find(b[i],alphabet)-zdx |
|||
while m do |
|||
res = b_add(res,iff(m<0?neg:pos),alphabet) |
|||
m += iff(m<0?+1:-1) |
|||
end while |
|||
pos &= '0' |
|||
neg &= '0' |
|||
end for |
|||
else |
|||
-- non-balanced (normal) number systems |
|||
bool negative = false |
|||
if a[1]='-' then a = a[2..$]; negative = true end if |
|||
if b[1]='-' then b = b[2..$]; negative = not negative end if |
|||
for i=length(b) to 1 by -1 do |
|||
integer m = find(b[i],alphabet)-zdx |
|||
while m>0 do |
|||
res = b_add(res,pos,alphabet) |
|||
m -= 1 |
|||
end while |
|||
pos &= '0' |
|||
end for |
|||
if negative then res = negate(res,alphabet) end if |
|||
end if |
|||
if ndp then |
|||
res[-ndp..-ndp-1] = "." |
|||
end if |
|||
res = b_trim(res) |
|||
return res |
|||
end function |
|||
-- [note 1] not surprisingly, the decimal output is somewhat cleaner/shorter when |
|||
-- the decimal string inputs for a and c are used, whereas tests 1/2/5/7 |
|||
-- (the 3-based ones) look much better with all ternary string inputs. |
|||
-- [note 2] proof that b_mul() copes with negative numbers, though b_add() dis'ne. |
|||
procedure test(string name, alphabet) |
|||
--string a = b2b("523.2391403749428",decimal,alphabet), -- [see note 1] |
|||
string a = b2b("+-0++0+.+-0++0+",balancedternary,alphabet), |
|||
b = b2b("436.436",decimal,alphabet), |
|||
-- b = b2b("+--+0++.++0-+00---+",balancedternary,alphabet), |
|||
-- b = b2b("-501.7034897119342",decimal,alphabet), -- [see note 2] |
|||
-- c = b2b("65.26748971193416",decimal,alphabet), -- [see note 1] |
|||
c = b2b("+-++-.+-++-",balancedternary,alphabet), |
|||
d = b_add(b,c,alphabet), |
|||
r = b_mul(a,d,alphabet) |
|||
-- r = b_mul(a,b,alphabet) -- [see note 2] |
|||
printf(1,"%s\n%s\n",{name,repeat('=',length(name))}) |
|||
printf(1," a = %.16g %s\n",{b2dec(a,alphabet),a}) |
|||
printf(1," b = %.16g %s\n",{b2dec(b,alphabet),b}) |
|||
printf(1," c = %.16g %s\n",{b2dec(c,alphabet),c}) |
|||
-- printf(1," d = %.16g %s\n",{b2dec(d,alphabet),d}) |
|||
printf(1,"a*(b+c) = %.16g %s\n\n",{b2dec(r,alphabet),r}) |
|||
-- printf(1," a*b = %.16g %s\n\n",{b2dec(r,alphabet),r}) -- [see note 2] |
|||
end procedure |
|||
test("balanced ternary", balancedternary) |
|||
test("balanced base 27", balanced_base27) |
|||
test("decimal", decimal) |
|||
test("binary", binary) |
|||
test("ternary", ternary) |
|||
test("hexadecimal", hexadecimal) |
|||
test("septemvigesimal", septemvigesimal)</lang> |
|||
The printed decimal output is inherently limited to IEEE 754 precision, hence I |
|||
deliberately limited output (%.16g) because it is silly to try and go any higher, |
|||
whereas the output from b_mul() is actually perfectly accurate, see [note 1] above. |
|||
{{out}} |
|||
<pre> |
|||
balanced ternary |
|||
================ |
|||
a = 523.2391403749428 +-0++0+.+-0++0+ |
|||
b = 436.4359999999999 +--+0++.++0-+00---+0+-+++0+-0----0++0000-00+-+-++-0+0+00++--0+-00+++-0-+---0-+0++++0-- |
|||
c = 65.26748971193416 +-++-.+-++- |
|||
a*(b+c) = 262510.9026799813 ++++000+0-0-.0-0+0+00+++00++0+0-++-++00+0--+000--0+000+-0-+++++---+-+0-+-0-0--0-0+--+--0-+++00---- |
|||
balanced base 27 |
|||
================ |
|||
a = 523.2391403749428 AUJ.FLI |
|||
b = 436.436 AXD.LSQSGLFZUINATKCIKUVMWEWJMQ0COTSWNRONXBMBQYL0VGRUCDYFDFTYSMHVANGXPVXHIZJRJWZD0PBGF |
|||
c = 65.26748971193416 BK.GF |
|||
a*(b+c) = 262510.9026799813 MICW.PJALDCRRAQIQCAWMKXSTPYUXYPK0LVOBZRGUSJJOGIHSNU0FRMZGOWQPEENDVDPNJZXKFGCLHKLCX0YBQHB |
|||
decimal |
|||
======= |
|||
a = 523.239140374943 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004 |
|||
b = 436.436 436.436 |
|||
c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045 |
|||
a*(b+c) = 262510.9026799814 262510.90267998140903693918986303277315826215892262734715612833785876513103053772667101895163734826631742752252837097627017862754285047634638652268078676654605120794218 |
|||
binary |
|||
====== |
|||
a = 523.2391403749427 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111 |
|||
b = 436.436 110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001 |
|||
c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101 |
|||
a*(b+c) = 262510.9026799814 1000000000101101110.111001110001011000001001000001101110011111011100000100000100001000101011100011110010110001010100110111001011101001010000001110110100111110001101000000001111110101 |
|||
ternary |
|||
======= |
|||
a = 523.2391403749428 201101.0201101 |
|||
b = 436.4360000000001 121011.102202211210021110012111201022222000202102010100101200200110122011122101110212 |
|||
c = 65.26748971193416 2102.02102 |
|||
a*(b+c) = 262510.9026799813 111100002121.2201010011100110022102110002120222120100001221111011202022012121122001201122110221112 |
|||
hexadecimal |
|||
=========== |
|||
a = 523.2391403749427 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62 |
|||
b = 436.436 1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2 |
|||
c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905 |
|||
a*(b+c) = 262510.9026799814 4016E.E7160906E7DC10422DA508321819F4A637E5AEE668ED5163B12FCB17A732442F589975B7F24112B2E8F6E95EAD45803915EE26D20DF323D67CAEEC75D7BED68AA34E02F2B492257D66F028545FB398F60E |
|||
septemvigesimal |
|||
=============== |
|||
a = 523.2391403749428 JA.6C9 |
|||
b = 436.436 G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276 |
|||
c = 65.26748971193416 2B.76 |
|||
a*(b+c) = 262510.9026799813 D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82 |
|||
</pre> |
|||
=== multiplication table === |
|||
Without e notation, with hexadecimal across, septemvigesimal down, and balanced ternary contents! |
|||
<lang Phix>printf(1,"# |") |
|||
for j=1 to 12 do |
|||
printf(1," #%s %3s |",{atm2b(j,hexadecimal),atm2b(j,balancedternary)}) |
|||
end for |
|||
for i=1 to 27 do |
|||
string a = atm2b(i,balancedternary) |
|||
printf(1,"\n%-2s|",{atm2b(i,septemvigesimal)}) |
|||
for j=1 to 12 do |
|||
if j>i then |
|||
printf(1," |") |
|||
else |
|||
string b = atm2b(j,balancedternary) |
|||
string m = b_mul(a,b,balancedternary) |
|||
printf(1," %6s |",{m}) |
|||
end if |
|||
end for |
|||
end for |
|||
printf(1,"\n")</lang> |
|||
{{out}} |
|||
<pre> |
|||
# | * | + #1 | +- #2 | +0 #3 | ++ #4 | +-- #5 | +-0 #6 | +-+ #7 | +0- #8 | +00 #9 | +0+ #A | ++- #B | ++0 #C | |
|||
1 | + | + | | | | | | | | | | | | |
|||
2 | +- | +- | ++ | | | | | | | | | | | |
|||
3 | +0 | +0 | +-0 | +00 | | | | | | | | | | |
|||
4 | ++ | ++ | +0- | ++0 | +--+ | | | | | | | | | |
|||
5 | +-- | +-- | +0+ | +--0 | +-+- | +0-+ | | | | | | | | |
|||
6 | +-0 | +-0 | ++0 | +-00 | +0-0 | +0+0 | ++00 | | | | | | | |
|||
7 | +-+ | +-+ | +--- | +-+0 | +00+ | ++0- | +---0 | +--++ | | | | | | |
|||
8 | +0- | +0- | +--+ | +0-0 | ++-- | ++++ | +--+0 | +-0+- | +-+0+ | | | | | |
|||
9 | +00 | +00 | +-00 | +000 | ++00 | +--00 | +-000 | +-+00 | +0-00 | +0000 | | | | |
|||
A | +0+ | +0+ | +-+- | +0+0 | ++++ | +-0-- | +-+-0 | +0--+ | +000- | +0+00 | ++-0+ | | | |
|||
B | ++- | ++- | +-++ | ++-0 | +--0- | +-00+ | +-++0 | +00-- | +0+-+ | ++-00 | ++0+- | +++++ | | |
|||
C | ++0 | ++0 | +0-0 | ++00 | +--+0 | +-+-0 | +0-00 | +00+0 | ++--0 | ++000 | ++++0 | +--0-0 | +--+00 | |
|||
D | +++ | +++ | +00- | +++0 | +-0-+ | +-++- | +00-0 | +0+0+ | ++0-- | +++00 | +---++ | +--+0- | +-0-+0 | |
|||
E | +--- | +--- | +00+ | +---0 | +-0+- | +0--+ | +00+0 | ++-0- | ++0++ | +---00 | +--+-- | +-0-0+ | +-0+-0 | |
|||
F | +--0 | +--0 | +0+0 | +--00 | +-+-0 | +0-+0 | +0+00 | ++0-0 | ++++0 | +--000 | +-0--0 | +-00+0 | +-+-00 | |
|||
G | +--+ | +--+ | ++-- | +--+0 | +-+0+ | +000- | ++--0 | ++0++ | +---+- | +--+00 | +-00-+ | +-+--- | +-+0+0 | |
|||
H | +-0- | +-0- | ++-+ | +-0-0 | +0--- | +00++ | ++-+0 | ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 | |
|||
I | +-00 | +-00 | ++00 | +-000 | +0-00 | +0+00 | ++000 | +---00 | +--+00 | +-0000 | +-+-00 | +-++00 | +0-000 | |
|||
J | +-0+ | +-0+ | +++- | +-0+0 | +0-++ | ++--- | +++-0 | +--0-+ | +-0-0- | +-0+00 | +-+00+ | +0--+- | +0-++0 | |
|||
K | +-+- | +-+- | ++++ | +-+-0 | +000- | ++-0+ | ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 | |
|||
L | +-+0 | +-+0 | +---0 | +-+00 | +00+0 | ++0-0 | +---00 | +--++0 | +-0+-0 | +-+000 | +0--+0 | +00--0 | +00+00 | |
|||
M | +-++ | +-++ | +--0- | +-++0 | +0+-+ | ++0+- | +--0-0 | +-0-0+ | +-+--- | +-++00 | +0-0++ | +0000- | +0+-+0 | |
|||
N | +0-- | +0-- | +--0+ | +0--0 | +0++- | +++-+ | +--0+0 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 | |
|||
O | +0-0 | +0-0 | +--+0 | +0-00 | ++--0 | ++++0 | +--+00 | +-0+-0 | +-+0+0 | +0-000 | +000-0 | +0+-+0 | ++--00 | |
|||
P | +0-+ | +0-+ | +-0-- | +0-+0 | ++-0+ | +---0- | +-0--0 | +-0+++ | +-+++- | +0-+00 | +00+-+ | +0++-- | ++-0+0 | |
|||
Q | +00- | +00- | +-0-+ | +00-0 | ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 | |
|||
10| +000 | +000 | +-000 | +0000 | ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 | |
|||
</pre> |
|||
[[Category:Arbitrary precision]] |
[[Category:Arbitrary precision]] |