Generalised floating point multiplication: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Wren}}: Minor tidy)
 
(21 intermediate revisions by 4 users not shown)
Line 58: Line 58:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.3.3 algol68g-2.3.3].}}
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.3.3 algol68g-2.3.3].}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
'''File: Template.Big_float.Multiplication.a68'''<lang algol68>##########################################
'''File: Template.Big_float.Multiplication.a68'''<syntaxhighlight lang="algol68">##########################################
# TASK CODE #
# TASK CODE #
# Actual generic mulitplication operator #
# Actual generic mulitplication operator #
Line 116: Line 116:


OP *:= = (REF DIGITS lhs, DIGIT arg)DIGITS: lhs := lhs * INITDIGITS arg;
OP *:= = (REF DIGITS lhs, DIGIT arg)DIGITS: lhs := lhs * INITDIGITS arg;
</lang>'''File: Template.Balanced_ternary_float.Base.a68'''<lang algol68>PR READ "Template.Big_float_BCD.Base.a68" PR # [[rc:Generalised floating point addition]] #
</syntaxhighlight>'''File: Template.Balanced_ternary_float.Base.a68'''<syntaxhighlight lang="algol68">PR READ "Template.Big_float_BCD.Base.a68" PR # [[rc:Generalised floating point addition]] #


################################################################
################################################################
Line 151: Line 151:
OD;
OD;
out SHR (UPB s-point)
out SHR (UPB s-point)
);</lang>'''File: test.Balanced_ternary_float.Multiplication.a68'''<lang algol68>#!/usr/local/bin/a68g --script #
);</syntaxhighlight>'''File: test.Balanced_ternary_float.Multiplication.a68'''<syntaxhighlight lang="algol68">#!/usr/local/bin/a68g --script #
####################################################################
####################################################################
# A program to test arbitrary length floating point multiplication #
# A program to test arbitrary length floating point multiplication #
Line 200: Line 200:
printf($l$)
printf($l$)
OD
OD
)</lang>'''Output:'''
)</syntaxhighlight>'''Output:'''
<pre>
<pre>
a = +523.23914037494284407864655 +-0++0+.+-0++0+
a = +523.23914037494284407864655 +-0++0+.+-0++0+
Line 238: Line 238:
</pre>
</pre>


=={{header|Phix}}==
=={{header|Go}}==
{{trans|Phix}}
Note regarding requirement #5: While this meets my definition of "reasonably efficient",
In the interests of brevity many of the comments and all of the commented-out code has been omitted.
it should not shock anyone that this kind of "string maths" which works digit-by-digit
<syntaxhighlight lang="go">package main
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.


import (
Deviation from task description:
"fmt"
b_add() only copes with negative parameters when using balanced number bases, hence I
"log"
changed the test slightly to remove the signs, or you could just omit the b-c part of
"math"
the test by setting b to -501.7034897119342 (ie -436.436 - 65.26748971193418) and then
"strings"
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


const (
constant binary = "01",
ternary = "012",
maxdp = 81
balancedternary = "-0+",
binary = "01"
decimal = "0123456789",
ternary = "012"
hexadecimal = "0123456789ABCDEF",
balancedTernary = "-0+"
septemvigesimal = "0123456789ABCDEFGHIJKLMNOPQ",
decimal = "0123456789"
hexadecimal = "0123456789ABCDEF"
-- heptavintimal = "0123456789ABCDEFGHKMNPRTVXZ", -- ??
septemVigesimal = "0123456789ABCDEFGHIJKLMNOPQ"
-- wonky_donkey_26 = "0ABCDEFGHIJKLMNOPQRSTUVWXY",
balancedBase27 = "ZYXWVUTSRQPON0ABCDEFGHIJKLM"
-- wonky_donkey_27 = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ",
base37 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
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.
--


/* helper functions */
function b2dec(string b, alphabet)

--
-- convert string b back into a normal (decimal) atom,
func changeByte(s string, idx int, c byte) string {
bytes := []byte(s)
-- eg b2dec("+0-",balancedternary) yields 8
bytes[idx] = c
--
atom res = 0
return string(bytes)
}
integer base = length(alphabet),

zdx = find('0',alphabet)
func removeByte(s string, idx int) string {
bool signed = (zdx=1 and b[1]='-')
le := len(s)
if signed then b = b[2..$] end if
integer len = length(b),
bytes := []byte(s)
copy(bytes[idx:], bytes[idx+1:])
ndp = find('.',b)
if ndp!=0 then
return string(bytes[0 : le-1])
}
b[ndp..ndp] = "" -- remove '.'

ndp = len-ndp
func insertByte(s string, idx int, c byte) string {
end if
for i=1 to length(b) do
le := len(s)
res = base*res+find(b[i],alphabet)-zdx
t := make([]byte, le+1)
end for
copy(t, s)
copy(t[idx+1:], t[idx:])
if ndp!=0 then res /= power(base,ndp) end if
t[idx] = c
if signed then res = -res end if
return string(t)
}

func prependByte(s string, c byte) string {
le := len(s)
bytes := make([]byte, le+1)
copy(bytes[1:], s)
bytes[0] = c
return string(bytes)
}

func abs(i int) int {
if i < 0 {
return -i
}
return i
}

// converts Phix indices to Go
func gIndex(pIndex, le int) int {
if pIndex < 0 {
return pIndex + le
}
return pIndex - 1
}

func getCarry(digit, base int) int {
if digit > base {
return 1
} else if digit < 1 {
return -1
}
return 0
}

// convert string 'b' to a decimal floating point number
func b2dec(b, alphabet string) float64 {
res := 0.0
base := len(alphabet)
zdx := strings.IndexByte(alphabet, '0') + 1
signed := zdx == 1 && b[0] == '-'
if signed {
b = b[1:]
}
le := len(b)
ndp := strings.IndexByte(b, '.') + 1
if ndp != 0 {
b = removeByte(b, ndp-1) // remove decimal point
ndp = le - ndp
}
for i := 1; i <= len(b); i++ {
idx := strings.IndexByte(alphabet, b[i-1]) + 1
res = float64(base)*res + float64(idx) - float64(zdx)
}
if ndp != 0 {
res /= math.Pow(float64(base), float64(ndp))
}
if signed {
res = -res
}
return res
return res
}
end function


// string 'b' can be balanced or unbalanced
function negate(string b, alphabet)
func negate(b, alphabet string) string {
--
if alphabet[0] == '0' {
-- negate b (can be balanced or unbalanced)
if b != "0" {
--
if alphabet[1]='0' then
if b[0] == '-' {
-- traditional: add/remove a leading '-'
b = b[1:]
-- eg "-123" <==> "123"
} else {
if b!="0" then
b = prependByte(b, '-')
if b[1]='-' then
}
b = b[2..$]
}
else
} else {
b = "-"&b
for i := 1; i <= len(b); i++ {
end if
if b[i-1] != '.' {
idx := strings.IndexByte(alphabet, b[i-1]) + 1
end if
gi := gIndex(-idx, len(alphabet))
else
b = changeByte(b, i-1, alphabet[gi])
-- 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
return b
}
end function

func bTrim(b string) string {
function b_trim(string b)
// trim trailing ".000"
-- (common code)
idx := strings.IndexByte(b, '.') + 1
-- trim trailing ".000"
if find('.',b) then
if idx != 0 {
b = trim_tail(trim_tail(b,'0'),'.')
b = strings.TrimRight(strings.TrimRight(b, "0"), ".")
end if
}
-- trim leading zeroes, but not "0.nnn" -> ".nnn"
// trim leading zeros but not "0.nnn"
for len(b) > 1 && b[0] == '0' && b[1] != '.' {
-- [hence we cannot use the standard trim_head()]
while length(b)>1 and b[1]='0' and b[2]!='.' do
b = b[1:]
b = b[2..$]
}
end while
return b
return b
}
end function


// for balanced number systems only
function b_carry(integer digit, base, idx, string n, alphabet)
func bCarry(digit, base, idx int, n, alphabet string) (int, string) {
-- (common code, for balanced number systems only)
integer carry = iff(digit>base?+1:iff(digit<1?-1:0))
carry := getCarry(digit, base)
if carry then
if carry != 0 {
for i=idx to 0 by -1 do
for i := idx; i >= 1; i-- {
if n[i]!='.' then
if n[i-1] != '.' {
integer k = find(n[i],alphabet)
k := strings.IndexByte(alphabet, n[i-1]) + 1
if k<base then
if k < base {
n[i] = alphabet[k+1]
n = changeByte(n, i-1, alphabet[k])
exit
break
end if
}
n[i]=alphabet[1]
n = changeByte(n, i-1, alphabet[0])
end if
}
end for
}
digit -= base*carry
digit -= base * carry
end if
}
return {digit,n}
return digit, n
}
end function


function b2b(string n, alphabet, alphabet2)
// convert a string from alphabet to alphabet2
func b2b(n, alphabet, alphabet2 string) string {
--
res, m := "0", ""
-- convert a string from alphabet to alphabet2,
if n != "0" {
-- eg b2b("8",decimal,balancedternary) yields "+0-",
base := len(alphabet)
-- & b2b("+0-",balancedternary,decimal) yields "8",
base2 := len(alphabet2)
--
zdx := strings.IndexByte(alphabet, '0') + 1
string res = "0", m = ""
zdx2 := strings.IndexByte(alphabet2, '0') + 1
if n!="0" then
integer base = length(alphabet),
var carry, q, r, digit int
idx := strings.IndexByte(alphabet, n[0]) + 1
base2 = length(alphabet2),
zdx = find('0',alphabet),
negative := (zdx == 1 && n[0] == '-') || (zdx != 1 && idx < zdx)
if negative {
zdx2 = find('0',alphabet2),
carry = 0, q, r, digit
n = negate(n, alphabet)
}
bool negative = (zdx=1 and n[1]='-')
if negative then n = n[2..$] end if
ndp := strings.IndexByte(n, '.') + 1
integer ndp = find('.',n)
if ndp != 0 {
if ndp!=0 then
n, m = n[0:ndp-1], n[ndp:]
}
{n,m} = {n[1..ndp-1],n[ndp+1..$]}
end if
res = ""
res = ""
while length(n) do
for len(n) > 0 {
q = 0
q = 0
for i=1 to length(n) do
for i := 1; i <= len(n); i++ {
--
digit = strings.IndexByte(alphabet, n[i-1]) + 1 - zdx
-- this is a digit-by-digit divide (/mod) loop
q = q*base + digit
-- eg for hex->decimal we would want:
r = abs(q) % base2
-- this loop/modrem("FFFF",10) --> "1999" rem 5,
digit = abs(q)/base2 + zdx
-- this loop/modrem("1999",10) --> "28F" rem 3,
if q < 0 {
-- this loop/modrem("28F",10) --> "41" rem 5,
digit--
-- this loop/modrem("41",10) --> "6" rem 5,
}
-- this loop/modrem("6",10) --> "0" rem 6,
if zdx != 1 {
-- ==> res:="65535" (in 5 full iterations over n).
digit, n = bCarry(digit, base, i-1, n, alphabet)
--
}
digit = find(n[i],alphabet)-zdx
n = changeByte(n, i-1, alphabet[digit-1])
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
q = r
end for
}
r += zdx2
r += zdx2
if zdx2!=1 then
if zdx2 != 1 {
r += carry
r += carry
carry = iff(r>base2?+1:iff(r<1?-1:0))
carry = getCarry(r, base2)
r -= base2*carry
r -= base2 * carry
end if
}
res = alphabet2[r]&res
res = prependByte(res, alphabet2[r-1])
n = trim_head(n,'0')
n = strings.TrimLeft(n, "0")
end while
}
if carry then
if carry != 0 {
res = alphabet2[carry+zdx2]&res
res = prependByte(res, alphabet2[carry+zdx2-1])
end if
}
if length(m) then
if len(m) > 0 {
res &= '.'
res += "."
ndp = 0
ndp = 0
if zdx!=1 then
if zdx != 1 {
-- convert fraction to unbalanced, to simplify the (other-base) multiply.
lm := len(m)
integer lm = length(m)
alphaNew := base37[0:len(alphabet)]
string alphanew = base37[1..length(alphabet)]
m = b2b(m, alphabet, alphaNew)
m = b2b(m,alphabet,alphanew) -- (nb: no fractional part!)
m = strings.Repeat("0", lm-len(m)) + m
m = repeat('0',lm-length(m))&m -- zero-pad if required
alphabet = alphaNew
alphabet = alphanew
zdx = 1
zdx = 1
end if
}
while length(m) and ndp<MAX_DP do
for len(m) > 0 && ndp < maxdp {
q = 0
q = 0
for i=length(m) to 1 by -1 do
for i := len(m); i >= 1; i-- {
--
digit = strings.IndexByte(alphabet, m[i-1]) + 1 - zdx
-- this is a digit-by-digit multiply loop
q += digit * base2
-- eg for [.]"1415" decimal->decimal we
r = abs(q)%base + zdx
-- would repeatedly multiply by 10, giving
q /= base
-- 1 and "4150", then 4 and "1500", then
if q < 0 {
-- 1 and "5000", then 5 and "0000". We
q--
-- strip zeroes between each output digit
}
-- & obviously normally alphabet in!=out.
m = changeByte(m, i-1, alphabet[r-1])
--
}
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
digit = q + zdx2
if zdx2!=1 then
if zdx2 != 1 {
{digit,res} = b_carry(digit,base2,length(res),res,alphabet2)
digit, res = bCarry(digit, base2, len(res), res, alphabet2)
end if
}
res &= alphabet2[digit]
res += string(alphabet2[digit-1])
m = trim_tail(m,'0')
m = strings.TrimRight(m, "0")
ndp += 1
ndp++
end while
}
end if
}
res = b_trim(res)
res = bTrim(res)
if negative then res = negate(res,alphabet2) end if
if negative {
res = negate(res, alphabet2)
end if
}
}
return res
return res
}
end function


// convert 'd' to a string in the specified base
function atm2b(atom d, string alphabet)
func float2b(d float64, alphabet string) string {
--
base := len(alphabet)
-- convert d to a string in the specified base,
zdx := strings.Index(alphabet, "0") + 1
-- eg atm2b(65535,hexadecimal) => "FFFF"
carry := 0
--
neg := d < 0
-- As a standard feature of phix, you can actually specify
if neg {
-- d in any number base between 2 and 36, eg 0(13)168 is
d = -d
-- equivalent to 255 (see test\t37misc.exw for more), but
}
-- not (yet) in balanced number bases, or with fractions,
res := ""
-- except (of course) for normal decimal fractions.
whole := int(d)
--
d -= float64(whole)
-- Note that eg b2b("-436.436",decimal,balancedternary) is
for {
-- more acccurate that atm2b(-436.436,balancedternary) due
ch := whole%base + zdx
-- to standard IEEE 754 floating point limitations.
if zdx != 1 {
-- 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
ch += carry
carry = iff(ch>base?+1:iff(ch<1?-1:0))
carry = getCarry(ch, base)
ch -= base*carry
ch -= base * carry
end if
}
res = alphabet[ch]&res
res = prependByte(res, alphabet[ch-1])
whole = floor(whole/base)
whole /= base
if whole=0 then exit end if
if whole == 0 {
end while
break
if carry then
}
}
res = alphabet[carry+zdx]&res
if carry != 0 {
res = prependByte(res, alphabet[carry+zdx-1])
carry = 0
carry = 0
end if
}
if d!=0 then
if d != 0 {
res &= '.'
res += "."
integer ndp = 0
ndp := 0
while d!=0 and ndp<MAX_DP do
for d != 0 && ndp < maxdp {
d *= base
d *= float64(base)
integer digit = floor(d) + zdx
digit := int(d) + zdx
d -= digit
d -= float64(digit)
if zdx!=1 then
if zdx != 1 {
{digit,res} = b_carry(digit,base,length(res),res,alphabet)
digit, res = bCarry(digit, base, len(res), res, alphabet)
end if
}
res &= alphabet[digit]
res += string(alphabet[digit-1])
ndp += 1
ndp++
end while
}
end if
}
if neg then res = negate(res,alphabet) end if
if neg {
res = negate(res, alphabet)
}
return res
return res
}
end function


function b_add(string a, b, alphabet)
func bAdd(a, b, alphabet string) string {
integer base = length(alphabet),
base := len(alphabet)
zdx = find('0',alphabet),
zdx := strings.IndexByte(alphabet, '0') + 1
carry = 0, da, db, digit
var carry, da, db, digit int
if zdx=1 then
if zdx == 1 {
-- (let me know if you can fix this for me!)
if a[0] == '-' {
if a[1]='-' or b[1]='-' then ?9/0 end if -- +ve only
return bSub(b, negate(a, alphabet), alphabet)
end if
}
integer adt = find('.',a),
if b[0] == '-' {
bdt = find('.',b)
return bSub(a, negate(b, alphabet), alphabet)
if adt or bdt then
}
}
-- remove the '.'s and zero-pad the shorter as needed
adt := strings.IndexByte(a, '.') + 1
-- (thereafter treat them as two whole integers)
bdt := strings.IndexByte(b, '.') + 1
-- eg "1.23"+"4.5" -> "123"+"450" (leaving adt==2)
if adt then adt = length(a)-adt+1; a[-adt..-adt] = "" end if
if adt != 0 || bdt != 0 {
if bdt then bdt = length(b)-bdt+1; b[-bdt..-bdt] = "" end if
if adt != 0 {
if bdt>adt then
adt = len(a) - adt + 1
a &= repeat('0',bdt-adt)
gi := gIndex(-adt, len(a))
a = removeByte(a, gi)
}
if bdt != 0 {
bdt = len(b) - bdt + 1
gi := gIndex(-bdt, len(b))
b = removeByte(b, gi)
}
if bdt > adt {
a += strings.Repeat("0", bdt-adt)
adt = bdt
adt = bdt
elsif adt>bdt then
} else if adt > bdt {
b &= repeat('0',adt-bdt)
b += strings.Repeat("0", adt-bdt)
end if
}
end if
}
if length(a)<length(b) then
if len(a) < len(b) {
{a,b} = {b,a} -- ensure b is the shorter
a, b = b, a
end if
}
for i=-1 to -length(a) by -1 do
for i := -1; i >= -len(a); i-- {
da = iff(i<-length(a)?0:find(a[i],alphabet)-zdx)
if i < -len(a) {
da = 0
db = iff(i<-length(b)?0:find(b[i],alphabet)-zdx)
} else {
da = strings.IndexByte(alphabet, a[len(a)+i]) + 1 - zdx
}
if i < -len(b) {
db = 0
} else {
db = strings.IndexByte(alphabet, b[len(b)+i]) + 1 - zdx
}
digit = da + db + carry + zdx
digit = da + db + carry + zdx
carry = iff(digit>base?+1:iff(digit<1?-1:0))
carry = getCarry(digit, base)
a[i] = alphabet[digit-carry*base]
a = changeByte(a, i+len(a), alphabet[digit-carry*base-1])
if i<-length(b) and carry=0 then exit end if
if i < -len(b) && carry == 0 {
end for
break
if carry then
}
}
a = alphabet[carry+zdx]&a
end if
if carry != 0 {
a = prependByte(a, alphabet[carry+zdx-1])
if adt then
}
a[-adt+1..-adt] = "."
end if
if adt != 0 {
a = b_trim(a)
gi := gIndex(-adt+1, len(a))
a = insertByte(a, gi, '.')
}
a = bTrim(a)
return a
return a
}
end function


function b_mul(string a, b, alphabet)
func aSmaller(a, b, alphabet string) bool {
integer base = length(alphabet),
if len(a) != len(b) {
zdx = find('0',alphabet),
log.Fatal("strings should be equal in length")
}
dpa = find('.',a),
dpb = find('.',b),
for i := 1; i <= len(a); i++ {
ndp = 0
da := strings.IndexByte(alphabet, a[i-1]) + 1
if dpa then ndp += length(a)-dpa; a[dpa..dpa] = "" end if
db := strings.IndexByte(alphabet, b[i-1]) + 1
if dpb then ndp += length(b)-dpb; b[dpb..dpb] = "" end if
if da != db {
string pos = a, res = "0"
return da < db
if zdx!=1 then
}
}
-- balanced number systems
return false
string neg = negate(pos,alphabet)
}
for i=length(b) to 1 by -1 do

integer m = find(b[i],alphabet)-zdx
func bSub(a, b, alphabet string) string {
while m do
res = b_add(res,iff(m<0?neg:pos),alphabet)
base := len(alphabet)
zdx := strings.IndexByte(alphabet, '0') + 1
m += iff(m<0?+1:-1)
end while
var carry, da, db, digit int
pos &= '0'
if zdx == 1 {
neg &= '0'
if a[0] == '-' {
return negate(bAdd(negate(a, alphabet), b, alphabet), alphabet)
end for
else
}
-- non-balanced (normal) number systems
if b[0] == '-' {
return bAdd(a, negate(b, alphabet), alphabet)
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
adt := strings.Index(a, ".") + 1
for i=length(b) to 1 by -1 do
bdt := strings.Index(b, ".") + 1
integer m = find(b[i],alphabet)-zdx
while m>0 do
if adt != 0 || bdt != 0 {
res = b_add(res,pos,alphabet)
if adt != 0 {
m -= 1
adt = len(a) - adt + 1
end while
gi := gIndex(-adt, len(a))
pos &= '0'
a = removeByte(a, gi)
end for
}
if negative then res = negate(res,alphabet) end if
if bdt != 0 {
bdt = len(b) - bdt + 1
end if
gi := gIndex(-bdt, len(b))
if ndp then
res[-ndp..-ndp-1] = "."
b = removeByte(b, gi)
end if
}
res = b_trim(res)
if bdt > adt {
a += strings.Repeat("0", bdt-adt)
adt = bdt
} else if adt > bdt {
b += strings.Repeat("0", adt-bdt)
}
}
bNegate := false
if len(a) < len(b) || (len(a) == len(b) && aSmaller(a, b, alphabet)) {
bNegate = true
a, b = b, a
}
for i := -1; i >= -len(a); i-- {
if i < -len(a) {
da = 0
} else {
da = strings.IndexByte(alphabet, a[len(a)+i]) + 1 - zdx
}
if i < -len(b) {
db = 0
} else {
db = strings.IndexByte(alphabet, b[len(b)+i]) + 1 - zdx
}
digit = da - db - carry + zdx
carry = 0
if digit <= 0 {
carry = 1
}
a = changeByte(a, i+len(a), alphabet[digit+carry*base-1])
if i < -len(b) && carry == 0 {
break
}
}
if carry != 0 {
log.Fatal("carry should be zero")
}
if adt != 0 {
gi := gIndex(-adt+1, len(a))
a = insertByte(a, gi, '.')
}
a = bTrim(a)
if bNegate {
a = negate(a, alphabet)
}
return a
}

func bMul(a, b, alphabet string) string {
zdx := strings.IndexByte(alphabet, '0') + 1
dpa := strings.IndexByte(a, '.') + 1
dpb := strings.IndexByte(b, '.') + 1
ndp := 0
if dpa != 0 {
ndp += len(a) - dpa
a = removeByte(a, dpa-1)
}
if dpb != 0 {
ndp += len(b) - dpb
b = removeByte(b, dpb-1)
}
pos, res := a, "0"
if zdx != 1 {
// balanced number systems
neg := negate(pos, alphabet)
for i := len(b); i >= 1; i-- {
m := strings.IndexByte(alphabet, b[i-1]) + 1 - zdx
for m != 0 {
temp, temp2 := pos, -1
if m < 0 {
temp = neg
temp2 = 1
}
res = bAdd(res, temp, alphabet)
m += temp2
}
pos += "0"
neg += "0"
}
} else {
// non-balanced number systems
negative := false
if a[0] == '-' {
a = a[1:]
negative = true
}
if b[0] == '-' {
b = b[1:]
negative = !negative
}
for i := len(b); i >= 1; i-- {
m := strings.IndexByte(alphabet, b[i-1]) + 1 - zdx
for m > 0 {
res = bAdd(res, pos, alphabet)
m--
}
pos += "0"
}
if negative {
res = negate(res, alphabet)
}
}
if ndp != 0 {
gi := gIndex(-ndp, len(res))
res = insertByte(res, gi, '.')
}
res = bTrim(res)
return res
return res
}
end function

func multTable() {
fmt.Println("multiplication table")
fmt.Println("====================")
fmt.Printf("* |")
for j := 1; j <= 12; j++ {
fj := float64(j)
fmt.Printf(" #%s %3s |", float2b(fj, hexadecimal), float2b(fj, balancedTernary))
}
for i := 1; i <= 27; i++ {
fi := float64(i)
a := float2b(fi, balancedTernary)
fmt.Printf("\n%-2s|", float2b(fi, septemVigesimal))
for j := 1; j <= 12; j++ {
if j > i {
fmt.Printf(" |")
} else {
fj := float64(j)
b := float2b(fj, balancedTernary)
m := bMul(a, b, balancedTernary)
fmt.Printf(" %6s |", m)
}
}
}
fmt.Println()
}

func test(name, alphabet string) {
a := b2b("+-0++0+.+-0++0+", balancedTernary, alphabet)
b := b2b("-436.436", decimal, alphabet)
c := b2b("+-++-.+-++-", balancedTernary, alphabet)
d := bSub(b, c, alphabet)
r := bMul(a, d, alphabet)
fmt.Printf("%s\n%s\n", name, strings.Repeat("=", len(name)))
fmt.Printf(" a = %.16g %s\n", b2dec(a, alphabet), a)
fmt.Printf(" b = %.16g %s\n", b2dec(b, alphabet), b)
fmt.Printf(" c = %.16g %s\n", b2dec(c, alphabet), c)
fmt.Printf("a*(b-c) = %.16g %s\n\n", b2dec(r, alphabet), r)
}


func main() {
-- [note 1] not surprisingly, the decimal output is somewhat cleaner/shorter when
test("balanced ternary", balancedTernary)
-- the decimal string inputs for a and c are used, whereas tests 1/2/5/7
test("balanced base 27", balancedBase27)
-- (the 3-based ones) look much better with all ternary string inputs.
test("decimal", decimal)
-- [note 2] proof that b_mul() copes with negative numbers, though b_add() dis'ne.
test("binary", binary)
test("ternary", ternary)
test("hexadecimal", hexadecimal)
test("septemvigesimal", septemVigesimal)
multTable()
}</syntaxhighlight>


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}}
{{out}}
<pre>
<pre>
Line 643: Line 803:
================
================
a = 523.2391403749428 +-0++0+.+-0++0+
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--
b = -436.4359999999999 -++-0--.--0+-00+++-0-+---0-+0++++0--0000+00-+-+--+0-0-00--++0-+00---+0+-+++0+-0----0++
c = 65.26748971193416 +-++-.+-++-
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----
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
balanced base 27
================
================
a = 523.2391403749428 AUJ.FLI
a = 523.2391403749428 AUJ.FLI
b = -436.4359999999999 NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
b = 436.436 AXD.LSQSGLFZUINATKCIKUVMWEWJMQ0COTSWNRONXBMBQYL0VGRUCDYFDFTYSMHVANGXPVXHIZJRJWZD0PBGF
c = 65.26748971193416 BK.GF
c = 65.26748971193416 BK.GF
a*(b-c) = -262510.9026799812 ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO
a*(b+c) = 262510.9026799813 MICW.PJALDCRRAQIQCAWMKXSTPYUXYPK0LVOBZRGUSJJOGIHSNU0FRMZGOWQPEENDVDPNJZXKFGCLHKLCX0YBQHB

decimal
=======
a = 523.2391403749428 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
b = -436.436 -436.436
c = 65.26748971193413 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b-c) = -262510.9026799813 -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.4360000000002 -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.4359999999999 -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
c = 65.26748971193416 2B.76
a*(b-c) = -262510.9026799812 -D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82

multiplication table
====================
* | #1 + | #2 +- | #3 +0 | #4 ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 | + | | | | | | | | | | | |
2 | +- | ++ | | | | | | | | | | |
3 | +0 | +-0 | +00 | | | | | | | | | |
4 | ++ | +0- | ++0 | +--+ | | | | | | | | |
5 | +-- | +0+ | +--0 | +-+- | +0-+ | | | | | | | |
6 | +-0 | ++0 | +-00 | +0-0 | +0+0 | ++00 | | | | | | |
7 | +-+ | +--- | +-+0 | +00+ | ++0- | +---0 | +--++ | | | | | |
8 | +0- | +--+ | +0-0 | ++-- | ++++ | +--+0 | +-0+- | +-+0+ | | | | |
9 | +00 | +-00 | +000 | ++00 | +--00 | +-000 | +-+00 | +0-00 | +0000 | | | |
A | +0+ | +-+- | +0+0 | ++++ | +-0-- | +-+-0 | +0--+ | +000- | +0+00 | ++-0+ | | |
B | ++- | +-++ | ++-0 | +--0- | +-00+ | +-++0 | +00-- | +0+-+ | ++-00 | ++0+- | +++++ | |
C | ++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 | +--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--- | +00++ | ++-+0 | ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 |
I | +-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+00 | +-+00+ | +0--+- | +0-++0 |
K | +-+- | ++++ | +-+-0 | +000- | ++-0+ | ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 |
L | +-+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 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 |
O | +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-+00 | +00+-+ | +0++-- | ++-0+0 |
Q | +00- | +-0-+ | +00-0 | ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 |
10| +000 | +-000 | +0000 | ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |
</pre>


=={{header|Julia}}==
<syntaxhighlight lang="julia">using Formatting
import Base.BigInt, Base.BigFloat, Base.print, Base.+, Base.-, Base.*

abstract type BalancedBaseDigitArray end

mutable struct BalancedTernary <: BalancedBaseDigitArray
dig::Vector{Int8}
p::Int
BalancedTernary(arr::Vector, i) = new(Int8.(arr), i)
end

const MAX_PRECISION = 81

function BalancedTernary(s::String)
if (i = findfirst(x -> x == '.', s)) != nothing
p = length(s) - i
s = s[1:i-1] * s[i+1:end]
else
p = 0
end
b = BalancedTernary([c == '-' ? -1 : c == '0' ? 0 : 1 for c in s], p) # 2
end

function BalancedTernary(n::Integer) # 1, 3
if n < 0
return -BalancedTernary(-n)
elseif n == 0
return BalancedTernary([0], 0)
else
return canonicalize!(BalancedTernary(reverse(digits(n, base=3)), 0))
end
end
BalancedTernary() = BalancedTernary(0)

function BalancedTernary(x::Real) # 1, 3
if x < 0
return -BalancedTernary(-x)
end
arr = reverse(digits(BigInt(round(x * big"3.0"^MAX_PRECISION)), base=3))
return canonicalize!(BalancedTernary(arr, MAX_PRECISION))
end

function String(b::BalancedTernary) # 3
canonicalize!(b)
s = String([['-', '0', '+'][c + 2] for c in b.dig])
if b.p > 0
if b.p < length(s)
s = s[1:end-b.p] * "." * s[end-b.p+1:end]
elseif b.p == length(s)
s = "0." * s
else
s = "0." * "0"^(b.p - length(s)) * s
end
end
return s
end

function BigInt(b::BalancedTernary)
canonicalize!(b)
if b.p > 0
throw(InexactError("$(b.p) places after decimal point"))
end
return sum(t -> BigInt(3)^(t[1] - 1) * t[2], enumerate(reverse(b.dig))) # 3
end

BigFloat(b::BalancedTernary) = BigInt(BalancedTernary(b.dig, 0)) / big"3.0"^(b.p)

function canonicalize!(b::BalancedTernary)
for i in length(b.dig):-1:1
if b.dig[i] > 1
b.dig[i] -= 3
if i == 1
pushfirst!(b.dig, 1)
else
b.dig[i - 1] += 1
end
elseif b.dig[i] < -1
b.dig[i] += 3
if i == 1
pushfirst!(b.dig, -1)
else
b.dig[i - 1] -= 1
end
end
end
if (i = findfirst(x -> x != 0, b.dig)) != nothing
if i > 1
b.dig = b.dig[i:end]
end
else
b.dig = [0]
end
if b.p > 0 && (i = findlast(x -> x != 0, b.dig)) != nothing
removable = min(b.p, length(b.dig) - i)
b.dig = b.dig[1:end-removable]
b.p -= removable
end
return b
end

# The following should work with any base number where dig, p are a similar array and Int
# and the proper constructors, canon, and conversion routines are defined # 6

Base.print(io::IO, b::BalancedBaseDigitArray) = print(io, String(b))

function +(b1::T, b2::T) where T <: BalancedBaseDigitArray # 4
if all(x -> x == 0, b1.dig)
return deepcopy(b2)
elseif all(x -> x == 0, b2.dig)
return deepcopy(b1)
end
ldigits1 = length(b1.dig) - b1.p
arr = b1.dig[1:ldigits1]
ldigits2 = length(b2.dig) - b2.p
arr2 = b2.dig[1:ldigits2]
if (i = ldigits1 - ldigits2) > 0
arr2 = [zeros(Int8, i); arr2]
elseif i < 0
arr = [zeros(Int8, -i); arr]
end
if (i = b1.p - b2.p) > 0
arr = [arr; b1.dig[ldigits1+1:end]]
arr2 = [arr2; b2.dig[ldigits2+1:end]; zeros(Int8, i)]
elseif i < 0
arr = [arr; b1.dig[ldigits1+1:end]; zeros(Int8, -i)]
arr2 = [arr2; b2.dig[ldigits2+1:end]]
else
arr = [arr; b1.dig[ldigits1+1:end]]
arr2 = [arr2; b2.dig[ldigits2+1:end]]
end
arr .+= arr2
return canonicalize!(T(arr, max(b1.p, b2.p)))
end

-(b1::T) where T <: BalancedBaseDigitArray = T(b1.dig .* -1, b1.p) # 4
-(b1::T, b2::T) where T <: BalancedBaseDigitArray = +(b1, -b2) # 4

function *(b1::T, b2::T) where T <: BalancedBaseDigitArray # 4
len = length(b2.dig)
bsum = T()
for i in len:-1:1
bsum += T([b1.dig .* b2.dig[i]; zeros(Int8, len - i)], 0)
end
bsum.p = b1.p + b2.p
return canonicalize!(bsum)
end

function code_reuse_task(T::Type)
a = T("+-0++0+.+-0++0+")
b = T(-436.436)
c = T("+-++-.+-++-")
println(" a = ", a, " = ", format(BigFloat(a)))
println(" b = ", b, " = ", format(BigFloat(b)))
println(" c = ", c, " = ", format(BigFloat(c)))
println("\na * (b - c) = ", String(a * (b - c)), "\n = ", format(BigFloat(a * (b - c))))

println("\n Multiplication 27 X 12")
println(" x|+ (1) |+- (2) |+0 (3) |++ (4) |+-- (5)|+-0 (6)|+-+ (7)|+0- (8)|+e+-(9)|+0+(10)|++-(11)|++0(12)|")
for i in 1:27
print(lpad(i, 2), "|")
for j in 1:12
print(lpad(String(T(i * j)), 7), "|")
end
print("\n")
end
end

code_reuse_task(BalancedTernary)
</syntaxhighlight>{{out}}
<pre>
a = +-0++0+.+-0++0+ = 523.23914
b = -++-0--.--0+-00+++-0-+---0-+0++++0--++++0-+0+-0+0+-000-0----+0--0---+-000++--++-+-0--0-+ = -436.436
c = +-++-.+-++- = 65.26749

a * (b - c) = ----000-0+0+.0+0-0-00---00--0-0+--+0-0+0++-+-0--0--+0-++-0-+00-++0-0-0+++--0-+0--+-++-+-+-++-+0+-+-+
= -262510.90268

Multiplication 27 X 12
x|+ (1) |+- (2) |+0 (3) |++ (4) |+-- (5)|+-0 (6)|+-+ (7)|+0- (8)|+e+-(9)|+0+(10)|++-(11)|++0(12)|
1| +| +-| +0| ++| +--| +-0| +-+| +0-| +00| +0+| ++-| ++0|
2| +-| ++| +-0| +0-| +0+| ++0| +---| +--+| +-00| +-+-| +-++| +0-0|
3| +0| +-0| +00| ++0| +--0| +-00| +-+0| +0-0| +000| +0+0| ++-0| ++00|
4| ++| +0-| ++0| +--+| +-+-| +0-0| +00+| ++--| ++00| ++++| +--0-| +--+0|
5| +--| +0+| +--0| +-+-| +0-+| +0+0| ++0-| ++++| +--00| +-0--| +-00+| +-+-0|
6| +-0| ++0| +-00| +0-0| +0+0| ++00| +---0| +--+0| +-000| +-+-0| +-++0| +0-00|
7| +-+| +---| +-+0| +00+| ++0-| +---0| +--++| +-0+-| +-+00| +0--+| +00--| +00+0|
8| +0-| +--+| +0-0| ++--| ++++| +--+0| +-0+-| +-+0+| +0-00| +000-| +0+-+| ++--0|
9| +00| +-00| +000| ++00| +--00| +-000| +-+00| +0-00| +0000| +0+00| ++-00| ++000|
10| +0+| +-+-| +0+0| ++++| +-0--| +-+-0| +0--+| +000-| +0+00| ++-0+| ++0+-| ++++0|
11| ++-| +-++| ++-0| +--0-| +-00+| +-++0| +00--| +0+-+| ++-00| ++0+-| +++++| +--0-0|
12| ++0| +0-0| ++00| +--+0| +-+-0| +0-00| +00+0| ++--0| ++000| ++++0| +--0-0| +--+00|
13| +++| +00-| +++0| +-0-+| +-++-| +00-0| +0+0+| ++0--| +++00| +---++| +--+0-| +-0-+0|
14| +---| +00+| +---0| +-0+-| +0--+| +00+0| ++-0-| ++0++| +---00| +--+--| +-0-0+| +-0+-0|
15| +--0| +0+0| +--00| +-+-0| +0-+0| +0+00| ++0-0| ++++0| +--000| +-0--0| +-00+0| +-+-00|
16| +--+| ++--| +--+0| +-+0+| +000-| ++--0| ++0++| +---+-| +--+00| +-00-+| +-+---| +-+0+0|
17| +-0-| ++-+| +-0-0| +0---| +00++| ++-+0| ++++-| +--00+| +-0-00| +-0+0-| +-+0-+| +0---0|
18| +-00| ++00| +-000| +0-00| +0+00| ++000| +---00| +--+00| +-0000| +-+-00| +-++00| +0-000|
19| +-0+| +++-| +-0+0| +0-++| ++---| +++-0| +--0-+| +-0-0-| +-0+00| +-+00+| +0--+-| +0-++0|
20| +-+-| ++++| +-+-0| +000-| ++-0+| ++++0| +--+--| +-00-+| +-+-00| +-+++-| +0-0++| +000-0|
21| +-+0| +---0| +-+00| +00+0| ++0-0| +---00| +--++0| +-0+-0| +-+000| +0--+0| +00--0| +00+00|
22| +-++| +--0-| +-++0| +0+-+| ++0+-| +--0-0| +-0-0+| +-+---| +-++00| +0-0++| +0000-| +0+-+0|
23| +0--| +--0+| +0--0| +0++-| +++-+| +--0+0| +-000-| +-+-++| +0--00| +00---| +00+0+| +0++-0|
24| +0-0| +--+0| +0-00| ++--0| ++++0| +--+00| +-0+-0| +-+0+0| +0-000| +000-0| +0+-+0| ++--00|
25| +0-+| +-0--| +0-+0| ++-0+| +---0-| +-0--0| +-0+++| +-+++-| +0-+00| +00+-+| +0++--| ++-0+0|
26| +00-| +-0-+| +00-0| ++0--| +---++| +-0-+0| +-+-+-| +0--0+| +00-00| +0+-0-| ++---+| ++0--0|
27| +000| +-000| +0000| ++000| +--000| +-0000| +-+000| +0-000| +00000| +0+000| ++-000| ++0000|
</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. 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.

<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Generic_multiplication.exw</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">MAX_DP</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">81</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">binary</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"01"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">ternary</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"012"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">balancedternary</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"-0+"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">decimal</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0123456789"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">hexadecimal</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0123456789ABCDEF"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">septemvigesimal</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0123456789ABCDEFGHIJKLMNOPQ"</span><span style="color: #0000FF;">,</span>
<span style="color: #000080;font-style:italic;">-- heptavintimal = "0123456789ABCDEFGHKMNPRTVXZ", -- ??
-- wonky_donkey_26 = "0ABCDEFGHIJKLMNOPQRSTUVWXY",
-- wonky_donkey_27 = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ",</span>
<span style="color: #000000;">balanced_base27</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"ZYXWVUTSRQPON0ABCDEFGHIJKLM"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">base37</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</span>
<span style="color: #000080;font-style:italic;">--
--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.
--</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b2dec</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- convert string b back into a normal (decimal) atom,
-- eg b2dec("+0-",balancedternary) yields 8
--</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">signed</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">signed</span> <span style="color: #008080;">then</span> <span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">len</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ndp</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">..</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #000080;font-style:italic;">-- remove '.'</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">len</span><span style="color: #0000FF;">-</span><span style="color: #000000;">ndp</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">base</span><span style="color: #0000FF;">*</span><span style="color: #000000;">res</span><span style="color: #0000FF;">+</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ndp</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">/=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">base</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">signed</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">res</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- negate b (can be balanced or unbalanced)
--</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- traditional: add/remove a leading '-'
-- eg "-123" &lt;==&gt; "123"</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">"0"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"-"</span><span style="color: #0000FF;">&</span><span style="color: #000000;">b</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">else</span>
<span style="color: #000080;font-style:italic;">-- balanced: mirror [non-0] digits
-- eg "-0+" (ie -8) &lt;==&gt; "+0-" (ie +8)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'.'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[-</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">b</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b_trim</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- (common code)
-- trim trailing ".000"</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim_tail</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">trim_tail</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">),</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- trim leading zeroes, but not "0.nnn" -&gt; ".nnn"
-- [hence we cannot use the standard trim_head()]</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)></span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'.'</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">b</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b_carry</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">base</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">idx</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- (common code, for balanced number systems only)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">></span><span style="color: #000000;">base</span><span style="color: #0000FF;">?+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;"><</span><span style="color: #000000;">1</span><span style="color: #0000FF;">?-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">idx</span> <span style="color: #008080;">to</span> <span style="color: #000000;">0</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #008000;">'.'</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;"><</span><span style="color: #000000;">base</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">exit</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">base</span><span style="color: #0000FF;">*</span><span style="color: #000000;">carry</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b2b</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- convert a string from alphabet to alphabet2,
-- eg b2b("8",decimal,balancedternary) yields "+0-",
-- & b2b("+0-",balancedternary,decimal) yields "8",
--</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">!=</span><span style="color: #008000;">"0"</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">base2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">q</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">digit</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">negative</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">((</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">or</span>
<span style="color: #0000FF;">(</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">and</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">negative</span> <span style="color: #008080;">then</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ndp</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">m</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$]}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">--
-- this is a digit-by-digit divide (/mod) loop
-- eg for hex-&gt;decimal we would want:
-- this loop/modrem("FFFF",10) --&gt; "1999" rem 5,
-- this loop/modrem("1999",10) --&gt; "28F" rem 3,
-- this loop/modrem("28F",10) --&gt; "41" rem 5,
-- this loop/modrem("41",10) --&gt; "6" rem 5,
-- this loop/modrem("6",10) --&gt; "0" rem 6,
-- ==&gt; res:="65535" (in 5 full iterations over n).
--</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">q</span><span style="color: #0000FF;">*</span><span style="color: #000000;">base</span><span style="color: #0000FF;">+</span><span style="color: #000000;">digit</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base2</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">/</span><span style="color: #000000;">base2</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">zdx</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_carry</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">n</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">r</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zdx2</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx2</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">carry</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">></span><span style="color: #000000;">base2</span><span style="color: #0000FF;">?+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;"><</span><span style="color: #000000;">1</span><span style="color: #0000FF;">?-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">base2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">carry</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">r</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">res</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim_head</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">+</span><span style="color: #000000;">zdx2</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'.'</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- convert fraction to unbalanced, to simplify the (other-base) multiply.</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">lm</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">alphanew</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">base37</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)]</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphanew</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (nb: no fractional part!)</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lm</span><span style="color: #0000FF;">-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">))&</span><span style="color: #000000;">m</span> <span style="color: #000080;font-style:italic;">-- zero-pad if required</span>
<span style="color: #000000;">alphabet</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphanew</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ndp</span><span style="color: #0000FF;"><</span><span style="color: #000000;">MAX_DP</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000080;font-style:italic;">--
-- this is a digit-by-digit multiply loop
-- eg for [.]"1415" decimal-&gt;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.
--</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">digit</span><span style="color: #0000FF;">*</span><span style="color: #000000;">base2</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">zdx</span>
<span style="color: #000000;">q</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">q</span><span style="color: #0000FF;">/</span><span style="color: #000000;">base</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">m</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">r</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">q</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zdx2</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx2</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_carry</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base2</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">),</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">[</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">trim_tail</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">negative</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet2</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- convert d to a string in the specified base,
-- eg atm2b(65535,hexadecimal) =&gt; "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().
--</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">neg</span> <span style="color: #008080;">then</span> <span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">d</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">whole</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">whole</span>
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">whole</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zdx</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">carry</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #000000;">base</span><span style="color: #0000FF;">?+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #000000;">1</span><span style="color: #0000FF;">?-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">base</span><span style="color: #0000FF;">*</span><span style="color: #000000;">carry</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">res</span>
<span style="color: #000000;">whole</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">whole</span><span style="color: #0000FF;">/</span><span style="color: #000000;">base</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">whole</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">+</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">res</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'.'</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ndp</span><span style="color: #0000FF;"><</span><span style="color: #000000;">MAX_DP</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">base</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zdx</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">digit</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_carry</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">,</span><span style="color: #000000;">base</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">),</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">neg</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">-- 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&gt;b: a-b == -(b-a) [avoid running off end]</span>
<span style="color: #008080;">forward</span> <span style="color: #008080;">function</span> <span style="color: #000000;">b_sub</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">da</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">db</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">digit</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (-a)+b == b-a</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">b_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- a+(-b) == a-b</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">b_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">bdt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">or</span> <span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- remove the '.'s and zero-pad the shorter as needed
-- (thereafter treat them as two whole integers)
-- eg "1.23"+"4.5" -&gt; "123"+"450" (leaving adt==2)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">then</span> <span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span> <span style="color: #000000;">bdt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bdt</span><span style="color: #0000FF;">></span><span style="color: #000000;">adt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bdt</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">adt</span><span style="color: #0000FF;">></span><span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)<</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- ensure b is the shorter</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">da</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">db</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">da</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">db</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">carry</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zdx</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">></span><span style="color: #000000;">base</span><span style="color: #0000FF;">?+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digit</span><span style="color: #0000FF;"><</span><span style="color: #000000;">1</span><span style="color: #0000FF;">?-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:</span><span style="color: #000000;">0</span><span style="color: #0000FF;">))</span>
<span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">-</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">*</span><span style="color: #000000;">base</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">carry</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">+</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">]&</span><span style="color: #000000;">a</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"."</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">a_smaller</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- return true if a is smaller than b
-- if not balanced then both are +ve</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)!=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span> <span style="color: #000080;font-style:italic;">-- sanity check</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">da</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">db</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">compare</span><span style="color: #0000FF;">(</span><span style="color: #000000;">da</span><span style="color: #0000FF;">,</span><span style="color: #000000;">db</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">return</span> <span style="color: #000000;">c</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #004600;">false</span> <span style="color: #000080;font-style:italic;">-- (=, which is not &lt;)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b_sub</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">da</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">db</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">digit</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (-a)-b == -(a+b)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- a-(-b) == a+b</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">bdt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">or</span> <span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- remove the '.'s and zero-pad the shorter as needed
-- (thereafter treat them as two whole integers)
-- eg "1.23"+"4.5" -&gt; "123"+"450" (leaving adt==2)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">then</span> <span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span> <span style="color: #000000;">bdt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bdt</span><span style="color: #0000FF;">></span><span style="color: #000000;">adt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">adt</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">bdt</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">adt</span><span style="color: #0000FF;">></span><span style="color: #000000;">bdt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">-</span><span style="color: #000000;">bdt</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">bNegate</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)<</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">or</span> <span style="color: #0000FF;">(</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">a_smaller</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">))</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">bNegate</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- ensure b is the shorter/smaller</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">da</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">db</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)?</span><span style="color: #000000;">0</span><span style="color: #0000FF;">:</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">digit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">da</span> <span style="color: #0000FF;">-</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">db</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">carry</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">zdx</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">digit</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span>
<span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">[</span><span style="color: #000000;">digit</span><span style="color: #0000FF;">+</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">*</span><span style="color: #000000;">base</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">i</span><span style="color: #0000FF;"><-</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #000000;">carry</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">then</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- should have set bNegate above...</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">adt</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">adt</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"."</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">bNegate</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">b_mul</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">base</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zdx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'0'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">dpa</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">a</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">dpb</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'.'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">ndp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dpa</span> <span style="color: #008080;">then</span> <span style="color: #000000;">ndp</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">dpa</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">dpa</span><span style="color: #0000FF;">..</span><span style="color: #000000;">dpa</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">dpb</span> <span style="color: #008080;">then</span> <span style="color: #000000;">ndp</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">dpb</span><span style="color: #0000FF;">;</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">dpb</span><span style="color: #0000FF;">..</span><span style="color: #000000;">dpb</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">pos</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"0"</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">zdx</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000080;font-style:italic;">-- balanced number systems</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">neg</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">m</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">neg</span><span style="color: #0000FF;">:</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">),</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">+=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">:-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'0'</span>
<span style="color: #000000;">neg</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'0'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">else</span>
<span style="color: #000080;font-style:italic;">-- non-balanced (normal) number systems</span>
<span style="color: #004080;">bool</span> <span style="color: #000000;">negative</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$];</span> <span style="color: #000000;">negative</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #008000;">'-'</span> <span style="color: #008080;">then</span> <span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$];</span> <span style="color: #000000;">negative</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">not</span> <span style="color: #000000;">negative</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">to</span> <span style="color: #000000;">1</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">zdx</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pos</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">m</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">pos</span> <span style="color: #0000FF;">&=</span> <span style="color: #008000;">'0'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">negative</span> <span style="color: #008080;">then</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">negate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ndp</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">res</span><span style="color: #0000FF;">[-</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">ndp</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"."</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_trim</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">res</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000080;font-style:italic;">-- [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.</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">name</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--string a = b2b("523.2391403749428",decimal,alphabet), -- [see note 1]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b2b</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"+-0++0+.+-0++0+"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b2b</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"-436.436"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">decimal</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000080;font-style:italic;">-- b = b2b("-++-0--.--0+-00+++-",balancedternary,alphabet),
-- c = b2b("65.26748971193416",decimal,alphabet), -- [see note 1]</span>
<span style="color: #000000;">c</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b2b</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"+-++-.+-++-"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s\n%s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">name</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">'='</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">name</span><span style="color: #0000FF;">))})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" a = %.16g %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">b2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">a</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" b = %.16g %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">b2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">b</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" c = %.16g %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">b2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">c</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">c</span><span style="color: #0000FF;">})</span>
<span style="color: #000080;font-style:italic;">-- printf(1," d = %.16g %s\n",{b2dec(d,alphabet),d})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"a*(b-c) = %.16g %s\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">b2dec</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">,</span><span style="color: #000000;">alphabet</span><span style="color: #0000FF;">),</span><span style="color: #000000;">r</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"balanced ternary"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"balanced base 27"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">balanced_base27</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"decimal"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">decimal</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"binary"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">binary</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"ternary"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ternary</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"hexadecimal"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">hexadecimal</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">test</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"septemvigesimal"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">septemvigesimal</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
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] regarding decimal/ternary input, just 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 NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
c = 65.26748971193416 BK.GF
a*(b-c) = -262510.9026799813 ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO


decimal
decimal
=======
=======
a = 523.239140374943 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
a = 523.239140374943 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
b = 436.436 436.436
b = -436.436 -436.436
c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b+c) = 262510.9026799814 262510.90267998140903693918986303277315826215892262734715612833785876513103053772667101895163734826631742752252837097627017862754285047634638652268078676654605120794218
a*(b-c) = -262510.9026799814 -262510.90267998140903693918986303277315826215892262734715612833785876513103053772667101895163734826631742752252837097627017862754285047634638652268078676654605120794218


binary
binary
======
======
a = 523.2391403749427 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111
a = 523.2391403749427 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111
b = 436.436 110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001
b = -436.436 -110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001
c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101
c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101
a*(b+c) = 262510.9026799814 1000000000101101110.111001110001011000001001000001101110011111011100000100000100001000101011100011110010110001010100110111001011101001010000001110110100111110001101000000001111110101
a*(b-c) = -262510.9026799814 -1000000000101101110.111001110001011000001001000001101110011111011100000100000100001000101011100011110010110001010100110111001011101001010000001110110100111110001101000000001111110101


ternary
ternary
=======
=======
a = 523.2391403749428 201101.0201101
a = 523.2391403749428 201101.0201101
b = 436.4360000000001 121011.102202211210021110012111201022222000202102010100101200200110122011122101110212
b = -436.4360000000001 -121011.102202211210021110012111201022222000202102010100101200200110122011122101110212
c = 65.26748971193416 2102.02102
c = 65.26748971193416 2102.02102
a*(b+c) = 262510.9026799813 111100002121.2201010011100110022102110002120222120100001221111011202022012121122001201122110221112
a*(b-c) = -262510.9026799813 -111100002121.2201010011100110022102110002120222120100001221111011202022012121122001201122110221112


hexadecimal
hexadecimal
===========
===========
a = 523.2391403749427 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62
a = 523.2391403749427 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62
b = 436.436 1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2
b = -436.436 -1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2
c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905
c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905
a*(b+c) = 262510.9026799814 4016E.E7160906E7DC10422DA508321819F4A637E5AEE668ED5163B12FCB17A732442F589975B7F24112B2E8F6E95EAD45803915EE26D20DF323D67CAEEC75D7BED68AA34E02F2B492257D66F028545FB398F60E
a*(b-c) = -262510.9026799814 -4016E.E7160906E7DC10422DA508321819F4A637E5AEE668ED5163B12FCB17A732442F589975B7F24112B2E8F6E95EAD45803915EE26D20DF323D67CAEEC75D7BED68AA34E02F2B492257D66F028545FB398F60E


septemvigesimal
septemvigesimal
===============
===============
a = 523.2391403749428 JA.6C9
a = 523.2391403749428 JA.6C9
b = 436.436 G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
b = -436.436 -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
c = 65.26748971193416 2B.76
c = 65.26748971193416 2B.76
a*(b+c) = 262510.9026799813 D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82
a*(b-c) = -262510.9026799813 -D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82
</pre>
</pre>


=== multiplication table ===
=== multiplication table ===
Without e notation, with hexadecimal across, septemvigesimal down, and balanced ternary contents!
Without e notation, with hexadecimal across, septemvigesimal down, and balanced ternary contents!
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>printf(1,"# |")
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"* |"</span><span style="color: #0000FF;">)</span>
for j=1 to 12 do
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">12</span> <span style="color: #008080;">do</span>
printf(1," #%s %3s |",{atm2b(j,hexadecimal),atm2b(j,balancedternary)})
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" #%s %3s |"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hexadecimal</span><span style="color: #0000FF;">),</span><span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">)})</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
for i=1 to 27 do
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">27</span> <span style="color: #008080;">do</span>
string a = atm2b(i,balancedternary)
<span style="color: #004080;">string</span> <span style="color: #000000;">a</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">)</span>
printf(1,"\n%-2s|",{atm2b(i,septemvigesimal)})
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n%-2s|"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">septemvigesimal</span><span style="color: #0000FF;">)})</span>
for j=1 to 12 do
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">12</span> <span style="color: #008080;">do</span>
if j>i then
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">></span><span style="color: #000000;">i</span> <span style="color: #008080;">then</span>
printf(1," |")
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" |"</span><span style="color: #0000FF;">)</span>
else
string b = atm2b(j,balancedternary)
<span style="color: #008080;">else</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">b</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">atm2b</span><span style="color: #0000FF;">(</span><span style="color: #000000;">j</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">)</span>
string m = b_mul(a,b,balancedternary)
<span style="color: #004080;">string</span> <span style="color: #000000;">m</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">b_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">,</span><span style="color: #000000;">balancedternary</span><span style="color: #0000FF;">)</span>
printf(1," %6s |",{m})
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" %6s |"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">m</span><span style="color: #0000FF;">})</span>
end if
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
printf(1,"\n")</lang>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
# | * | + #1 | +- #2 | +0 #3 | ++ #4 | +-- #5 | +-0 #6 | +-+ #7 | +0- #8 | +00 #9 | +0+ #A | ++- #B | ++0 #C |
* | #1 + | #2 +- | #3 +0 | #4 ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 | + | + | | | | | | | | | | | |
1 | + | | | | | | | | | | | |
2 | +- | +- | ++ | | | | | | | | | | |
2 | +- | ++ | | | | | | | | | | |
3 | +0 | +0 | +-0 | +00 | | | | | | | | | |
3 | +0 | +-0 | +00 | | | | | | | | | |
4 | ++ | ++ | +0- | ++0 | +--+ | | | | | | | | |
4 | ++ | +0- | ++0 | +--+ | | | | | | | | |
5 | +-- | +-- | +0+ | +--0 | +-+- | +0-+ | | | | | | | |
5 | +-- | +0+ | +--0 | +-+- | +0-+ | | | | | | | |
6 | +-0 | +-0 | ++0 | +-00 | +0-0 | +0+0 | ++00 | | | | | | |
6 | +-0 | ++0 | +-00 | +0-0 | +0+0 | ++00 | | | | | | |
7 | +-+ | +-+ | +--- | +-+0 | +00+ | ++0- | +---0 | +--++ | | | | | |
7 | +-+ | +--- | +-+0 | +00+ | ++0- | +---0 | +--++ | | | | | |
8 | +0- | +0- | +--+ | +0-0 | ++-- | ++++ | +--+0 | +-0+- | +-+0+ | | | | |
8 | +0- | +--+ | +0-0 | ++-- | ++++ | +--+0 | +-0+- | +-+0+ | | | | |
9 | +00 | +00 | +-00 | +000 | ++00 | +--00 | +-000 | +-+00 | +0-00 | +0000 | | | |
9 | +00 | +-00 | +000 | ++00 | +--00 | +-000 | +-+00 | +0-00 | +0000 | | | |
A | +0+ | +0+ | +-+- | +0+0 | ++++ | +-0-- | +-+-0 | +0--+ | +000- | +0+00 | ++-0+ | | |
A | +0+ | +-+- | +0+0 | ++++ | +-0-- | +-+-0 | +0--+ | +000- | +0+00 | ++-0+ | | |
B | ++- | ++- | +-++ | ++-0 | +--0- | +-00+ | +-++0 | +00-- | +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 |
C | ++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 |
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 |
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 |
F | +--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 |
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 |
H | +-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 |
I | +-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 |
J | +-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 |
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 |
L | +-+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 |
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 |
N | +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 |
O | +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 |
P | +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 |
Q | +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 |
10| +000 | +-000 | +0000 | ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |
</pre>

=={{header|Wren}}==
{{trans|Phix}}
{{libheader|Wren-str}}
{{libheader|Wren-iterate}}
{{libheader|Wren-fmt}}
Translated via the Go entry.
<syntaxhighlight lang="wren">import "./str" for Str
import "./iterate" for Stepped
import "./fmt" for Fmt

var maxdp = 81
var binary = "01"
var ternary = "012"
var balancedTernary = "-0+"
var decimal = "0123456789"
var hexadecimal = "0123456789ABCDEF"
var septemVigesimal = "0123456789ABCDEFGHIJKLMNOPQ"
var balancedBase27 = "ZYXWVUTSRQPON0ABCDEFGHIJKLM"
var base37 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// converts Phix indices to Wren
var wIndex = Fn.new { |pIndex, le|
if (pIndex < 0) return pIndex + le
return pIndex - 1
}

var getCarry = Fn.new { |digit, base|
if (digit > base) {
return 1
} else if (digit < 1) {
return -1
}
return 0
}

// convert string 'b' to a decimal floating point number
var b2dec = Fn.new { |b, alphabet|
var res = 0
var base = alphabet.count
var zdx = alphabet.indexOf("0") + 1
var signed = zdx == 1 && b[0] == "-"
if (signed) b = b[1..-1]
var le = b.count
var ndp = b.indexOf(".") + 1
if (ndp != 0) {
b = Str.delete(b, ndp - 1) // remove decimal point
ndp = le - ndp
}
for (i in Stepped.ascend(1..b.count)) {
var idx = alphabet.indexOf(b[i-1]) + 1
res = base * res + idx - zdx
}
if (ndp != 0) res = res / base.pow(ndp)
if (signed) res = -res
return res
}

// string 'b' can be balanced or unbalanced
var negate = Fn.new { |b, alphabet|
if (alphabet[0] == "0") {
if (b != "0") b = (b[0] == "-") ? b[1..-1] : Str.insert(b, 0, "-")
} else {
for (i in Stepped.ascend(1..b.count)) {
if (b[i-1] != ".") {
var idx = alphabet.indexOf(b[i-1]) + 1
var wi = wIndex.call(-idx, alphabet.count)
b = Str.change(b, i-1, alphabet[wi])
}
}
}
return b
}

var bTrim = Fn.new { |b|
// trim trailing ".000"
var idx = b.indexOf(".") + 1
if (idx != 0) b = b.trimEnd("0").trimEnd(".")
// trim leading zeros but not "0.nnn"
while (b.count > 1 && b[0] == "0" && b[1] != ".") b = b[1..-1]
return b
}

// for balanced number systems only
var bCarry = Fn.new { |digit, base, idx, n, alphabet|
var carry = getCarry.call(digit, base)
if (carry != 0) {
for (i in Stepped.descend(idx..1)) {
if (n[i-1] != ".") {
var k = alphabet.indexOf(n[i-1]) + 1
if (k < base) {
n = Str.change(n, i-1, alphabet[k])
break
}
n = Str.change(n, i-1, alphabet[0])
}
}
digit = digit - base * carry
}
return [digit, n]
}

// convert a string from alphabet to alphabet2
var b2b // recursive function
b2b = Fn.new { |n, alphabet, alphabet2|
var res = "0"
var m = ""
if (n != "0") {
var base = alphabet.count
var base2 = alphabet2.count
var zdx = alphabet.indexOf("0") + 1
var zdx2 = alphabet2.indexOf("0") + 1
var carry = 0
var q = 0
var r = 0
var digit = 0
var idx = alphabet.indexOf(n[0]) + 1
var negative = (zdx == 1 && n[0] == "-") || (zdx != 1 && idx < zdx)
if (negative) n = negate.call(n, alphabet)
var ndp = n.indexOf(".") + 1
if (ndp != 0) {
var t = n
n = n[0...ndp-1]
m = t[ndp..-1]
}
res = ""
while (n.count > 0) {
q = 0
for (i in Stepped.ascend(1..n.count)) {
digit = alphabet.indexOf(n[i-1]) + 1 - zdx
q = q*base + digit
r = q.abs % base2
digit = (q.abs/base2).floor + zdx
if (q < 0) digit = digit - 1
if (zdx != 1) {
var p = bCarry.call(digit, base, i-1, n, alphabet)
digit = p[0]
n = p[1]
}
n = Str.change(n, i-1, alphabet[digit-1])
q = r
}
r = r + zdx2
if (zdx2 != 1) {
r = r + carry
carry = getCarry.call(r, base2)
r = r - base2 * carry
}
res = Str.insert(res, 0, alphabet2[r-1])
n = n.trimStart("0")
}
if (carry != 0) res = Str.insert(res, 0, alphabet2[carry+zdx2-1])
if (m.count > 0) {
res = res + "."
ndp = 0
if (zdx != 1) {
var lm = m.count
var alphaNew = base37[0...alphabet.count]
m = b2b.call(m, alphabet, alphaNew)
m = ("0" * (lm-m.count)) + m
alphabet = alphaNew
zdx = 1
}
while (m.count > 0 && ndp < maxdp) {
q = 0
for (i in Stepped.descend(m.count..1)) {
digit = alphabet.indexOf(m[i-1]) + 1 - zdx
q = q + digit * base2
r = q.abs % base + zdx
q = (q / base).truncate
if (q < 0) q = q - 1
m = Str.change(m, i-1, alphabet[r-1])
}
digit = q + zdx2
if (zdx2 != 1) {
var p = bCarry.call(digit, base2, res.count, res, alphabet2)
digit = p[0]
res = p[1]
}
res = res + alphabet2[digit-1]
m = m.trimEnd("0")
ndp = ndp + 1
}
}
res = bTrim.call(res)
if (negative) res = negate.call(res, alphabet2)
}
return res
}

// convert 'd' to a string in the specified base
var float2b = Fn.new { |d, alphabet|
var base = alphabet.count
var zdx = alphabet.indexOf("0") + 1
var carry = 0
var neg = d < 0
if (neg) d = -d
var res = ""
var whole = d.floor
d = d - whole
while (true) {
var ch = whole % base + zdx
if (zdx != 1) {
ch = ch + carry
carry = getCarry.call(ch, base)
ch = ch - base * carry
}
res = Str.insert(res, 0, alphabet[ch-1])
whole = (whole / base).truncate
if (whole == 0) break
}
if (carry != 0) {
res = Str.insert(res, 0, alphabet[carry+zdx-1])
carry = 0
}
if (d != 0) {
res = res + "."
var ndp = 0
while (d != 0 && ndp < maxdp) {
d = d * base
var digit = d.truncate + zdx
d = d - digit
if (zdx != 1) {
var p = bCarry.call(digit, base, res.count, res, alphabet)
digit = p[0]
res = p[1]
}
res = res + alphabet[digit-1]
ndp = ndp + 1
}
}
if (neg) res = negate.call(res, alphabet)
return res
}

var bSub // forwward declaration

var bAdd = Fn.new { |a, b, alphabet|
var base = alphabet.count
var zdx = alphabet.indexOf("0") + 1
var carry = 0
var da = 0
var db = 0
var digit = 0
if (zdx == 1) {
if (a[0] == "-") {
return bSub.call(b, negate.call(a, alphabet), alphabet)
}
if (b[0] == "-") {
return bSub.call(a, negate.call(b, alphabet), alphabet)
}
}
var adt = a.indexOf(".") + 1
var bdt = b.indexOf(".") + 1
if (adt != 0 || bdt != 0) {
if (adt != 0) {
adt = a.count - adt + 1
var wi = wIndex.call(-adt, a.count)
a = Str.delete(a, wi)
}
if (bdt != 0) {
bdt = b.count - bdt + 1
var wi = wIndex.call(-bdt, b.count)
b = Str.delete(b, wi)
}
if (bdt > adt) {
a = a + ("0" * (bdt-adt))
adt = bdt
} else if (adt > bdt) {
b = b + ("0" * (adt-bdt))
}
}
if (a.count < b.count) {
var t = a
a = b
b = t
}
for (i in Stepped.descend(-1..-a.count)) {
if (i < -a.count) {
da = 0
} else {
da = alphabet.indexOf(a[a.count + i]) + 1 - zdx
}
if (i < -b.count) {
db = 0
} else {
db = alphabet.indexOf(b[b.count + i]) + 1 - zdx
}
digit = da + db + carry + zdx
carry = getCarry.call(digit, base)
a = Str.change(a, i + a.count, alphabet[digit-carry*base-1])
if (i < -b.count && carry == 0) break
}
if (carry != 0) {
a = Str.insert(a, 0, alphabet[carry+zdx-1])
}
if (adt != 0) {
var wi = wIndex.call(-adt+1, a.count)
a = Str.insert(a, wi, ".")
}
a = bTrim.call(a)
return a
}

var aSmaller = Fn.new { |a, b, alphabet|
if (a.count != b.count) Fiber.abort("strings should be equal in length")
for (i in Stepped.ascend(1..a.count)) {
var da = alphabet.indexOf(a[i-1]) + 1
var db = alphabet.indexof(b[i-1]) + 1
if (da != db) return da < db
}
return false
}

// declared earlier
bSub = Fn.new { |a, b, alphabet|
var base = alphabet.count
var zdx = alphabet.indexOf("0") + 1
var carry = 0
var da = 0
var db = 0
var digit = 0
if (zdx == 1) {
if (a[0] == "-") {
return negate.call(bAdd.call(negate.call(a, alphabet), b, alphabet), alphabet)
}
if (b[0] == "-") {
return bAdd.call(a, negate.call(b, alphabet), alphabet)
}
}
var adt = a.indexOf(".") + 1
var bdt = b.indexOf(".") + 1
if (adt != 0 || bdt != 0) {
if (adt != 0) {
adt = a.count - adt + 1
var wi = wIndex.call(-adt, a.count)
a = Str.delete(a, wi)
}
if (bdt != 0) {
bdt = b.count - bdt + 1
var wi = wIndex.call(-bdt, b.count)
b = Str.delete(b, wi)
}
if (bdt > adt) {
a = a + ("0" * (bdt-adt))
adt = bdt
} else if (adt > bdt) {
b = b + ("0" * (adt-bdt))
}
}
var bNegate = false
if (a.count < b.count || (a.count == b.count && aSmaller.call(a, b, alphabet))) {
bNegate = true
var t = a
a = b
b = t
}
for (i in Stepped.descend(-1..-a.count)) {
if (i < -a.count) {
da = 0
} else {
da = alphabet.indexOf(a[a.count+i]) + 1 - zdx
}
if (i < -b.count) {
db = 0
} else {
db = alphabet.indexOf(b[b.count+i]) + 1 - zdx
}
digit = da - db - carry + zdx
carry = 0
if (digit <= 0) carry = 1
a = Str.change(a, i+a.count, alphabet[digit+carry*base-1])
if (i < -b.count && carry == 0) break
}
if (carry != 0) Fiber.abort("carry should be zero")
if (adt != 0) {
var wi = wIndex.call(-adt+1, a.count)
a = Str.insert(a, wi, ".")
}
a = bTrim.call(a)
if (bNegate) a = negate.call(a, alphabet)
return a
}

var bMul = Fn.new { |a, b, alphabet|
var zdx = alphabet.indexOf("0") + 1
var dpa = a.indexOf(".") + 1
var dpb = b.indexOf(".") + 1
var ndp = 0
if (dpa != 0) {
ndp = ndp + a.count - dpa
a = Str.delete(a, dpa-1)
}
if (dpb != 0) {
ndp = ndp + b.count - dpb
b = Str.delete(b, dpb-1)
}
var pos = a
var res = "0"
if (zdx != 1) {
// balanced number systems
var neg = negate.call(pos, alphabet)
for (i in Stepped.descend(b.count..1)) {
var m = alphabet.indexOf(b[i-1]) + 1 - zdx
while (m != 0) {
var temp = pos
var temp2 = -1
if (m < 0) {
temp = neg
temp2 = 1
}
res = bAdd.call(res, temp, alphabet)
m = m + temp2
}
pos = pos + "0"
neg = neg + "0"
}
} else {
// non-balanced number systems
var negative = false
if (a[0] == "-") {
a = a[1..-1]
negative = true
}
if (b[0] == "-") {
b = b[1..-1]
negative = !negative
}
for (i in Stepped.descend(b.count..1)) {
var m = alphabet.indexOf(b[i-1]) + 1 - zdx
while (m > 0) {
res = bAdd.call(res, pos, alphabet)
m = m - 1
}
pos = pos + "0"
}
if (negative) res = negate.call(res, alphabet)
}
if (ndp != 0) {
var wi = wIndex.call(-ndp, res.count)
res = Str.insert(res, wi, ".")
}
res = bTrim.call(res)
return res
}

var multTable = Fn.new {
System.print("multiplication table")
System.print("====================")
System.write("* |")
for (j in 1..12) {
Fmt.write(" #$s $3s |", float2b.call(j, hexadecimal), float2b.call(j, balancedTernary))
}
for (i in 1..27) {
var a = float2b.call(i, balancedTernary)
Fmt.write("\n$-2s|", float2b.call(i, septemVigesimal))
for (j in 1..12) {
if (j > i) {
System.write(" |")
} else {
var b = float2b.call(j, balancedTernary)
var m = bMul.call(a, b, balancedTernary)
Fmt.write(" $6s |", m)
}
}
}
System.print()
}

var test = Fn.new {|name, alphabet|
var a = b2b.call("+-0++0+.+-0++0+", balancedTernary, alphabet)
var b = b2b.call("-436.436", decimal, alphabet)
var c = b2b.call("+-++-.+-++-", balancedTernary, alphabet)
var d = bSub.call(b, c, alphabet)
var r = bMul.call(a, d, alphabet)
Fmt.print("$s\n$s", name, "=" * name.count)
Fmt.print(" a = $.14f $s", b2dec.call(a, alphabet), a)
Fmt.print(" b = $.14f $s", b2dec.call(b, alphabet), b)
Fmt.print(" c = $.14f $s", b2dec.call(c, alphabet), c)
Fmt.print("a*(b-c) = $.14f $s\n", b2dec.call(r, alphabet), r)
}

test.call("balanced ternary", balancedTernary)
test.call("balanced base 27", balancedBase27)
test.call("decimal", decimal)
test.call("binary", binary)
test.call("ternary", ternary)
test.call("hexadecimal", hexadecimal)
test.call("septemvigesimal", septemVigesimal)
multTable.call()</syntaxhighlight>

{{out}}
<pre>
balanced ternary
================
a = 523.23914037494285 +-0++0+.+-0++0+
b = -436.43599999999992 -++-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.90267998125637 ----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.23914037494285 AUJ.FLI
b = -436.43600000000004 NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
c = 65.26748971193416 BK.GF
a*(b-c) = -262510.90267998125637 ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO

decimal
=======
a = 523.23914037494296 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
b = -436.43599999999998 -436.436
c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b-c) = -262510.90267998137278 -262510.90267998140903693918986303277315826215892262734715612833785876513103053772667101895163734826631742752252837097627017862754285047634638652268078676654605120794218

binary
======
a = 523.23914037494274 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111
b = -436.43600000000004 -110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001
c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101
a*(b-c) = -262510.90267998143099 -1000000000101101110.111001110001011000001001000001101110011111011100000100000100001000101011100011110010110001010100110111001011101001010000001110110100111110001101000000001111110101

ternary
=======
a = 523.23914037494285 201101.0201101
b = -436.43600000000021 -121011.102202211210021110012111201022222000202102010100101200200110122011122101110212
c = 65.26748971193416 2102.02102
a*(b-c) = -262510.90267998125637 -111100002121.2201010011100110022102110002120222120100001221111011202022012121122001201122110221112

hexadecimal
===========
a = 523.23914037494274 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62
b = -436.43599999999998 -1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2
c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905
a*(b-c) = -262510.90267998143099 -4016E.E7160906E7DC10422DA508321819F4A637E5AEE668ED5163B12FCB17A732442F589975B7F24112B2E8F6E95EAD45803915EE26D20DF323D67CAEEC75D7BED68AA34E02F2B492257D66F028545FB398F60E

septemvigesimal
===============
a = 523.23914037494285 JA.6C9
b = -436.43600000000004 -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
c = 65.26748971193416 2B.76
a*(b-c) = -262510.90267998125637 -D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82

multiplication table
====================
* | #1 + | #2 +- | #3 +0 | #4 ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 | + | | | | | | | | | | | |
2 | +- | ++ | | | | | | | | | | |
3 | +0 | +-0 | +00 | | | | | | | | | |
4 | ++ | +0- | ++0 | +--+ | | | | | | | | |
5 | +-- | +0+ | +--0 | +-+- | +0-+ | | | | | | | |
6 | +-0 | ++0 | +-00 | +0-0 | +0+0 | ++00 | | | | | | |
7 | +-+ | +--- | +-+0 | +00+ | ++0- | +---0 | +--++ | | | | | |
8 | +0- | +--+ | +0-0 | ++-- | ++++ | +--+0 | +-0+- | +-+0+ | | | | |
9 | +00 | +-00 | +000 | ++00 | +--00 | +-000 | +-+00 | +0-00 | +0000 | | | |
A | +0+ | +-+- | +0+0 | ++++ | +-0-- | +-+-0 | +0--+ | +000- | +0+00 | ++-0+ | | |
B | ++- | +-++ | ++-0 | +--0- | +-00+ | +-++0 | +00-- | +0+-+ | ++-00 | ++0+- | +++++ | |
C | ++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 | +--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--- | +00++ | ++-+0 | ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 |
I | +-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+00 | +-+00+ | +0--+- | +0-++0 |
K | +-+- | ++++ | +-+-0 | +000- | ++-0+ | ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 |
L | +-+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 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 |
O | +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-+00 | +00+-+ | +0++-- | ++-0+0 |
Q | +00- | +-0-+ | +00-0 | ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 |
10| +000 | +-000 | +0000 | ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |
</pre>
</pre>



Latest revision as of 14:01, 7 December 2023

Generalised floating point multiplication is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Use the Generalised floating point addition template to implement generalised floating point multiplication for a Balanced ternary test case.

Test case details: Balanced ternary is a way of representing numbers. Unlike the prevailing binary representation, a balanced ternary "real" is in base 3, and each digit can have the values 1, 0, or −1. For example, decimal 11 = 32 + 31 − 30, thus can be written as "++−", while 6 = 32 − 31 + 0 × 30, i.e., "+−0" and for an actual real number 6⅓ the exact representation is 32 − 31 + 0 × 30 + 1 × 3-1 i.e., "+−0.+"

For this task, implement balanced ternary representation of real numbers with the following:

Requirements

  1. Support arbitrary precision real numbers, both positive and negative;
  2. Provide ways to convert to and from text strings, using digits '+', '-' and '0' (unless you are already using strings to represent balanced ternary; but see requirement 5).
  3. Provide ways to convert to and from native integer and real type (unless, improbably, your platform's native integer type is balanced ternary). If your native integers can't support arbitrary length, overflows during conversion must be indicated.
  4. Provide ways to perform addition, negation and multiplication directly on balanced ternary integers; do not convert to native integers first.
  5. Make your implementation efficient, with a reasonable definition of "efficient" (and with a reasonable definition of "reasonable").
  6. The Template should successfully handle these multiplications in other bases. In particular Septemvigesimal and "Balanced base-27".

Optionally:

  • For faster long multiplication use Karatsuba algorithm.
  • Using the Karatsuba algorithm, spread the computation across multiple CPUs.

Test case 1 - With balanced ternaries a from string "+-0++0+.+-0++0+", b from native real -436.436, c "+-++-.+-++-":

  • write out a, b and c in decimal notation.
  • calculate a × (bc), write out the result in both ternary and decimal notations.
  • In the above limit the precision to 81 ternary digits after the point.

Test case 2 - Generate a multiplication table of balanced ternaries where the rows of the table are for a 1st factor of 1 to 27, and the column of the table are for the second factor of 1 to 12.

Implement the code in a generalised form (such as a Template, Module or Mixin etc) that permits reusing of the code for different Bases.

If it is not possible to implement code in syntax of the specific language then:

  • note the reason.
  • perform the test case using a built-in or external library.

ALGOL 68

Works with: ALGOL 68 version Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.
Works with: ALGOL 68G version Any - tested with release algol68g-2.3.3.

File: Template.Big_float.Multiplication.a68

##########################################
#               TASK CODE                #
# Actual generic mulitplication operator #
##########################################
# Alternatively use http://en.wikipedia.org/wiki/Karatsuba_algorithm #

OP * = (DIGITS a, b)DIGITS: (
  DIGITS minus one = -IDENTITY LOC DIGITS,
         zero = ZERO LOC DIGITS,
         one = IDENTITY LOC DIGITS;
  INT order = digit order OF arithmetic;
  IF SIGN a = 0 OR SIGN b = 0 THEN zero
CO # Note: The following require the inequality operators #
  ELIF a = one THEN b
  ELIF b = one THEN a
  ELIF a = minus one THEN -b
  ELIF b = minus one THEN -a
END CO
  ELSE
    DIGIT zero = ZERO LOC DIGIT;
    DIGIT one =  IDENTITY LOC DIGIT;
    [order + MSD a+MSD b: LSD a+LSD b]DIGIT a x b;

    FOR place FROM LSD a+LSD b BY order TO LSD a+MSD b DO
      a x b[place] := zero # pad the MSDs of the result with Zero #
    OD;
    FOR place a FROM LSD a BY order TO MSD a DO
      DIGIT digit a = a[place a];
      DIGIT carry := zero;
      FOR place b FROM LSD b BY order TO MSD b DO
        DIGIT digit b = b[place b];
        REF DIGIT digit ab = a x b[place a + place b];
        IF carry OF arithmetic THEN # used for big number arithmetic #
          MOID(carry := ( digit ab +:= carry ));
          DIGIT prod := digit a;
          MOID(carry +:= ( prod *:= digit b ));
          MOID(carry +:= ( digit ab +:= prod ))
        ELSE # carry = 0 so we can just ignore the carry #
          DIGIT prod := digit a;
          MOID(prod *:= digit b);
          MOID(digit ab +:= prod)
        FI
      OD;
      a x b[place a + MSD b + order] := carry
    OD;
    INITDIGITS a x b # normalise #
  FI
);

######################################
#  Define the hybrid multiplication  #
# operators for the generalised base #
######################################

OP * = (DIGIT a, DIGITS b)DIGITS: INITDIGITS a * b;
OP * = (DIGITS a, DIGIT b)DIGITS: a * INITDIGITS b;

OP *:= = (REF DIGITS lhs, DIGIT arg)DIGITS: lhs := lhs * INITDIGITS arg;

File: Template.Balanced_ternary_float.Base.a68

PR READ "Template.Big_float_BCD.Base.a68" PR # [[rc:Generalised floating point addition]] #

################################################################
# First: define the attributes of the arithmetic we are using. #
################################################################
arithmetic := (
  # balanced = # TRUE, 
  # carry = # TRUE, 
  # base = # 3, # width = # 1, # places = # 81, # order = # -1, 
  # repr = # USTRING("-","0","+")[@-1]
);

OP INITDIGIT = (CHAR c)DIGIT: (
  DIGIT out;
  digit OF out :=
    IF   c = "+" THEN +1
    ELIF c = "0" THEN  0
    ELIF c = "-" THEN -1
    ELSE raise value error("Unknown digit :"""+c+""""); SKIP
    FI;
  out
);

OP INITBIGREAL = (STRING s)BIGREAL: (
  BIGREAL out;
  BIGREAL base of arithmetic = INITBIGREAL base OF arithmetic; # Todo: Opt #
  INT point := UPB s; # put the point on the extreme right #
  FOR place FROM LWB s TO UPB s DO
    IF s[place]="." THEN
      point := place
    ELSE
      out := out SHR digit order OF arithmetic + INITDIGIT s[place]
    FI
  OD;
  out SHR (UPB s-point)
);

File: test.Balanced_ternary_float.Multiplication.a68

#!/usr/local/bin/a68g --script #
####################################################################
# A program to test arbitrary length floating point multiplication #
####################################################################

PR READ "prelude/general.a68" PR  # [[rc:Template:ALGOL 68/prelude]] #

PR READ "Template.Big_float.Multiplication.a68" PR

# include the basic axioms of the digits being used #
PR READ "Template.Balanced_ternary_float.Base.a68" PR

PR READ "Template.Big_float.Addition.a68" PR # [[rc:Generalised floating point addition]] #
PR READ "Template.Big_float.Subtraction.a68" PR # [[rc:Generalised floating point addition]] #

test1:( # Basic arithmetic #
  INT rw = long real width;
  BIGREAL a = INITBIGREAL "+-0++0+.+-0++0+", # 523.239... #
          b = INITBIGREAL - LONG 436.436,
          c = INITBIGREAL "+-++-.+-++-"; # 65.267... #
  printf(($g 9k g(rw,rw-5)39kgl$,
    "a =",INITLONGREAL a, REPR a,
    "b =",INITLONGREAL b, REPR b,
    "c =",INITLONGREAL c, REPR c,
    "a*(b-c)",INITLONGREAL(a*(b-c)), REPR(a*(b-c)),
  $l$))
);

test2:( # A floating point Ternary multiplication table #
  FORMAT s = $"|"$; # field seperator #

  INT lwb = 1, tab = 8, upb = 12;

  printf($"# "f(s)" *   "f(s)$);
  FOR j FROM lwb TO upb DO
    FORMAT col = $n(tab)k f(s)$;
    printf(($g" #"g(0)f(col)$, REPR INITBIGREAL j,j))
  OD;
  printf($l$);
  FOR i FROM lwb TO 27 DO
    printf(($g(0) 3k f(s) g 9k f(s)$,i,REPR INITBIGREAL i));
    FOR j FROM lwb TO i MIN upb DO
      FORMAT col = $n(tab)k f(s)$;
      BIGREAL product = INITBIGREAL i * INITBIGREAL j;
      printf(($gf(col)$, REPR product))
    OD;
    IF upb > i THEN printf($n(upb-i)(n(tab-1)x f(s))$) FI;
    printf($l$)
  OD
)

Output:

a =     +523.23914037494284407864655  +-0++0+.+-0++0+
b =     -436.43600000000000000000000  -++-0--.--0+-00+++-0-+---0-+0++++0--0000+00-+-+--+0-0-00--++0-+00---+0+-+++0+-0----0++
c =      +65.26748971193415637860082  +-++-.+-++-
a*(b-c) -262510.90267998140903693919  ----000-0+0+.0+0-0-00---00--0-0+--+--00-0++-000++0-000-+0+-----+++-+-0+-+0+0++0+0-++-++0+---00++++

# | *   |+ #1   |+- #2  |+0 #3  |++ #4  |+-- #5 |+-0 #6 |+-+ #7 |+0- #8 |+e+- #9|+0+ #10|++- #11|++0 #12|
1 |+    |+      |       |       |       |       |       |       |       |       |       |       |       |
2 |+-   |+-     |++     |       |       |       |       |       |       |       |       |       |       |
3 |+0   |+0     |+-0    |+e+-   |       |       |       |       |       |       |       |       |       |
4 |++   |++     |+0-    |++0    |+--+   |       |       |       |       |       |       |       |       |
5 |+--  |+--    |+0+    |+--0   |+-+-   |+0-+   |       |       |       |       |       |       |       |
6 |+-0  |+-0    |++0    |+-e+-  |+0-0   |+0+0   |++e+-  |       |       |       |       |       |       |
7 |+-+  |+-+    |+---   |+-+0   |+00+   |++0-   |+---0  |+--++  |       |       |       |       |       |
8 |+0-  |+0-    |+--+   |+0-0   |++--   |++++   |+--+0  |+-0+-  |+-+0+  |       |       |       |       |
9 |+e+- |+e+-   |+-e+-  |+e+0   |++e+-  |+--e+- |+-e+0  |+-+e+- |+0-e+- |+e++   |       |       |       |
10|+0+  |+0+    |+-+-   |+0+0   |++++   |+-0--  |+-+-0  |+0--+  |+000-  |+0+e+- |++-0+  |       |       |
11|++-  |++-    |+-++   |++-0   |+--0-  |+-00+  |+-++0  |+00--  |+0+-+  |++-e+- |++0+-  |+++++  |       |
12|++0  |++0    |+0-0   |++e+-  |+--+0  |+-+-0  |+0-e+- |+00+0  |++--0  |++e+0  |++++0  |+--0-0 |+--+e+-|
13|+++  |+++    |+00-   |+++0   |+-0-+  |+-++-  |+00-0  |+0+0+  |++0--  |+++e+- |+---++ |+--+0- |+-0-+0 |
14|+--- |+---   |+00+   |+---0  |+-0+-  |+0--+  |+00+0  |++-0-  |++0++  |+---e+-|+--+-- |+-0-0+ |+-0+-0 |
15|+--0 |+--0   |+0+0   |+--e+- |+-+-0  |+0-+0  |+0+e+- |++0-0  |++++0  |+--e+0 |+-0--0 |+-00+0 |+-+-e+-|
16|+--+ |+--+   |++--   |+--+0  |+-+0+  |+000-  |++--0  |++0++  |+---+- |+--+e+-|+-00-+ |+-+--- |+-+0+0 |
17|+-0- |+-0-   |++-+   |+-0-0  |+0---  |+00++  |++-+0  |++++-  |+--00+ |+-0-e+-|+-0+0- |+-+0-+ |+0---0 |
18|+-e+-|+-e+-  |++e+-  |+-e+0  |+0-e+- |+0+e+- |++e+0  |+---e+-|+--+e+-|+-e++  |+-+-e+-|+-++e+-|+0-e+0 |
19|+-0+ |+-0+   |+++-   |+-0+0  |+0-++  |++---  |+++-0  |+--0-+ |+-0-0- |+-0+e+-|+-+00+ |+0--+- |+0-++0 |
20|+-+- |+-+-   |++++   |+-+-0  |+000-  |++-0+  |++++0  |+--+-- |+-00-+ |+-+-e+-|+-+++- |+0-0++ |+000-0 |
21|+-+0 |+-+0   |+---0  |+-+e+- |+00+0  |++0-0  |+---e+-|+--++0 |+-0+-0 |+-+e+0 |+0--+0 |+00--0 |+00+e+-|
22|+-++ |+-++   |+--0-  |+-++0  |+0+-+  |++0+-  |+--0-0 |+-0-0+ |+-+--- |+-++e+-|+0-0++ |+0000- |+0+-+0 |
23|+0-- |+0--   |+--0+  |+0--0  |+0++-  |+++-+  |+--0+0 |+-000- |+-+-++ |+0--e+-|+00--- |+00+0+ |+0++-0 |
24|+0-0 |+0-0   |+--+0  |+0-e+- |++--0  |++++0  |+--+e+-|+-0+-0 |+-+0+0 |+0-e+0 |+000-0 |+0+-+0 |++--e+-|
25|+0-+ |+0-+   |+-0--  |+0-+0  |++-0+  |+---0- |+-0--0 |+-0+++ |+-+++- |+0-+e+-|+00+-+ |+0++-- |++-0+0 |
26|+00- |+00-   |+-0-+  |+00-0  |++0--  |+---++ |+-0-+0 |+-+-+- |+0--0+ |+00-e+-|+0+-0- |++---+ |++0--0 |
27|+e+0 |+e+0   |+-e+0  |+e++   |++e+0  |+--e+0 |+-e++  |+-+e+0 |+0-e+0 |+e+--  |+0+e+0 |++-e+0 |++e++  |

Go

Translation of: Phix

In the interests of brevity many of the comments and all of the commented-out code has been omitted.

package main

import (
    "fmt"
    "log"
    "math"
    "strings"
)

const (
    maxdp           = 81
    binary          = "01"
    ternary         = "012"
    balancedTernary = "-0+"
    decimal         = "0123456789"
    hexadecimal     = "0123456789ABCDEF"
    septemVigesimal = "0123456789ABCDEFGHIJKLMNOPQ"
    balancedBase27  = "ZYXWVUTSRQPON0ABCDEFGHIJKLM"
    base37          = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

/* helper functions */

func changeByte(s string, idx int, c byte) string {
    bytes := []byte(s)
    bytes[idx] = c
    return string(bytes)
}

func removeByte(s string, idx int) string {
    le := len(s)
    bytes := []byte(s)
    copy(bytes[idx:], bytes[idx+1:])
    return string(bytes[0 : le-1])
}

func insertByte(s string, idx int, c byte) string {
    le := len(s)
    t := make([]byte, le+1)
    copy(t, s)
    copy(t[idx+1:], t[idx:])
    t[idx] = c
    return string(t)
}

func prependByte(s string, c byte) string {
    le := len(s)
    bytes := make([]byte, le+1)
    copy(bytes[1:], s)
    bytes[0] = c
    return string(bytes)
}

func abs(i int) int {
    if i < 0 {
        return -i
    }
    return i
}

// converts Phix indices to Go
func gIndex(pIndex, le int) int {
    if pIndex < 0 {
        return pIndex + le
    }
    return pIndex - 1
}

func getCarry(digit, base int) int {
    if digit > base {
        return 1
    } else if digit < 1 {
        return -1
    }
    return 0
}

// convert string 'b' to a decimal floating point number
func b2dec(b, alphabet string) float64 {
    res := 0.0
    base := len(alphabet)
    zdx := strings.IndexByte(alphabet, '0') + 1
    signed := zdx == 1 && b[0] == '-'
    if signed {
        b = b[1:]
    }
    le := len(b)
    ndp := strings.IndexByte(b, '.') + 1
    if ndp != 0 {
        b = removeByte(b, ndp-1) // remove decimal point
        ndp = le - ndp
    }
    for i := 1; i <= len(b); i++ {
        idx := strings.IndexByte(alphabet, b[i-1]) + 1
        res = float64(base)*res + float64(idx) - float64(zdx)
    }
    if ndp != 0 {
        res /= math.Pow(float64(base), float64(ndp))
    }
    if signed {
        res = -res
    }
    return res
}

// string 'b' can be balanced or unbalanced
func negate(b, alphabet string) string {
    if alphabet[0] == '0' {
        if b != "0" {
            if b[0] == '-' {
                b = b[1:]
            } else {
                b = prependByte(b, '-')
            }
        }
    } else {
        for i := 1; i <= len(b); i++ {
            if b[i-1] != '.' {
                idx := strings.IndexByte(alphabet, b[i-1]) + 1
                gi := gIndex(-idx, len(alphabet))
                b = changeByte(b, i-1, alphabet[gi])
            }
        }
    }
    return b
}

func bTrim(b string) string {
    // trim  trailing ".000"
    idx := strings.IndexByte(b, '.') + 1
    if idx != 0 {
        b = strings.TrimRight(strings.TrimRight(b, "0"), ".")
    }
    // trim leading zeros but not "0.nnn"
    for len(b) > 1 && b[0] == '0' && b[1] != '.' {
        b = b[1:]
    }
    return b
}

// for balanced number systems only
func bCarry(digit, base, idx int, n, alphabet string) (int, string) {
    carry := getCarry(digit, base)
    if carry != 0 {
        for i := idx; i >= 1; i-- {
            if n[i-1] != '.' {
                k := strings.IndexByte(alphabet, n[i-1]) + 1
                if k < base {
                    n = changeByte(n, i-1, alphabet[k])
                    break
                }
                n = changeByte(n, i-1, alphabet[0])
            }
        }
        digit -= base * carry
    }
    return digit, n
}

// convert a string from alphabet to alphabet2
func b2b(n, alphabet, alphabet2 string) string {
    res, m := "0", ""
    if n != "0" {
        base := len(alphabet)
        base2 := len(alphabet2)
        zdx := strings.IndexByte(alphabet, '0') + 1
        zdx2 := strings.IndexByte(alphabet2, '0') + 1
        var carry, q, r, digit int
        idx := strings.IndexByte(alphabet, n[0]) + 1
        negative := (zdx == 1 && n[0] == '-') || (zdx != 1 && idx < zdx)
        if negative {
            n = negate(n, alphabet)
        }
        ndp := strings.IndexByte(n, '.') + 1
        if ndp != 0 {
            n, m = n[0:ndp-1], n[ndp:]
        }
        res = ""
        for len(n) > 0 {
            q = 0
            for i := 1; i <= len(n); i++ {
                digit = strings.IndexByte(alphabet, n[i-1]) + 1 - zdx
                q = q*base + digit
                r = abs(q) % base2
                digit = abs(q)/base2 + zdx
                if q < 0 {
                    digit--
                }
                if zdx != 1 {
                    digit, n = bCarry(digit, base, i-1, n, alphabet)
                }
                n = changeByte(n, i-1, alphabet[digit-1])
                q = r
            }
            r += zdx2
            if zdx2 != 1 {
                r += carry
                carry = getCarry(r, base2)
                r -= base2 * carry
            }
            res = prependByte(res, alphabet2[r-1])
            n = strings.TrimLeft(n, "0")
        }
        if carry != 0 {
            res = prependByte(res, alphabet2[carry+zdx2-1])
        }
        if len(m) > 0 {
            res += "."
            ndp = 0
            if zdx != 1 {
                lm := len(m)
                alphaNew := base37[0:len(alphabet)]
                m = b2b(m, alphabet, alphaNew)
                m = strings.Repeat("0", lm-len(m)) + m
                alphabet = alphaNew
                zdx = 1
            }
            for len(m) > 0 && ndp < maxdp {
                q = 0
                for i := len(m); i >= 1; i-- {
                    digit = strings.IndexByte(alphabet, m[i-1]) + 1 - zdx
                    q += digit * base2
                    r = abs(q)%base + zdx
                    q /= base
                    if q < 0 {
                        q--
                    }
                    m = changeByte(m, i-1, alphabet[r-1])
                }
                digit = q + zdx2
                if zdx2 != 1 {
                    digit, res = bCarry(digit, base2, len(res), res, alphabet2)
                }
                res += string(alphabet2[digit-1])
                m = strings.TrimRight(m, "0")
                ndp++
            }
        }
        res = bTrim(res)
        if negative {
            res = negate(res, alphabet2)
        }
    }
    return res
}

// convert 'd' to a string in the specified base
func float2b(d float64, alphabet string) string {
    base := len(alphabet)
    zdx := strings.Index(alphabet, "0") + 1
    carry := 0
    neg := d < 0
    if neg {
        d = -d
    }
    res := ""
    whole := int(d)
    d -= float64(whole)
    for {
        ch := whole%base + zdx
        if zdx != 1 {
            ch += carry
            carry = getCarry(ch, base)
            ch -= base * carry
        }
        res = prependByte(res, alphabet[ch-1])
        whole /= base
        if whole == 0 {
            break
        }
    }
    if carry != 0 {
        res = prependByte(res, alphabet[carry+zdx-1])
        carry = 0
    }
    if d != 0 {
        res += "."
        ndp := 0
        for d != 0 && ndp < maxdp {
            d *= float64(base)
            digit := int(d) + zdx
            d -= float64(digit)
            if zdx != 1 {
                digit, res = bCarry(digit, base, len(res), res, alphabet)
            }
            res += string(alphabet[digit-1])
            ndp++
        }
    }
    if neg {
        res = negate(res, alphabet)
    }
    return res
}

func bAdd(a, b, alphabet string) string {
    base := len(alphabet)
    zdx := strings.IndexByte(alphabet, '0') + 1
    var carry, da, db, digit int
    if zdx == 1 {
        if a[0] == '-' {
            return bSub(b, negate(a, alphabet), alphabet)
        }
        if b[0] == '-' {
            return bSub(a, negate(b, alphabet), alphabet)
        }
    }
    adt := strings.IndexByte(a, '.') + 1
    bdt := strings.IndexByte(b, '.') + 1
    if adt != 0 || bdt != 0 {
        if adt != 0 {
            adt = len(a) - adt + 1
            gi := gIndex(-adt, len(a))
            a = removeByte(a, gi)
        }
        if bdt != 0 {
            bdt = len(b) - bdt + 1
            gi := gIndex(-bdt, len(b))
            b = removeByte(b, gi)
        }
        if bdt > adt {
            a += strings.Repeat("0", bdt-adt)
            adt = bdt
        } else if adt > bdt {
            b += strings.Repeat("0", adt-bdt)
        }
    }
    if len(a) < len(b) {
        a, b = b, a
    }
    for i := -1; i >= -len(a); i-- {
        if i < -len(a) {
            da = 0
        } else {
            da = strings.IndexByte(alphabet, a[len(a)+i]) + 1 - zdx
        }
        if i < -len(b) {
            db = 0
        } else {
            db = strings.IndexByte(alphabet, b[len(b)+i]) + 1 - zdx
        }
        digit = da + db + carry + zdx
        carry = getCarry(digit, base)
        a = changeByte(a, i+len(a), alphabet[digit-carry*base-1])
        if i < -len(b) && carry == 0 {
            break
        }
    }
    if carry != 0 {
        a = prependByte(a, alphabet[carry+zdx-1])
    }
    if adt != 0 {
        gi := gIndex(-adt+1, len(a))
        a = insertByte(a, gi, '.')
    }
    a = bTrim(a)
    return a
}

func aSmaller(a, b, alphabet string) bool {
    if len(a) != len(b) {
        log.Fatal("strings should be equal in length")
    }
    for i := 1; i <= len(a); i++ {
        da := strings.IndexByte(alphabet, a[i-1]) + 1
        db := strings.IndexByte(alphabet, b[i-1]) + 1
        if da != db {
            return da < db
        }
    }
    return false
}

func bSub(a, b, alphabet string) string {
    base := len(alphabet)
    zdx := strings.IndexByte(alphabet, '0') + 1
    var carry, da, db, digit int
    if zdx == 1 {
        if a[0] == '-' {
            return negate(bAdd(negate(a, alphabet), b, alphabet), alphabet)
        }
        if b[0] == '-' {
            return bAdd(a, negate(b, alphabet), alphabet)
        }
    }
    adt := strings.Index(a, ".") + 1
    bdt := strings.Index(b, ".") + 1
    if adt != 0 || bdt != 0 {
        if adt != 0 {
            adt = len(a) - adt + 1
            gi := gIndex(-adt, len(a))
            a = removeByte(a, gi)
        }
        if bdt != 0 {
            bdt = len(b) - bdt + 1
            gi := gIndex(-bdt, len(b))
            b = removeByte(b, gi)
        }
        if bdt > adt {
            a += strings.Repeat("0", bdt-adt)
            adt = bdt
        } else if adt > bdt {
            b += strings.Repeat("0", adt-bdt)
        }
    }
    bNegate := false
    if len(a) < len(b) || (len(a) == len(b) && aSmaller(a, b, alphabet)) {
        bNegate = true
        a, b = b, a
    }
    for i := -1; i >= -len(a); i-- {
        if i < -len(a) {
            da = 0
        } else {
            da = strings.IndexByte(alphabet, a[len(a)+i]) + 1 - zdx
        }
        if i < -len(b) {
            db = 0
        } else {
            db = strings.IndexByte(alphabet, b[len(b)+i]) + 1 - zdx
        }
        digit = da - db - carry + zdx
        carry = 0
        if digit <= 0 {
            carry = 1
        }
        a = changeByte(a, i+len(a), alphabet[digit+carry*base-1])
        if i < -len(b) && carry == 0 {
            break
        }
    }
    if carry != 0 {
        log.Fatal("carry should be zero")
    }
    if adt != 0 {
        gi := gIndex(-adt+1, len(a))
        a = insertByte(a, gi, '.')
    }
    a = bTrim(a)
    if bNegate {
        a = negate(a, alphabet)
    }
    return a
}

func bMul(a, b, alphabet string) string {
    zdx := strings.IndexByte(alphabet, '0') + 1
    dpa := strings.IndexByte(a, '.') + 1
    dpb := strings.IndexByte(b, '.') + 1
    ndp := 0
    if dpa != 0 {
        ndp += len(a) - dpa
        a = removeByte(a, dpa-1)
    }
    if dpb != 0 {
        ndp += len(b) - dpb
        b = removeByte(b, dpb-1)
    }
    pos, res := a, "0"
    if zdx != 1 {
        // balanced number systems
        neg := negate(pos, alphabet)
        for i := len(b); i >= 1; i-- {
            m := strings.IndexByte(alphabet, b[i-1]) + 1 - zdx
            for m != 0 {
                temp, temp2 := pos, -1
                if m < 0 {
                    temp = neg
                    temp2 = 1
                }
                res = bAdd(res, temp, alphabet)
                m += temp2
            }
            pos += "0"
            neg += "0"
        }
    } else {
        // non-balanced number systems
        negative := false
        if a[0] == '-' {
            a = a[1:]
            negative = true
        }
        if b[0] == '-' {
            b = b[1:]
            negative = !negative
        }
        for i := len(b); i >= 1; i-- {
            m := strings.IndexByte(alphabet, b[i-1]) + 1 - zdx
            for m > 0 {
                res = bAdd(res, pos, alphabet)
                m--
            }
            pos += "0"
        }
        if negative {
            res = negate(res, alphabet)
        }
    }
    if ndp != 0 {
        gi := gIndex(-ndp, len(res))
        res = insertByte(res, gi, '.')
    }
    res = bTrim(res)
    return res
}

func multTable() {
    fmt.Println("multiplication table")
    fmt.Println("====================")
    fmt.Printf("* |")
    for j := 1; j <= 12; j++ {
        fj := float64(j)
        fmt.Printf(" #%s %3s |", float2b(fj, hexadecimal), float2b(fj, balancedTernary))
    }
    for i := 1; i <= 27; i++ {
        fi := float64(i)
        a := float2b(fi, balancedTernary)
        fmt.Printf("\n%-2s|", float2b(fi, septemVigesimal))
        for j := 1; j <= 12; j++ {
            if j > i {
                fmt.Printf("        |")
            } else {
                fj := float64(j)
                b := float2b(fj, balancedTernary)
                m := bMul(a, b, balancedTernary)
                fmt.Printf(" %6s |", m)
            }
        }
    }
    fmt.Println()
}

func test(name, alphabet string) {
    a := b2b("+-0++0+.+-0++0+", balancedTernary, alphabet)
    b := b2b("-436.436", decimal, alphabet)
    c := b2b("+-++-.+-++-", balancedTernary, alphabet)
    d := bSub(b, c, alphabet)
    r := bMul(a, d, alphabet)
    fmt.Printf("%s\n%s\n", name, strings.Repeat("=", len(name)))
    fmt.Printf("      a = %.16g  %s\n", b2dec(a, alphabet), a)
    fmt.Printf("      b = %.16g  %s\n", b2dec(b, alphabet), b)
    fmt.Printf("      c = %.16g  %s\n", b2dec(c, alphabet), c)
    fmt.Printf("a*(b-c) = %.16g  %s\n\n", b2dec(r, alphabet), r)
}

func main() {
    test("balanced ternary", balancedTernary)
    test("balanced base 27", balancedBase27)
    test("decimal", decimal)
    test("binary", binary)
    test("ternary", ternary)
    test("hexadecimal", hexadecimal)
    test("septemvigesimal", septemVigesimal)
    multTable()
}
Output:
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.4359999999999  NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
      c = 65.26748971193416  BK.GF
a*(b-c) = -262510.9026799812  ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO

decimal
=======
      a = 523.2391403749428  523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
      b = -436.436  -436.436
      c = 65.26748971193413  65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b-c) = -262510.9026799813  -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.4360000000002  -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.4359999999999  -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
      c = 65.26748971193416  2B.76
a*(b-c) = -262510.9026799812  -D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82

multiplication table
====================
* | #1   + | #2  +- | #3  +0 | #4  ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 |      + |        |        |        |        |        |        |        |        |        |        |        |
2 |     +- |     ++ |        |        |        |        |        |        |        |        |        |        |
3 |     +0 |    +-0 |    +00 |        |        |        |        |        |        |        |        |        |
4 |     ++ |    +0- |    ++0 |   +--+ |        |        |        |        |        |        |        |        |
5 |    +-- |    +0+ |   +--0 |   +-+- |   +0-+ |        |        |        |        |        |        |        |
6 |    +-0 |    ++0 |   +-00 |   +0-0 |   +0+0 |   ++00 |        |        |        |        |        |        |
7 |    +-+ |   +--- |   +-+0 |   +00+ |   ++0- |  +---0 |  +--++ |        |        |        |        |        |
8 |    +0- |   +--+ |   +0-0 |   ++-- |   ++++ |  +--+0 |  +-0+- |  +-+0+ |        |        |        |        |
9 |    +00 |   +-00 |   +000 |   ++00 |  +--00 |  +-000 |  +-+00 |  +0-00 |  +0000 |        |        |        |
A |    +0+ |   +-+- |   +0+0 |   ++++ |  +-0-- |  +-+-0 |  +0--+ |  +000- |  +0+00 |  ++-0+ |        |        |
B |    ++- |   +-++ |   ++-0 |  +--0- |  +-00+ |  +-++0 |  +00-- |  +0+-+ |  ++-00 |  ++0+- |  +++++ |        |
C |    ++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 |  +--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--- |  +00++ |  ++-+0 |  ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 |
I |   +-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+00 | +-+00+ | +0--+- | +0-++0 |
K |   +-+- |   ++++ |  +-+-0 |  +000- |  ++-0+ |  ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 |
L |   +-+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 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 |
O |   +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-+00 | +00+-+ | +0++-- | ++-0+0 |
Q |   +00- |  +-0-+ |  +00-0 |  ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 |
10|   +000 |  +-000 |  +0000 |  ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |


Julia

using Formatting
import Base.BigInt, Base.BigFloat, Base.print, Base.+, Base.-, Base.*

abstract type BalancedBaseDigitArray end

mutable struct BalancedTernary <: BalancedBaseDigitArray
    dig::Vector{Int8}
    p::Int
    BalancedTernary(arr::Vector, i) = new(Int8.(arr), i)
end

const MAX_PRECISION = 81

function BalancedTernary(s::String)
    if (i = findfirst(x -> x == '.', s)) != nothing
        p = length(s) - i
        s = s[1:i-1] * s[i+1:end]
    else
        p = 0
    end
    b = BalancedTernary([c == '-' ? -1 : c == '0' ? 0 : 1 for c in s], p)  # 2
end

function BalancedTernary(n::Integer)                                                # 1, 3
    if n < 0
        return -BalancedTernary(-n)
    elseif n == 0
        return BalancedTernary([0], 0)
    else
        return canonicalize!(BalancedTernary(reverse(digits(n, base=3)), 0))
    end
end
BalancedTernary() = BalancedTernary(0)

function BalancedTernary(x::Real)                                             # 1, 3
    if x < 0
        return -BalancedTernary(-x)
    end
    arr = reverse(digits(BigInt(round(x * big"3.0"^MAX_PRECISION)), base=3))
    return canonicalize!(BalancedTernary(arr, MAX_PRECISION))
end

function String(b::BalancedTernary)                                           # 3
    canonicalize!(b)
    s = String([['-', '0', '+'][c + 2] for c in b.dig])
    if b.p > 0
        if b.p < length(s)
            s = s[1:end-b.p] * "." * s[end-b.p+1:end]
        elseif b.p == length(s)
            s = "0." * s
        else
            s = "0." * "0"^(b.p - length(s)) * s
        end
    end
    return s
end

function BigInt(b::BalancedTernary)
    canonicalize!(b)
    if b.p > 0
        throw(InexactError("$(b.p) places after decimal point"))
    end
    return sum(t -> BigInt(3)^(t[1] - 1) * t[2], enumerate(reverse(b.dig)))          # 3
end

BigFloat(b::BalancedTernary) = BigInt(BalancedTernary(b.dig, 0)) / big"3.0"^(b.p)

function canonicalize!(b::BalancedTernary)
    for i in length(b.dig):-1:1
        if b.dig[i] > 1
            b.dig[i] -= 3
            if i == 1
                pushfirst!(b.dig, 1)
            else
                b.dig[i - 1] += 1
            end
        elseif b.dig[i] < -1
            b.dig[i] += 3
            if i == 1
                pushfirst!(b.dig, -1)
            else
                b.dig[i - 1] -= 1
            end
        end
    end
    if (i = findfirst(x -> x != 0, b.dig)) != nothing
        if i > 1
            b.dig = b.dig[i:end]
        end
    else
        b.dig = [0]
    end
    if b.p > 0 && (i = findlast(x -> x != 0, b.dig)) != nothing
        removable = min(b.p, length(b.dig) - i)
        b.dig = b.dig[1:end-removable]
        b.p -= removable
    end
    return b
end

# The following should work with any base number where dig, p are a similar array and Int
# and the proper constructors, canon, and conversion routines are defined     # 6

Base.print(io::IO, b::BalancedBaseDigitArray) = print(io, String(b))

function +(b1::T, b2::T) where T <: BalancedBaseDigitArray                 # 4
    if all(x -> x == 0, b1.dig)
        return deepcopy(b2)
    elseif all(x -> x == 0, b2.dig)
        return deepcopy(b1)
    end
    ldigits1 = length(b1.dig) - b1.p
    arr = b1.dig[1:ldigits1]
    ldigits2 = length(b2.dig) - b2.p
    arr2 = b2.dig[1:ldigits2]
    if (i = ldigits1 - ldigits2) > 0
        arr2 = [zeros(Int8, i); arr2]
    elseif i < 0
        arr = [zeros(Int8, -i); arr]
    end
    if (i = b1.p - b2.p) > 0
        arr = [arr; b1.dig[ldigits1+1:end]]
        arr2 = [arr2; b2.dig[ldigits2+1:end]; zeros(Int8, i)]
    elseif i < 0
        arr = [arr; b1.dig[ldigits1+1:end]; zeros(Int8, -i)]
        arr2 = [arr2; b2.dig[ldigits2+1:end]]
    else
        arr = [arr; b1.dig[ldigits1+1:end]]
        arr2 = [arr2; b2.dig[ldigits2+1:end]]
    end
    arr .+= arr2
    return canonicalize!(T(arr, max(b1.p, b2.p)))
end

-(b1::T) where T <: BalancedBaseDigitArray = T(b1.dig .* -1, b1.p)            # 4
-(b1::T, b2::T) where T <: BalancedBaseDigitArray = +(b1, -b2)                # 4

function *(b1::T, b2::T) where T <: BalancedBaseDigitArray                    # 4
    len = length(b2.dig)
    bsum = T()
    for i in len:-1:1
        bsum += T([b1.dig .* b2.dig[i]; zeros(Int8, len - i)], 0)
    end
    bsum.p = b1.p + b2.p
    return canonicalize!(bsum)
end

function code_reuse_task(T::Type)
    a = T("+-0++0+.+-0++0+")
    b = T(-436.436)
    c = T("+-++-.+-++-")
    println(" a = ", a, " = ", format(BigFloat(a)))
    println(" b = ", b, " = ", format(BigFloat(b)))
    println(" c = ", c, " = ", format(BigFloat(c)))
    println("\na * (b - c) = ", String(a * (b - c)), "\n = ", format(BigFloat(a * (b - c))))

    println("\n           Multiplication 27 X 12")
    println(" x|+ (1)  |+- (2) |+0 (3) |++ (4) |+-- (5)|+-0 (6)|+-+ (7)|+0- (8)|+e+-(9)|+0+(10)|++-(11)|++0(12)|")
    for i in 1:27
        print(lpad(i, 2), "|")
        for j in 1:12
            print(lpad(String(T(i * j)), 7), "|")
        end
        print("\n")
    end
end

code_reuse_task(BalancedTernary)
Output:
 a = +-0++0+.+-0++0+ = 523.23914
 b = -++-0--.--0+-00+++-0-+---0-+0++++0--++++0-+0+-0+0+-000-0----+0--0---+-000++--++-+-0--0-+ = -436.436
 c = +-++-.+-++- = 65.26749

a * (b - c) = ----000-0+0+.0+0-0-00---00--0-0+--+0-0+0++-+-0--0--+0-++-0-+00-++0-0-0+++--0-+0--+-++-+-+-++-+0+-+-+
 = -262510.90268

           Multiplication 27 X 12
 x|+ (1)  |+- (2) |+0 (3) |++ (4) |+-- (5)|+-0 (6)|+-+ (7)|+0- (8)|+e+-(9)|+0+(10)|++-(11)|++0(12)|
 1|      +|     +-|     +0|     ++|    +--|    +-0|    +-+|    +0-|    +00|    +0+|    ++-|    ++0|
 2|     +-|     ++|    +-0|    +0-|    +0+|    ++0|   +---|   +--+|   +-00|   +-+-|   +-++|   +0-0|
 3|     +0|    +-0|    +00|    ++0|   +--0|   +-00|   +-+0|   +0-0|   +000|   +0+0|   ++-0|   ++00|
 4|     ++|    +0-|    ++0|   +--+|   +-+-|   +0-0|   +00+|   ++--|   ++00|   ++++|  +--0-|  +--+0|
 5|    +--|    +0+|   +--0|   +-+-|   +0-+|   +0+0|   ++0-|   ++++|  +--00|  +-0--|  +-00+|  +-+-0|
 6|    +-0|    ++0|   +-00|   +0-0|   +0+0|   ++00|  +---0|  +--+0|  +-000|  +-+-0|  +-++0|  +0-00|
 7|    +-+|   +---|   +-+0|   +00+|   ++0-|  +---0|  +--++|  +-0+-|  +-+00|  +0--+|  +00--|  +00+0|
 8|    +0-|   +--+|   +0-0|   ++--|   ++++|  +--+0|  +-0+-|  +-+0+|  +0-00|  +000-|  +0+-+|  ++--0|
 9|    +00|   +-00|   +000|   ++00|  +--00|  +-000|  +-+00|  +0-00|  +0000|  +0+00|  ++-00|  ++000|
10|    +0+|   +-+-|   +0+0|   ++++|  +-0--|  +-+-0|  +0--+|  +000-|  +0+00|  ++-0+|  ++0+-|  ++++0|
11|    ++-|   +-++|   ++-0|  +--0-|  +-00+|  +-++0|  +00--|  +0+-+|  ++-00|  ++0+-|  +++++| +--0-0|
12|    ++0|   +0-0|   ++00|  +--+0|  +-+-0|  +0-00|  +00+0|  ++--0|  ++000|  ++++0| +--0-0| +--+00|
13|    +++|   +00-|   +++0|  +-0-+|  +-++-|  +00-0|  +0+0+|  ++0--|  +++00| +---++| +--+0-| +-0-+0|
14|   +---|   +00+|  +---0|  +-0+-|  +0--+|  +00+0|  ++-0-|  ++0++| +---00| +--+--| +-0-0+| +-0+-0|
15|   +--0|   +0+0|  +--00|  +-+-0|  +0-+0|  +0+00|  ++0-0|  ++++0| +--000| +-0--0| +-00+0| +-+-00|
16|   +--+|   ++--|  +--+0|  +-+0+|  +000-|  ++--0|  ++0++| +---+-| +--+00| +-00-+| +-+---| +-+0+0|
17|   +-0-|   ++-+|  +-0-0|  +0---|  +00++|  ++-+0|  ++++-| +--00+| +-0-00| +-0+0-| +-+0-+| +0---0|
18|   +-00|   ++00|  +-000|  +0-00|  +0+00|  ++000| +---00| +--+00| +-0000| +-+-00| +-++00| +0-000|
19|   +-0+|   +++-|  +-0+0|  +0-++|  ++---|  +++-0| +--0-+| +-0-0-| +-0+00| +-+00+| +0--+-| +0-++0|
20|   +-+-|   ++++|  +-+-0|  +000-|  ++-0+|  ++++0| +--+--| +-00-+| +-+-00| +-+++-| +0-0++| +000-0|
21|   +-+0|  +---0|  +-+00|  +00+0|  ++0-0| +---00| +--++0| +-0+-0| +-+000| +0--+0| +00--0| +00+00|
22|   +-++|  +--0-|  +-++0|  +0+-+|  ++0+-| +--0-0| +-0-0+| +-+---| +-++00| +0-0++| +0000-| +0+-+0|
23|   +0--|  +--0+|  +0--0|  +0++-|  +++-+| +--0+0| +-000-| +-+-++| +0--00| +00---| +00+0+| +0++-0|
24|   +0-0|  +--+0|  +0-00|  ++--0|  ++++0| +--+00| +-0+-0| +-+0+0| +0-000| +000-0| +0+-+0| ++--00|
25|   +0-+|  +-0--|  +0-+0|  ++-0+| +---0-| +-0--0| +-0+++| +-+++-| +0-+00| +00+-+| +0++--| ++-0+0|
26|   +00-|  +-0-+|  +00-0|  ++0--| +---++| +-0-+0| +-+-+-| +0--0+| +00-00| +0+-0-| ++---+| ++0--0|
27|   +000|  +-000|  +0000|  ++000| +--000| +-0000| +-+000| +0-000| +00000| +0+000| ++-000| ++0000|

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. 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.

-- 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]='-') or
                         (zdx!=1 and find(n[1],alphabet)<zdx))
        if negative then n = negate(n,alphabet) 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
 
-- 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)
    integer base = length(alphabet),
            zdx = find('0',alphabet),
            carry = 0, da, db, digit
    if zdx=1 then
        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),
            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 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(da,db)
        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
 
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.
 
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),
--     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})
    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})
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)

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] regarding decimal/ternary input, just above.

Output:
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  NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
      c = 65.26748971193416  BK.GF
a*(b-c) = -262510.9026799813  ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO

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

multiplication table

Without e notation, with hexadecimal across, septemvigesimal down, and balanced ternary contents!

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")
Output:
* | #1   + | #2  +- | #3  +0 | #4  ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 |      + |        |        |        |        |        |        |        |        |        |        |        |
2 |     +- |     ++ |        |        |        |        |        |        |        |        |        |        |
3 |     +0 |    +-0 |    +00 |        |        |        |        |        |        |        |        |        |
4 |     ++ |    +0- |    ++0 |   +--+ |        |        |        |        |        |        |        |        |
5 |    +-- |    +0+ |   +--0 |   +-+- |   +0-+ |        |        |        |        |        |        |        |
6 |    +-0 |    ++0 |   +-00 |   +0-0 |   +0+0 |   ++00 |        |        |        |        |        |        |
7 |    +-+ |   +--- |   +-+0 |   +00+ |   ++0- |  +---0 |  +--++ |        |        |        |        |        |
8 |    +0- |   +--+ |   +0-0 |   ++-- |   ++++ |  +--+0 |  +-0+- |  +-+0+ |        |        |        |        |
9 |    +00 |   +-00 |   +000 |   ++00 |  +--00 |  +-000 |  +-+00 |  +0-00 |  +0000 |        |        |        |
A |    +0+ |   +-+- |   +0+0 |   ++++ |  +-0-- |  +-+-0 |  +0--+ |  +000- |  +0+00 |  ++-0+ |        |        |
B |    ++- |   +-++ |   ++-0 |  +--0- |  +-00+ |  +-++0 |  +00-- |  +0+-+ |  ++-00 |  ++0+- |  +++++ |        |
C |    ++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 |  +--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--- |  +00++ |  ++-+0 |  ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 |
I |   +-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+00 | +-+00+ | +0--+- | +0-++0 |
K |   +-+- |   ++++ |  +-+-0 |  +000- |  ++-0+ |  ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 |
L |   +-+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 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 |
O |   +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-+00 | +00+-+ | +0++-- | ++-0+0 |
Q |   +00- |  +-0-+ |  +00-0 |  ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 |
10|   +000 |  +-000 |  +0000 |  ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |

Wren

Translation of: Phix
Library: Wren-str
Library: Wren-iterate
Library: Wren-fmt

Translated via the Go entry.

import "./str" for Str
import "./iterate" for Stepped
import "./fmt" for Fmt

var maxdp           = 81
var binary          = "01"
var ternary         = "012"
var balancedTernary = "-0+"
var decimal         = "0123456789"
var hexadecimal     = "0123456789ABCDEF"
var septemVigesimal = "0123456789ABCDEFGHIJKLMNOPQ"
var balancedBase27  = "ZYXWVUTSRQPON0ABCDEFGHIJKLM"
var base37          = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// converts Phix indices to Wren
var wIndex = Fn.new { |pIndex, le|
    if (pIndex < 0) return pIndex + le
    return pIndex - 1
}

var getCarry = Fn.new { |digit, base|
    if (digit > base) {
        return 1
    } else if (digit < 1) {
        return -1
    }
    return 0
}

// convert string 'b' to a decimal floating point number
var b2dec = Fn.new { |b, alphabet|
    var res = 0
    var base = alphabet.count
    var zdx = alphabet.indexOf("0") + 1
    var signed = zdx == 1 && b[0] == "-"
    if (signed) b = b[1..-1]
    var le = b.count
    var ndp = b.indexOf(".") + 1
    if (ndp != 0) {
        b = Str.delete(b, ndp - 1) // remove decimal point
        ndp = le - ndp
    }
    for (i in Stepped.ascend(1..b.count)) {
        var idx = alphabet.indexOf(b[i-1]) + 1
        res = base * res + idx - zdx
    }
    if (ndp != 0) res = res / base.pow(ndp)
    if (signed) res = -res
    return res
}

// string 'b' can be balanced or unbalanced
var negate = Fn.new { |b, alphabet|
    if (alphabet[0] == "0") {
        if (b != "0") b = (b[0] == "-") ? b[1..-1] : Str.insert(b, 0, "-")
    } else {
        for (i in Stepped.ascend(1..b.count)) {
            if (b[i-1] != ".") {
                var idx = alphabet.indexOf(b[i-1]) + 1
                var wi = wIndex.call(-idx, alphabet.count)
                b = Str.change(b, i-1, alphabet[wi])
            }
        }
    }
    return b
}

var bTrim = Fn.new { |b|
    // trim  trailing ".000"
    var idx = b.indexOf(".") + 1
    if (idx != 0) b = b.trimEnd("0").trimEnd(".")
    // trim leading zeros but not "0.nnn"
    while (b.count > 1 && b[0] == "0" && b[1] != ".") b = b[1..-1]
    return b
}

// for balanced number systems only
var bCarry = Fn.new { |digit, base, idx, n, alphabet|
    var carry = getCarry.call(digit, base)
    if (carry != 0) {
        for (i in Stepped.descend(idx..1)) {
            if (n[i-1] != ".") {
                var k = alphabet.indexOf(n[i-1]) + 1
                if (k < base) {
                    n = Str.change(n, i-1, alphabet[k])
                    break
                }
                n = Str.change(n, i-1, alphabet[0])
            }
        }
        digit = digit - base * carry
    }
    return [digit, n]
}

// convert a string from alphabet to alphabet2
var b2b // recursive function
b2b = Fn.new { |n, alphabet, alphabet2|
    var res = "0"
    var m = ""
    if (n != "0") {
        var base = alphabet.count
        var base2 = alphabet2.count
        var zdx = alphabet.indexOf("0") + 1
        var zdx2 = alphabet2.indexOf("0") + 1
        var carry = 0
        var q = 0
        var r = 0
        var digit = 0
        var idx = alphabet.indexOf(n[0]) + 1
        var negative = (zdx == 1 && n[0] == "-") || (zdx != 1 && idx < zdx)
        if (negative) n = negate.call(n, alphabet)
        var ndp = n.indexOf(".") + 1
        if (ndp != 0) {
            var t = n
            n = n[0...ndp-1]
            m = t[ndp..-1]
        }
        res = ""
        while (n.count > 0) {
            q = 0
            for (i in Stepped.ascend(1..n.count)) {
                digit = alphabet.indexOf(n[i-1]) + 1 - zdx
                q = q*base + digit
                r = q.abs % base2
                digit = (q.abs/base2).floor + zdx
                if (q < 0) digit = digit - 1
                if (zdx != 1) {
                    var p = bCarry.call(digit, base, i-1, n, alphabet)
                    digit = p[0]
                    n = p[1]
                }
                n = Str.change(n, i-1, alphabet[digit-1])
                q = r
            }
            r = r + zdx2
            if (zdx2 != 1) {
                r = r + carry
                carry = getCarry.call(r, base2)
                r = r - base2 * carry
            }
            res = Str.insert(res, 0, alphabet2[r-1])
            n = n.trimStart("0")
        }
        if (carry != 0) res = Str.insert(res, 0, alphabet2[carry+zdx2-1])
        if (m.count > 0) {
            res = res + "."
            ndp = 0
            if (zdx != 1) {
                var lm = m.count
                var alphaNew = base37[0...alphabet.count]
                m = b2b.call(m, alphabet, alphaNew)
                m = ("0" * (lm-m.count)) + m
                alphabet = alphaNew
                zdx = 1
            }
            while (m.count > 0 && ndp < maxdp) {
                q = 0
                for (i in Stepped.descend(m.count..1)) {
                    digit = alphabet.indexOf(m[i-1]) + 1 - zdx
                    q = q + digit * base2
                    r = q.abs % base + zdx
                    q = (q / base).truncate
                    if (q < 0) q = q - 1
                    m = Str.change(m, i-1, alphabet[r-1])
                }
                digit = q + zdx2
                if (zdx2 != 1) {
                    var p = bCarry.call(digit, base2, res.count, res, alphabet2)
                    digit = p[0]
                    res = p[1]
                }
                res = res + alphabet2[digit-1]
                m = m.trimEnd("0")
                ndp = ndp + 1
            }
        }
        res = bTrim.call(res)
        if (negative) res = negate.call(res, alphabet2)
    }
    return res
}

// convert 'd' to a string in the specified base
var float2b = Fn.new { |d, alphabet|
    var base = alphabet.count
    var zdx = alphabet.indexOf("0") + 1
    var carry = 0
    var neg = d < 0
    if (neg) d = -d
    var res = ""
    var whole = d.floor
    d = d - whole
    while (true) {
        var ch = whole % base + zdx
        if (zdx != 1) {
            ch = ch + carry
            carry = getCarry.call(ch, base)
            ch = ch - base * carry
        }
        res = Str.insert(res, 0, alphabet[ch-1])
        whole = (whole / base).truncate
        if (whole == 0) break
    }
    if (carry != 0) {
        res = Str.insert(res, 0, alphabet[carry+zdx-1])
        carry = 0
    }
    if (d != 0) {
        res = res + "."
        var ndp = 0
        while (d != 0 && ndp < maxdp) {
            d = d * base
            var digit = d.truncate + zdx
            d = d - digit
            if (zdx != 1) {
                var p = bCarry.call(digit, base, res.count, res, alphabet)
                digit = p[0]
                res = p[1]
            }
            res = res + alphabet[digit-1]
            ndp = ndp + 1
        }
    }
    if (neg) res = negate.call(res, alphabet)
    return res
}

var bSub // forwward declaration

var bAdd = Fn.new { |a, b, alphabet|
    var base = alphabet.count
    var zdx = alphabet.indexOf("0") + 1
    var carry = 0
    var da = 0
    var db = 0
    var digit = 0
    if (zdx == 1) {
        if (a[0] == "-") {
            return bSub.call(b, negate.call(a, alphabet), alphabet)
        }
        if (b[0] == "-") {
            return bSub.call(a, negate.call(b, alphabet), alphabet)
        }
    }
    var adt = a.indexOf(".") + 1
    var bdt = b.indexOf(".") + 1
    if (adt != 0 || bdt != 0) {
        if (adt != 0) {
            adt = a.count - adt + 1
            var wi = wIndex.call(-adt, a.count)
            a = Str.delete(a, wi)
        }
        if (bdt != 0) {
            bdt = b.count - bdt + 1
            var wi = wIndex.call(-bdt, b.count)
            b = Str.delete(b, wi)
        }
        if (bdt > adt) {
            a = a + ("0" * (bdt-adt))
            adt = bdt
        } else if (adt > bdt) {
            b = b + ("0" * (adt-bdt))
        }
    }
    if (a.count < b.count) {
       var t = a
       a = b
       b = t
    }
    for (i in Stepped.descend(-1..-a.count)) {
        if (i < -a.count) {
            da = 0
        } else {
            da = alphabet.indexOf(a[a.count + i]) + 1 - zdx
        }
        if (i < -b.count) {
            db = 0
        } else {
            db = alphabet.indexOf(b[b.count + i]) + 1 - zdx
        }
        digit = da + db + carry + zdx
        carry = getCarry.call(digit, base)
        a = Str.change(a, i + a.count, alphabet[digit-carry*base-1])
        if (i < -b.count && carry == 0) break
    }
    if (carry != 0) {
        a = Str.insert(a, 0, alphabet[carry+zdx-1])
    }
    if (adt != 0) {
        var wi = wIndex.call(-adt+1, a.count)
        a = Str.insert(a, wi, ".")
    }
    a = bTrim.call(a)
    return a
}

var aSmaller = Fn.new { |a, b, alphabet|
    if (a.count != b.count) Fiber.abort("strings should be equal in length")
    for (i in Stepped.ascend(1..a.count)) {
        var da = alphabet.indexOf(a[i-1]) + 1
        var db = alphabet.indexof(b[i-1]) + 1
        if (da != db) return da < db
    }
    return false
}

// declared earlier
bSub = Fn.new { |a, b, alphabet|
    var base = alphabet.count
    var zdx = alphabet.indexOf("0") + 1
    var carry = 0
    var da = 0
    var db = 0
    var digit = 0
    if (zdx == 1) {
        if (a[0] == "-") {
            return negate.call(bAdd.call(negate.call(a, alphabet), b, alphabet), alphabet)
        }
        if (b[0] == "-") {
            return bAdd.call(a, negate.call(b, alphabet), alphabet)
        }
    }
    var adt = a.indexOf(".") + 1
    var bdt = b.indexOf(".") + 1
    if (adt != 0 || bdt != 0) {
        if (adt != 0) {
            adt = a.count - adt + 1
            var wi = wIndex.call(-adt, a.count)
            a = Str.delete(a, wi)
        }
        if (bdt != 0) {
            bdt = b.count - bdt + 1
            var wi = wIndex.call(-bdt, b.count)
            b = Str.delete(b, wi)
        }
        if (bdt > adt) {
            a = a + ("0" * (bdt-adt))
            adt = bdt
        } else if (adt > bdt) {
            b = b + ("0" * (adt-bdt))
        }
    }
    var bNegate = false
    if (a.count < b.count || (a.count == b.count && aSmaller.call(a, b, alphabet))) {
        bNegate = true
        var t = a
        a = b
        b = t
    }
    for (i in Stepped.descend(-1..-a.count)) {
        if (i < -a.count) {
            da = 0
        } else {
            da = alphabet.indexOf(a[a.count+i]) + 1 - zdx
        }
        if (i < -b.count) {
            db = 0
        } else {
            db = alphabet.indexOf(b[b.count+i]) + 1 - zdx
        }
        digit = da - db - carry + zdx
        carry = 0
        if (digit <= 0) carry = 1
        a = Str.change(a, i+a.count, alphabet[digit+carry*base-1])
        if (i < -b.count && carry == 0) break
    }
    if (carry != 0) Fiber.abort("carry should be zero")
    if (adt != 0) {
        var wi = wIndex.call(-adt+1, a.count)
        a = Str.insert(a, wi, ".")
    }
    a = bTrim.call(a)
    if (bNegate) a = negate.call(a, alphabet)
    return a
}

var bMul = Fn.new { |a, b, alphabet|
    var zdx = alphabet.indexOf("0") + 1
    var dpa = a.indexOf(".") + 1
    var dpb = b.indexOf(".") + 1
    var ndp = 0
    if (dpa != 0) {
        ndp = ndp + a.count - dpa
        a = Str.delete(a, dpa-1)
    }
    if (dpb != 0) {
        ndp = ndp + b.count - dpb
        b = Str.delete(b, dpb-1)
    }
    var pos = a
    var res = "0"
    if (zdx != 1) {
        // balanced number systems
        var neg = negate.call(pos, alphabet)
        for (i in Stepped.descend(b.count..1)) {
            var m = alphabet.indexOf(b[i-1]) + 1 - zdx
            while (m != 0) {
                var temp = pos
                var temp2 = -1
                if (m < 0) {
                    temp = neg
                    temp2 = 1
                }
                res = bAdd.call(res, temp, alphabet)
                m = m + temp2
            }
            pos = pos + "0"
            neg = neg + "0"
        }
    } else {
        // non-balanced number systems
        var negative = false
        if (a[0] == "-") {
            a = a[1..-1]
            negative = true
        }
        if (b[0] == "-") {
            b = b[1..-1]
            negative = !negative
        }
        for (i in Stepped.descend(b.count..1)) {
            var m = alphabet.indexOf(b[i-1]) + 1 - zdx
            while (m > 0) {
                res = bAdd.call(res, pos, alphabet)
                m = m - 1
            }
            pos = pos + "0"
        }
        if (negative) res = negate.call(res, alphabet)
    }
    if (ndp != 0) {
        var wi = wIndex.call(-ndp, res.count)
        res = Str.insert(res, wi, ".")
    }
    res = bTrim.call(res)
    return res
}

var multTable = Fn.new {
    System.print("multiplication table")
    System.print("====================")
    System.write("* |")
    for (j in 1..12) {
        Fmt.write(" #$s $3s |", float2b.call(j, hexadecimal), float2b.call(j, balancedTernary))
    }
    for (i in 1..27) {
        var a = float2b.call(i, balancedTernary)
        Fmt.write("\n$-2s|", float2b.call(i, septemVigesimal))
        for (j in 1..12) {
            if (j > i) {
                System.write("        |")
            } else {
                var b = float2b.call(j, balancedTernary)
                var m = bMul.call(a, b, balancedTernary)
                Fmt.write(" $6s |", m)
            }
        }
    }
    System.print()
}

var test = Fn.new {|name, alphabet|
    var a = b2b.call("+-0++0+.+-0++0+", balancedTernary, alphabet)
    var b = b2b.call("-436.436", decimal, alphabet)
    var c = b2b.call("+-++-.+-++-", balancedTernary, alphabet)
    var d = bSub.call(b, c, alphabet)
    var r = bMul.call(a, d, alphabet)
    Fmt.print("$s\n$s", name, "=" * name.count)
    Fmt.print("      a = $.14f $s", b2dec.call(a, alphabet), a)
    Fmt.print("      b = $.14f $s", b2dec.call(b, alphabet), b)
    Fmt.print("      c = $.14f $s", b2dec.call(c, alphabet), c)
    Fmt.print("a*(b-c) = $.14f $s\n", b2dec.call(r, alphabet), r)
}

test.call("balanced ternary", balancedTernary)
test.call("balanced base 27", balancedBase27)
test.call("decimal", decimal)
test.call("binary", binary)
test.call("ternary", ternary)
test.call("hexadecimal", hexadecimal)
test.call("septemvigesimal", septemVigesimal)
multTable.call()
Output:
balanced ternary
================
      a = 523.23914037494285 +-0++0+.+-0++0+
      b = -436.43599999999992 -++-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.90267998125637 ----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.23914037494285 AUJ.FLI
      b = -436.43600000000004 NKQ.YFDFTYSMHVANGXPVXHIZJRJWZD0PBGFJAEBAKOZODLY0ITEHPQLSQSGLFZUINATKCIKUVMWEWJMQ0COTS
      c = 65.26748971193416 BK.GF
a*(b-c) = -262510.90267998125637 ZVPJ.CWNYQPEENDVDPNJZXKFGCLHKLCX0YIBOMETHFWWBTVUFAH0SEZMTBJDCRRAQIQCAWMKXSTPYUXYPK0LODUO

decimal
=======
      a = 523.23914037494296 523.239140374942844078646547782350251486053955189757658893461362597165066300868770004
      b = -436.43599999999998 -436.436
      c = 65.26748971193415 65.267489711934156378600823045267489711934156378600823045267489711934156378600823045
a*(b-c) = -262510.90267998137278 -262510.90267998140903693918986303277315826215892262734715612833785876513103053772667101895163734826631742752252837097627017862754285047634638652268078676654605120794218

binary
======
      a = 523.23914037494274 1000001011.001111010011100001001101101110011000100001011110100101001010100100000111001000111
      b = -436.43600000000004 -110110100.011011111001110110110010001011010000111001010110000001000001100010010011011101001
      c = 65.26748971193416 1000001.01000100011110100011010010101100110001100000111010111111101111001001001101111101
a*(b-c) = -262510.90267998143099 -1000000000101101110.111001110001011000001001000001101110011111011100000100000100001000101011100011110010110001010100110111001011101001010000001110110100111110001101000000001111110101

ternary
=======
      a = 523.23914037494285 201101.0201101
      b = -436.43600000000021 -121011.102202211210021110012111201022222000202102010100101200200110122011122101110212
      c = 65.26748971193416 2102.02102
a*(b-c) = -262510.90267998125637 -111100002121.2201010011100110022102110002120222120100001221111011202022012121122001201122110221112

hexadecimal
===========
      a = 523.23914037494274 20B.3D384DB9885E94A90723EF9CBCB174B443E45FFC41152FE0293416F15E3AC303A0F3799ED81589C62
      b = -436.43599999999998 -1B4.6F9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB22D0E5604189374BC6A7EF9DB2
      c = 65.26748971193416 41.447A34ACC60EBFBC937D5DC2E5A99CF8A021B641511E8D2B3183AFEF24DF5770B96A673E28086D905
a*(b-c) = -262510.90267998143099 -4016E.E7160906E7DC10422DA508321819F4A637E5AEE668ED5163B12FCB17A732442F589975B7F24112B2E8F6E95EAD45803915EE26D20DF323D67CAEEC75D7BED68AA34E02F2B492257D66F028545FB398F60E

septemvigesimal
===============
      a = 523.23914037494285 JA.6C9
      b = -436.43600000000004 -G4.BKML7C5DJ8Q0KB39AIICH4HACN02OJKGPLOPG2D1MFBQI6LJ33F645JELD7I0Q6FNHG88E9M9GE3QO276
      c = 65.26748971193416 2B.76
a*(b-c) = -262510.90267998125637 -D92G.OA1C42LM0N8N30HDAFKJNEIFEOB0BHP1DM6ILA9P797KPJ05MCE6OGMO54Q3I3NQ9DGB673C8BC2FQF1N82

multiplication table
====================
* | #1   + | #2  +- | #3  +0 | #4  ++ | #5 +-- | #6 +-0 | #7 +-+ | #8 +0- | #9 +00 | #A +0+ | #B ++- | #C ++0 |
1 |      + |        |        |        |        |        |        |        |        |        |        |        |
2 |     +- |     ++ |        |        |        |        |        |        |        |        |        |        |
3 |     +0 |    +-0 |    +00 |        |        |        |        |        |        |        |        |        |
4 |     ++ |    +0- |    ++0 |   +--+ |        |        |        |        |        |        |        |        |
5 |    +-- |    +0+ |   +--0 |   +-+- |   +0-+ |        |        |        |        |        |        |        |
6 |    +-0 |    ++0 |   +-00 |   +0-0 |   +0+0 |   ++00 |        |        |        |        |        |        |
7 |    +-+ |   +--- |   +-+0 |   +00+ |   ++0- |  +---0 |  +--++ |        |        |        |        |        |
8 |    +0- |   +--+ |   +0-0 |   ++-- |   ++++ |  +--+0 |  +-0+- |  +-+0+ |        |        |        |        |
9 |    +00 |   +-00 |   +000 |   ++00 |  +--00 |  +-000 |  +-+00 |  +0-00 |  +0000 |        |        |        |
A |    +0+ |   +-+- |   +0+0 |   ++++ |  +-0-- |  +-+-0 |  +0--+ |  +000- |  +0+00 |  ++-0+ |        |        |
B |    ++- |   +-++ |   ++-0 |  +--0- |  +-00+ |  +-++0 |  +00-- |  +0+-+ |  ++-00 |  ++0+- |  +++++ |        |
C |    ++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 |  +--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--- |  +00++ |  ++-+0 |  ++++- | +--00+ | +-0-00 | +-0+0- | +-+0-+ | +0---0 |
I |   +-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+00 | +-+00+ | +0--+- | +0-++0 |
K |   +-+- |   ++++ |  +-+-0 |  +000- |  ++-0+ |  ++++0 | +--+-- | +-00-+ | +-+-00 | +-+++- | +0-0++ | +000-0 |
L |   +-+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 | +-000- | +-+-++ | +0--00 | +00--- | +00+0+ | +0++-0 |
O |   +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-+00 | +00+-+ | +0++-- | ++-0+0 |
Q |   +00- |  +-0-+ |  +00-0 |  ++0-- | +---++ | +-0-+0 | +-+-+- | +0--0+ | +00-00 | +0+-0- | ++---+ | ++0--0 |
10|   +000 |  +-000 |  +0000 |  ++000 | +--000 | +-0000 | +-+000 | +0-000 | +00000 | +0+000 | ++-000 | ++0000 |