Big Integer Maths

Modified on 2016/12/23 23:20 by Administrator — Categorized as: Maths, _LIB Original MMBasic

This module is part of the original MMBasic library. It is reproduced here with kind permission of Hugh Buckle and Geoff Graham. Be aware it may reference functionality which has changed or is deprecated in the latest versions of MMBasic.

Note: Any required file(s) are available in the attachments tab (top right).

' integer maths by TassyJim 07 Feb 2012

' MM Basic CAN do big integer maths!

' The included code uses integer maths to calculate
' 1, 1×2, 1×2×3, 1×2×3×4, etc. the successive factorial numbers.
' The limit in MM Basic is the length of a string or 255 digits.
' At this stage, only positive integers are allowed as inputs.
' This code is SLOW and I have not made any attempt to speed it up.
' Working in base 1000 (3 digits at a time) is the obvious way to
' gain speed but this exercise was a proof of concept rather than good code.
' I know a lot more about MM Basic subroutine now!
' It needs MM Basic V3.1 as it uses user defined subroutines.
' Converting to gosubs and line numbers is a task for someone else.

' Now I need to go the next step and allow negative numbers as inputs. 

a$ = "13"
For i = 0 To 15 ' demo of the four operations
    add( a$ , Str$( i ),res$ )
    Print a$;" + ";i;" = ";res$
    min( a$ , Str$( i ),res$ )
    Print a$;" - ";i;" = ";res$
    multy( a$ , Str$( i ),res$ )
    Print a$;" * ";i;" = ";res$
    div( a$ , Str$( i ),res$ )
    Print a$;" / ";i;" = ";res$
    Print
Next i

a$="1"
For i = 1 To 55 ' printing up to factorial 55.
    b$=Str$(i)
    multy(a$, b$, res$)
    Print b$;"! = ";res$;"  (";len(res$);" )"
    a$=res$
Next i

End

Sub div( a$ , b$, c$ ) ' given a$ and b$, returns a/b in c$
    Local f, i, d, t, try$, nr$, a1$, b1$, a2$, z$
    a1$=a$ : b1$=b$ : c$="" ' make copies of a$ and b$ to preserve originals
    If Val( b$ ) = 0 Then   ' divide by zero
        c$ = "error"
    Else
        For i = Len( a1$ ) - Len( b1$ ) To 0 Step -1
            f = 0
            nr$ = "0"
            z$=String$(i,"0")
            For d = 0 To 9
                md( b1$ + z$ , d, try$ )
                big( a1$ , try$, t )
                If t Then
                    f = d
                    nr$ = try$
                EndIf
            Next d
            c$ = c$ + Str$( f )
            If f > 0 Then
                min( a1$ , nr$, a2$ )
                a1$ = a2$
            EndIf
        Next i
    EndIf
    trim (c$)
End Sub

Sub multy( a$ , b$, c$ ) ' given a$ and b$, returns the sum in c$
    Local i, h$, a1$, b1$, t$, d$, z$
    a1$=a$ : b1$=b$ : c$="" ' make copies of a$ and b$ to preserve originals
    If Len( b1$ ) > Len( a1$ ) Then ' swap number for greater speed
        h$ = a1$
        a1$ = b1$
        b1$ = h$
    EndIf
    For i = Len( a1$ ) To 1 Step -1
        z$=String$(Len( a1$ )-i,"0")
        md( b1$ , Val( Mid$( a1$ , i , 1 ) ) , t$)
        add( c$ , t$+ z$ ,d$)
        c$=d$
    Next i
    trim (c$)
End Sub

Sub md( a$ ,  nr, c$ ) ' multiply a$ by a single digit, result in c$
    Local hold, carry, i
    carry = 0 : c$=""
    For i = Len( a$ ) To 1 Step -1
        hold = Val( Mid$( a$ , i , 1 ) ) * nr + carry
        carry = Int( hold / 10 )
        c$ = Str$( hold Mod 10 ) + c$
    Next i
    If carry > 0 Then c$ = Str$( carry ) + c$
End Sub

Sub samelen (a$, b$) ' pads the shorter variable with leading zeros
    dif=Abs(Len( a$ )-Len( b$ ))
    If dif>0 Then
        z$=String$(dif,"0")
        If Len( a$ ) < Len( b$ ) Then
            a$ = z$+a$
        Else
            b$ = z$+b$
        EndIf
    EndIf
End Sub

Sub add( a$ , b$, c$ ) ' given a$ and b$, returns the sum in c$
    Local carry, hold, i,a1$, b1$
    c$="" : a1$=a$ : b1$=b$
    samelen a1$ , b1$
    For i = Len( a1$ ) To 1 Step -1
        hold = Val( Mid$( a1$ , i , 1 ) ) + Val( Mid$( b1$ , i , 1 ) ) + carry
        carry = Int( hold / 10 )
        x$=Str$( hold Mod 10 )
        c$ = Right$( x$,1) + c$
    Next i
    If carry > 0 Then c$ = Str$( carry ) + c$
End Sub

Sub min( a$ , b$, c$ ) ' given a$ and b$, returns the difference in c$
    Local a1$, b1$, h$, i, hold, borrow
    c$="" : s$="" :a1$=a$ : b1$=b$ ' initialise variables and preserve a$ and b$
    samelen a1$ , b1$
    If a1$<b1$ Then ' if result is going to be negative, swap a1 & b1
        h$ = a1$
        a1$ = b1$
        b1$ = h$
        s$="-"
    EndIf
    For i = Len( a1$ ) To 1 Step -1
        hold = Val( Mid$( a1$ , i , 1 ) ) - Val( Mid$( b1$ , i , 1 ) ) + 10 - borrow
        borrow = 1- Int( hold / 10 )
        c$ = Str$( hold Mod 10 ) + c$
    Next i
    trim c$
    c$ = s$+c$ ' add the sign
End Sub

Sub big( a$, b$, biggest ) ' biggest = 1 if a$ >= b$
    Local a1$, b1$      'preserve a$ and b$
    a1$ = a$ : b1$ = b$
    biggest = 0
    samelen (a1$ , b1$)
    If a1$>=b1$ Then biggest = 1
End Sub

Sub trim (a$) ' given a$, leading zeros are stripped. a$ is altered.
    Local s$
    s$=""
    If Left$(a$,1)="-" Then ' if the number is negative, preserve the sign
        s$="-"
        a$=Mid$(a$,2)
    EndIf
    Do While Left$(a$,1)="0" ' strip leading characters while they are "0"
        a$=Mid$(a$,2)
    Loop
    If a$="" Then a$="0"
    a$=s$+a$ ' replace the sign
End Sub