M2000 Interpreter rational numbers

From Rosetta Code

M2000 Interpreter

Module RationalNumbers {
      Class Rational {
            numerator as decimal, denominator as decimal
            gcd=lambda->0
            lcm=lambda->0
            operator "+" {
                 Read l
                 denom=.lcm(l.denominator, .denominator)
                 .numerator<=denom/l.denominator*l.numerator+denom/.denominator*.numerator
                 if .numerator==0 then denom=1
                 .denominator<=denom
            }
            Operator Unary {
                  .numerator-!
            }
            Operator "-" {
                  Read l
                  Call Operator "+", -l
            }
            Operator "*" {
                  Read l
                  g1=.gcd(l.numerator,.denominator)
                  g2=.gcd(.numerator, l.denominator)
                  Push l.numerator/g1*.numerator/g2
                  Push l.denominator/g2*.denominator/g1
                  Read .denominator, .numerator
      
            }
            Function Inverse {
                  if .numerator==0 then Error "Division by zero"
                  ret=This
                  sign=sgn(ret.numerator) : if sign<0 then ret.numerator-!
                  swap ret.numerator, ret.denominator
                  if sign<0 then ret.numerator-!
                  =ret
            }
            Operator "/" {
                  Read l
                  call operator "*", l.inverse()
            }
            Function Power {
                  Read pow as long
                  ret=This
                  ret.numerator<=.numerator^pow
                  ret.denominator<=.denominator^pow
                  =ret
            }
            Operator "=" {
                  Read l
                  Def boolean T=True, F=False
                  if Abs(sgn(l.numerator))+Abs(sgn(.numerator))=0 then Push T: exit
                  if sgn(l.numerator) <>sgn(.numerator) then Push F : exit
                  pcomp=l/this
                  PUSH pcomp.numerator=1 and pcomp.denominator=1
            }
            Operator ">" {
                  Read l
                  Def boolean F
                  if Abs(sgn(l.numerator))+Abs(sgn(.numerator))=0 then Push F: exit
                  if sgn(l.numerator)=0 then {
                        PUSH .numerator>0
                  } Else {      
                        pcomp=this/l
                        PUSH pcomp.real>1
                  }
            }
            Operator ">=" {
                  Read l
                  if sgn(l.numerator)=0 then {
                        PUSH .numerator>=0
                  } Else {      
                        pcomp=this/l
                        PUSH pcomp.real>=1
                  }
            }      
            Operator "<" {
                  Read l
                  Def boolean F
                  if Abs(sgn(l.numerator))+Abs(sgn(.numerator))=0 then Push F: exit
                  if sgn(l.numerator)=0 then {
                        PUSH .numerator<0
                  } Else {      
                        pcomp=this/l
                        PUSH pcomp.real<1
                  }
            }
            Operator "<=" {
                  Read l
                  if sgn(l.numerator)=0 then {
                        PUSH .numerator<=0
                  } Else {      
                        pcomp=this/l
                        PUSH pcomp.real<=1
                  }            
            }
            Operator "<>" {
                  Read l
                  if sgn(l.numerator)=0 then {
                        PUSH .numerator<>0
                  } Else {      
                        pcomp=this/l
                        PUSH pcomp.real<>1
                  }            
            }
            Group Real {
                  value {
                        link parent numerator, denominator to n, d
                        =n/d
                  }
            }
            Group ToString$ {
                 value {
                        link parent numerator, denominator to n, d
                        =Str$(n)+"/"+Str$(d,"")
                  }      
            }
            class:
            Module Rational (.numerator, .denominator) {
                  if .denominator=0 then Error "Zero denominator"
                  sgn=Sgn(.numerator)*Sgn(.denominator)
                  .denominator<=abs(.denominator)
                  .numerator<=abs(.numerator)*sgn
                  gcd1=lambda (a as decimal, b as decimal) -> {
                        if a<b then swap a,b
                        g=a mod b
                        while g {
                              a=b:b=g: g=a mod b
                        }
                        =abs(b)
                  }
                  gdcval=gcd1(abs(.numerator), .denominator)
                  if gdcval<.denominator and gdcval<>0 then
                        .denominator/=gdcval
                        .numerator/=gdcval
                  end if
                  .gcd<=gcd1
                  .lcm<=lambda gcd=gcd1 (a as decimal, b as decimal) -> {
                        =a/gcd(a,b)*b
                  }
            }
      }
      Print rational(-3,3)<>rational(-3,3)
      M=Rational(10, 150)
      N=Rational(2, 4)
      Z=M+N
      Print Z.numerator, Z.denominator
      Print 10/150@+2/4@
      Print Z.real
      Z=-M+N
      Print Z.numerator, Z.denominator
      Print -10/150@+2/4@
      Print Z.real
      Z=M-N
      Print Z.numerator, Z.denominator
      Print 10/150@-2/4@
      Print Z.real
      Z=M*N
      Print Z.numerator, Z.denominator
      Print (10/150@)*(2/4@)
      Print Z.real
      Z=M/N
      Print Z.numerator, Z.denominator
      Print (10/150@)/(2/4@)
      Print Z.real
      Z=Z.Power(2)
      Print Z.real
      Print Z=Z
      Print Z=N
      Print Z=-Z
      ZZ=-Z
      Print ZZ=ZZ
      Print -Z=-Z
      Print Z.numerator, Z.denominator
      Print Z.real, Z.tostring$
      \\ Array of rational numbers
      Dim K(100)=rational(1,1)
      M=K(4)+K(3)
      Print M.real
      Print K(4).toString$
}
RationalNumbers