Generalised floating point multiplication: Difference between revisions
Generalised floating point multiplication (view source)
Revision as of 20:21, 27 June 2019
, 4 years ago→{{header|Phix}}: added b_sub
m (→{{header|Phix}}: added b_sub) |
|||
Line 242:
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. However this does
offer perfect accuracy in any given base, whereas gmp, for all it's brilliance, can hold
0.1 accurate to several million decimal places, but just never quite exact.
<lang Phix>-- demo\rosetta\Generic_multiplication.exw
constant MAX_DP = 81
Line 371 ⟶ 368:
zdx2 = find('0',alphabet2),
carry = 0, q, r, digit
bool negative = ((zdx=1 and n[1]='-') or
if negative then n = negate(n,alphabet) end if
integer ndp = find('.',n)
if ndp!=0 then
Line 516 ⟶ 514:
return res
end function
-- negative numbers in addition and subtraction
-- (esp. non-balanced) are treated as follows:
-- for -ve a: (-a)+b == b-a; (-a)-b == -(a+b)
-- for -ve b: a+(-b) == a-b; a-(-b) == a+b
-- for a>b: a-b == -(b-a) [avoid running off end]
forward function b_sub(string a, b, alphabet)
function b_add(string a, b, alphabet)
Line 523 ⟶ 529:
if zdx=1 then
-- (let me know if you can fix this for me!)
if a[1]='-' then -- (-a)+b == b-a
return b_sub(b,negate(a,alphabet),alphabet)
end if
if b[1]='-' then -- a+(-b) == a-b
return b_sub(a,negate(b,alphabet),alphabet)
end if
end if
integer adt = find('.',a),
Line 558 ⟶ 570:
end if
a = b_trim(a)
return a
end function
function a_smaller(string a, b, alphabet)
-- return true if a is smaller than b
-- if not balanced then both are +ve
if length(a)!=length(b) then ?9/0 end if -- sanity check
for i=1 to length(a) do
integer da = find(a[i],alphabet),
db = find(b[i],alphabet),
c = compare(a,b)
if c!=0 then return c<0 end if
end for
return false -- (=, which is not <)
end function
function b_sub(string a, b, alphabet)
integer base = length(alphabet),
zdx = find('0',alphabet),
carry = 0, da, db, digit
if zdx=1 then
if a[1]='-' then -- (-a)-b == -(a+b)
return negate(b_add(negate(a,alphabet),b,alphabet),alphabet)
end if
if b[1]='-' then -- a-(-b) == a+b
return b_add(a,negate(b,alphabet),alphabet)
end if
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
bool bNegate = false
if length(a)<length(b)
or (length(a)=length(b) and a_smaller(a,b,alphabet)) then
bNegate = true
{a,b} = {b,a} -- ensure b is the shorter/smaller
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 = digit<=0
a[i] = alphabet[digit+carry*base]
if i<-length(b) and carry=0 then exit end if
end for
if carry then
?9/0 -- should have set bNegate above...
end if
if adt then
a[-adt+1..-adt] = "."
end if
a = b_trim(a)
if bNegate then
a = negate(a,alphabet)
end if
return a
end function
Line 607 ⟶ 686:
-- 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.
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("
-- 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)
printf(1,"%s\n%s\n",{name,repeat('=',length(name))})
printf(1," a = %.16g %s\n",{b2dec(a,alphabet),a})
Line 625 ⟶ 701:
printf(1," c = %.16g %s\n",{b2dec(c,alphabet),c})
-- printf(1," d = %.16g %s\n",{b2dec(d,alphabet),d})
printf(1,"a*(b
end procedure
test("balanced ternary", balancedternary)
Line 643 ⟶ 718:
================
a = 523.2391403749428 +-0++0+.+-0++0+
b = -436.4359999999999
c = 65.26748971193416 +-++-.+-++-
a*(b
balanced base 27
================
a = 523.2391403749428 AUJ.FLI
b = -436.436 NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
c = 65.26748971193416 BK.GF
a*(b
decimal
=======
a = 523.239140374943 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
b = -436.436 -436.436
c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b
binary
======
a = 523.2391403749427 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111
b = -436.436 -110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001
c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101
a*(b
ternary
=======
a = 523.2391403749428 201101.0201101
b = -436.4360000000001 -121011.102202211210021110012111201022222000202102010100101200200110122011122101110212
c = 65.26748971193416 2102.02102
a*(b
hexadecimal
===========
a = 523.2391403749427 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62
b = -436.436 -1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2
c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905
a*(b
septemvigesimal
===============
a = 523.2391403749428 JA.6C9
b = -436.436 -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
c = 65.26748971193416 2B.76
a*(b
</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)})
Line 712 ⟶ 787:
{{out}}
<pre>
1 | + | | | | | | | | | | | |
2 | +- | ++ | | | | | | | | | | |
|