Παρασκευή 3 Ιουλίου 2026

Balanced ternary (for Rosetta Code)

 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

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.