https://rosettacode.org/wiki/Balanced_ternary#M2000_Interpreter
Adding a nice class for balanced ternary numbers.
module balanced_ternary {
class ternary {
private:
string val="0"
function rev() {
=replace("a","-", replace("-","+", replace("+","a",letter$)))
}
function neg() {
a=this
a.val=.rev(.val)
=a
}
function addstr(b, c) {
d=len(b)-len(c)
if d<0 then
b=string$("0", -d)+b
else.if d>0 then
c=string$("0", d)+c
end if
string f=string$("0", len(c)),e="0"
for i=len(b) to 1
select case mid$(b,i,1)+mid$(c,i,1)+e
case "000", "-+0", "+-0", "-0+","+0-","0+-", "0-+"
e="0"
case "00+", "0+0", "+00"
insert i,1 f="+" : e="0"
case "00-", "0-0", "-00"
insert i,1 f="-" : e="0"
case "--0","-0-","0--"
insert i,1 f="+" : e="-"
case "++0", "+0+","0++"
insert i,1 f="-" : e="+"
case "++-","+-+","-++"
insert i,1 f="+" : e="0"
case "--+","-+-","+--"
insert i,1 f="-" : e="0"
case "+++"
e="+"
case "---"
e="-"
end select
next
if e<>"0" then =e+f else =f
}
public:
' this is for negate.tostring, negate.tostring(), negate.tostring.decimal(), negate.tostring.decimalsign()
group negate {
private:
function id {
link parent neg() to neg()
' space need to break identifier to neg(
=neg( ).tostring(![])
}
public:
group tostring {
public:
function decimal() {
link parent id() to id()
=id(1)
}
function decimalsign() {
link parent id() to id()
=id(2)
}
value (){
link parent id() to id()
=id(![])
}
}
value {
link parent neg() to neg()
=neg()
}
}
function add(a as ternary) {
a.val<=.addstr(.val, a.val)
=a
}
operator unary {
this<=.neg()
}
operator "+" (a as ternary) {
this<=.add(a)
}
operator "-" (a as ternary) {
this<=.add(a.neg())
}
operator high "*" (a as ternary) {
this<=.mul(a)
}
function mul(a as ternary) {
c=""
s=""
r=.rev(a.val)
for i = len(.val) to 1 step -1
select case mid$(.val,i,1)
case "+"
c=.addstr(a.val+s,c)
case "-"
c=.addstr(r+s,c)
end select
s+="0"
next
a.val<=c
=a
}
group tostring {
enum conv {
asis=0, decimal, decimalsign
}
function decimal() {
link &this to &m
=m(1)
}
function decimalsign() {
link &this to &m
=m(2)
}
}
property tostring {
value {
long how=.asis
read ? how
link parent val to v
if how=.asis then
value=v
else
biginteger z=1
biginteger acc=0
for i=len(v) to 1
select case mid(v,i,1)
case "-"
acc-=z
case "+"
acc+=z
end select
z*=3
next
if acc>=0 and how=.decimalsign then
value="+"+acc
else
value=""+acc
end if
end if
}
}=""
class:
module ternary (a as variant) {
if type(a)="String" then
a=replace(chrcode$(8722), "-", a)
f=filter(a,"0-+")
.val<=filter(a, f)
if .val="" then .val<="0"
else
try ok {
biginteger v=a
f=""
sign=sgn(v)
v=abs(v)
do
select case v mod 3
case 0
f+="0"
v|div 3
case 1
if sign<0 then f+="-" else f+="+"
v|div 3
case 2
if sign<0 then f+="+" else f+="-"
v=(v+1) div 3
end select
until v=0
.val<=strrev$(f)
}
if not ok then error "wrong type"
end if
}
}
' test with big numbers:
w="123456787890123456787890123456787890123456787890123456787901"
print ternary(123456787890123456787890123456787890123456787890123456787890u).add(ternary(11)).tostring(1)=w
print 123456787890123456787890123456787890123456787890123456787890u+11=biginteger(w)
' test as rosetta code describe:
ternary a("+-0++0+"), b(-436), c("+-++-")
print a.mul(b.add(c.negate)).tostring.decimal()="-262023"
print a.mul(b.add(c.negate)).tostring="0----0+--0++0"
print a.tostring.decimal()="523"
print b.tostring.decimal()="-436"
print c.tostring(c.tostring.decimal)="65" ' using enum value
print c.tostring(c.tostring.asis)="+-++-" ' using enum value
' additional:
def v(a as ternary)=biginteger(a.tostring.decimal())
' using operators:
print v(a*(b-c))=-262023
print v(-a*(b-c))=262023
print v(ternary("+-0++0+")*(ternary(-436)-ternary("+-++-")))=-262023
}
balanced_ternary