generic module to add , subtract, mul 2 numbers of any size
Posted: Thu Jan 03, 2008 8:53 am
Here is something I wrote which can add subtract, multiply 2 integer numbers of any size (not restricted by the size of the longest register etc)
I wanted to make this into a generic calculator/math library which can be used for all sorts of computations, without running into floating point issues and rounding errors.
Right now it works with positive inputs, will be adding support for negative inputs as well as well as support for Mod and Division in a while,
Please feel free to let me know any tricks you may have to achieve the same
I wanted to make this into a generic calculator/math library which can be used for all sorts of computations, without running into floating point issues and rounding errors.
Right now it works with positive inputs, will be adding support for negative inputs as well as well as support for Mod and Division in a while,
Please feel free to let me know any tricks you may have to achieve the same
Code: Select all
Global n2$="",n1$="" ;hold the absolute value without the sign, after padding zeros
Global n1,n2; this holds the absolute length of the numbers after padding zeros, without the sign
Global n1sign$,n2sign$ ; holds the + or - sign of n1 and n2
;********do not ever access these values directly from the main program**********
;these can be treated as global registers user by the all the to pass computed values
; compare() function not only compares but also removes leading zeros,
; seperates signs in the input from the abs value, and adds padding
;these are used to pass across n1$ and n2$ and their associated properties
;across all subroutines
;so in other words while each procedure holds it's input as myn1$ and myn2$,
;it can always use the global n1$ and n2$ to get back values from "compare"
;compare returns 0 if n1>n2 , 1 if n2>n1 and -1 if n1=n2
Procedure Compare (myn1$,myn2$)
;1st we check for any leading 0s in myn1$
;PrintN("inside compare")
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN("=================")
Protected flag=0
Protected flag1=0;;keeps track if we have seen a non zero element
Protected cnt=0;amount by which the string has to be trimmed
Protected myn1sign$,myn2sign$ ;incase there is a sign
Protected myn1,myn2
Protected i
If Mid(myn1$,1,1)="-"
myn1sign$="-"
myn1$=Right(myn1$,n1-1)
EndIf
myn1=Len(myn1$)
;PrintN (Str(myn1)+"::"+Str(n1))
;PrintN (myn1$)
For i=1 To myn1
If Mid(myn1$,i,1)="0" And (flag1=0)
cnt=cnt+1
Else
flag1=1
Break
EndIf
Next i
myn1$=Right(myn1$,myn1-cnt)
;myn1$=myn1sign$+myn1$
myn1=Len(myn1$)
;PrintN (Str(myn1)+","+Str(cnt))
;PrintN (myn1$)
;============================
;now we check for any leading 0s in myn2$
flag1=0 ;keeps track if we have seen a non zero element
cnt=0;amount by which the string has to be trimmed
myn2sign$="" ;incase there is a sign
If Mid(myn2$,1,1)="-"
myn2sign$="-"
myn2$=Right(myn2$,myn2-1)
EndIf
myn2=Len(myn2$)
;PrintN (Str(myn2))
;PrintN (myn2$)
For i=1 To Len(myn2$)
If Mid(myn2$,i,1)="0" And (flag1=0)
cnt=cnt+1
Else
flag1=1
Break
EndIf
Next i
myn2$=Right(myn2$,myn2-cnt)
;myn2$=n2sign$+myn2$
myn2=Len(myn2$)
;PrintN (Str(n2)+","+Str(cnt))
;PrintN (myn2$)
;zero pads
If myn1>myn2
size=myn1
diff=myn1-myn2
For i=1 To diff
myn2$="0"+myn2$
Next i
ElseIf myn2>myn1
size=myn2
diff=myn2-myn1
For i=1 To diff
myn1$="0"+myn1$
Next i
EndIf
;PrintN(myn1$+"::"+myn2$)
;done with zero pads
;PrintN("inside compare")
;PrintN (myn1$)
;PrintN (myn2$)
flag=-1;the flag is 0 is abs(myn1$)>abs(myn2$) else is 1, if both are equal flag is -1
; we now need to check which one is greater
If myn1>myn2
flag=0
ElseIf myn2>myn1
flag=1
ElseIf (myn1=myn2)
For i = 1 To myn1
If Val(Mid(myn1$,i,1))>Val(Mid(myn2$,i,1))
flag=0
Break
ElseIf Val(Mid(myn1$,i,1))<Val(Mid(myn2$,i,1))
flag=1
Break
EndIf
Next i
EndIf
;flag stays -1 if both are equal
;PrintN("inside compare")
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN (Str(flag))
;PrintN("=================")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
If (flag=0) And (myn1sign$="") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 0
ElseIf (flag=0) And (myn1sign$="") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 0
ElseIf (flag=0) And (myn1sign$="-") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 1
ElseIf (flag=0) And (myn1sign$="-") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ElseIf (flag=-1) And (myn1sign$="") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn -1
ElseIf (flag=-1) And (myn1sign$="") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 0
ElseIf (flag=-1) And (myn1sign$="-") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 1
ElseIf (flag=-1) And (myn1sign$="-") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn -1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ElseIf (flag=1) And (myn1sign$="") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 1
ElseIf (flag=1) And (myn1sign$="") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 0
ElseIf (flag=1) And (myn1sign$="-") And (myn2sign$="")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 1
ElseIf (flag=1) And (myn1sign$="-") And (myn2sign$="-")
n1$=myn1$
n2$=myn2$
n1=Len(myn1$)
n2=Len(myn2$)
n1sign$=myn1sign$
n2sign$=myn2sign$
ProcedureReturn 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
EndIf
;by this time myn1$ and myn2$ are of equal length in terms of string size (excluding the "-" sign)
EndProcedure
;=============================================
Procedure.s Add (myn1$,myn2$)
;PrintN ("==============================")
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN ("==============================")
result=Compare (myn1$,myn2$)
myn1$=n1$;we need to reassign these to the padded values
myn2$=n2$
Protected result$=""
Protected carry=0
Protected size=Len(n1$)
Protected temp_result$=""
;PrintN ("==============================")
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN ("==============================")
For i=size To 1 Step -1
;PrintN(Mid(myn1$,size,1))
;PrintN(Mid(myn2$,size,1))
;PrintN("-----------------")
temp_result$=Str(Val(Mid(myn1$,i,1))+Val(Mid(myn2$,i,1))+carry)
;PrintN(temp_result$)
;PrintN("-----------------")
If Len(temp_result$)=2 And Not(i=1) ; if i=1 this is the 1st digit so the carry has to stick on front
carry=Val(Mid(temp_result$,1,1))
temp_result$=Mid(temp_result$,2,1)
Else
carry=0
EndIf
result$=temp_result$+result$
Next i
If result$=""
result$="0"
EndIf
;PrintN ("Add:"+result$)
ProcedureReturn result$
EndProcedure
;==============================================
Procedure.s Carry_propogation (myn1$,i,size)
;PrintN ("myn1$:"+myn1$)
temp_left$=Left(myn1$,i-1)
temp_right$=Right(myn1$,size-i)
this$=""
;PrintN("temp left:"+temp_left$)
;PrintN("temp right:"+temp_right$)
If Val(Mid(myn1$,i,1))=0 ;if this zero, we have to borrow from previous and make this "9"
this$="9"
myn1$=temp_left$+this$+temp_right$
;PrintN ("myn1$:"+myn1$)
myn1$=Carry_propogation(myn1$,i-1,size)
Else
this$=Str(Val(Mid(myn1$,i,1))-1)
myn1$=temp_left$+this$+temp_right$
;PrintN ("myn1$:"+myn1$)
EndIf
;PrintN ("myn1$:"+myn1$)
ProcedureReturn myn1$
EndProcedure
;==============================================
Procedure.s Subtract (myn1$,myn2$)
;PrintN ("inside subtract")
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN ("==============================")
Protected carry
Protected temp_result$
Protected toggle=0 ;if myn1$>=myn2$ we stay at 0 else we become 1
Protected result=Compare(myn1$,myn2$)
If (result=1) ; if n1$<n2$ result is 1 and so we swap myn1$ and myn2$
toggle=1
myn2$=n1$
myn1$=n2$
ElseIf (result=0)Or(result=-1)
toggle=0
myn1$=n1$
myn2$=n2$
EndIf
size=Len(n1$)
result$=""
;PrintN ("inside subtract")
;PrintN (Str(result))
;PrintN (myn1$)
;PrintN (myn2$)
;PrintN ("==============================")
For i=size To 1 Step -1
carry=0
If Val(Mid(myn1$,i,1))>=Val(Mid(myn2$,i,1))
temp_result$=Str(Val(Mid(myn1$,i,1))-Val(Mid(myn2$,i,1))+carry)
result$=temp_result$+result$
;PrintN ("size="+Str(i))
;PrintN (result$)
ElseIf Val(Mid(myn1$,i,1))<Val(Mid(myn2$,i,1))
carry=10
myn1$=Carry_propogation(myn1$,i-1,size) ; carry reduction propogates from "i-1"
temp_result$=Str(Val(Mid(myn1$,i,1))-Val(Mid(myn2$,i,1))+carry)
result$=temp_result$+result$
;PrintN (result$)
EndIf
Next i
;remove leading zeros
For i=1 To Len(result$)
If Mid(result$,i,1)="0" And (flag=0)
cnt=cnt+1
Else
Break
EndIf
Next i
result$=Right(result$,Len(result$)-cnt)
;If toggle=1
;result$="-"+result$
;EndIf
If result$=""
result$="0"
EndIf
;PrintN("Subtract:"+result$)
ProcedureReturn result$
EndProcedure
;===============================================
Procedure.s Multiply (myn1$,myn2$)
result=Compare (myn1$,myn2$)
myn1$=n1$;we need to reassign these to the padded values
myn2$=n2$
Protected result$=""
Protected carry=0
Protected size=Len(n1$)
Protected temp_result$=""
Protected line_result$="0"
For i=size To 1 Step -1; this goes across digits of myn2$
temp_result$=""
For j=size To 1 Step -1; this goes across digits of myn1$
local_result$=Str(Val(Mid(myn2$,i,1))*Val(Mid(myn1$,j,1))+carry)
If Len(local_result$)=2 And Not(j=1) ; if j=1 this is the 1st digit so carry can stay as it is
carry=Val(Mid(local_result$,1,1))
local_result$=Mid(local_result$,2,1)
Else
carry=0
EndIf
temp_result$=local_result$+temp_result$
Next j
temp_result$=LSet(temp_result$,Len(temp_result$)+size-i,"0")
;PrintN("temp_result$:"+temp_result$)
line_result$=Add(line_result$,temp_result$)
;PrintN("line_result$:"+line_result$)
Next i
result$=line_result$
ProcedureReturn result$
EndProcedure
;compare function returns 0 if myn1>n2 and 1 if n2>n1
;it pads the smaller number with leading 0s
;it removes any leading 0s in the original input
;the numbers obtained after a compare are suitable for any mathematical operation now
num1$="00000000000005000"
num2$="000020"
OpenConsole()
PrintN ("num1$=" +num1$ + ";num2$=" + num2$)
;Compare (num1$,num2$)
;Result$= Add(n1$,n2$)
;PrintN ("Result::"+Str(result))
result$=Multiply(num1$,num2$)
PrintN ("Multiply::"+result$)
Input()
num2$=num1$
num1$=result$
num1=Len(num1$)
num2=Len(num2$)
;PrintN (num1$+"::"+num2$)
result$=Add(num1$,num2$)
PrintN ("addition::"+result$)
;PrintN (Str(Val("00100")))
;we compute 100! now
fact$="1"
For i=1 To 100
fact$=Multiply(fact$,Str(i))
Next i
Input()
CloseConsole()