Long String Division?

Just starting out? Need help? Post your questions and find answers here.
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

Long String Division?

Post by matalog »

Has anyone written a program to divide 2 long numbers contained in strings?

This program allows one long string of any length, which can be divided by an integer.

Code: Select all

Debug "Long Intger Division"
k$="12345678987654321234567890987654321"
d=123456789
a$=""
i=1
t=Val (Mid(k$,i,1))
back:
While t<d
  t=t*10+Val (Mid(k$,i+1,1))
  i=i+1
Wend
i=i+1
While Len (k$)>i-1
  a$=a$+Str(Int (t/d))
  t=(t-d*Int (t/d))*10+Val (Mid(k$,i,1))
  i=i+1
Wend
i=i+1
a$=a$+Str (Int (t/d))
Debug a$
How different would a 2 long string division program have to be?
firace
Addict
Addict
Posts: 947
Joined: Wed Nov 09, 2011 8:58 am

Re: Long String Division?

Post by firace »

The below code (based on a very old forum post) is for multiplication.
Perhaps it can easily be adapted to division? Not sure.

Code: Select all

Procedure.s MultiplyBigHelper(factor_1$, factor_2$)   ;;  Helle 2007!
  
  Protected n.l,len_factor_1.l,len_factor_2.l
  
  len_factor_1=Len(factor_1$)
  len_factor_2=Len(factor_2$)
  If len_factor_2>len_factor_1 ;make it so larger# is always factor_1
    Swap factor_1$,factor_2$
    Swap len_factor_1,len_factor_2
  EndIf
  n=len_factor_1
  
  Protected n_2.l=n*2
  Protected Dim factor_1.l(n)
  Protected Dim factor_2.l(n)
  Protected Dim prod.l(n_2)
  Protected Prod$,I.l,J.l,s.l,temp.l
  
  For I = 1 To n ;convert #'s
    factor_1(I) = Val(Mid(factor_1$,I,1))
  Next I
  
  For I = n - len_factor_2 + 1 To n ;convert #'s
    factor_2(I) = Val(Mid(factor_2$,I + len_factor_2 - n,1))
  Next I 
  
  For I = n - len_factor_2 + 1 To n ;digit# for factor_1
    For J = n To 1 Step -1          ;digit# for factor_2
      prod(I + J) + factor_1(J) * factor_2(I)
    Next J
  Next I
  
  For I = n_2 To 1 Step -1 ;digits# of product
    temp=Int(prod(I) / 10) ;=carry
    prod(I - 1) + temp     ;add to next place value
    prod(I) - 10 * temp    ;subtract from previous place value
  Next I
  
  For I = 1 To n_2 ;digits# of product
    If prod(I) >0  ;find first non-zero digit
      Break
    EndIf
  Next I
  
  If FindString(factor_1$,"-",1) ;get sign of factor_1
    s=1
  EndIf
  
  If FindString(factor_2$,"-",1) ;combine with sign of factor_2
    s ! 1
  EndIf
  
  If s=1  ;=sign will be negative
    Prod$="-"
  EndIf
  
  For J = I To n_2 ;digits# of product
    Prod$ + Str(prod(J))
  Next J
  
  ProcedureReturn Prod$
EndProcedure

Procedure.s MultiplyBig(f1$, f2$)
  P$=MultiplyBigHelper(RemoveString(F1$, "."), RemoveString(F2$, "."))
  
  If FindString(F1$, ".")
    howmanydigitsafterpoint1 = Len(F1$) - FindString(F1$, ".")
  Else
    howmanydigitsafterpoint1 = 0
  EndIf 
  
  If FindString(F2$, ".")
    howmanydigitsafterpoint2 = Len(F2$) - FindString(F2$, ".")
  Else
    howmanydigitsafterpoint2 = 0
  EndIf 
  
  leftpart$  = Left(p$, Len(p$) - (howmanydigitsafterpoint1+howmanydigitsafterpoint2))
  rightpart$ = RTrim (Right(p$,   (howmanydigitsafterpoint1+howmanydigitsafterpoint2)), "0")
  If rightpart$ = "" : rightpart$ = "0" : EndIf 
  
  p$ = leftpart$ +  "." + rightpart$
  
  ProcedureReturn p$
EndProcedure   



;; EXAMPLE
N1$= "42.0510000000000"
N2$= "3.00000040008287"

Debug MultiplyBig(N1$, N2$)
firace
Addict
Addict
Posts: 947
Joined: Wed Nov 09, 2011 8:58 am

Re: Long String Division?

Post by firace »

Ah, this module seems to handle division too (didn't test):

https://www.purebasic.fr/english/viewtopic.php?t=61309
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

Re: Long String Division?

Post by matalog »

firace wrote: Sat Aug 10, 2024 2:10 pm Ah, this module seems to handle division too (didn't test):

https://www.purebasic.fr/english/viewtopic.php?t=61309
Thanks, it doesn't handle enough digits, they are not stored as strings, and the numbers overflow when too big.
TassyJim
Enthusiast
Enthusiast
Posts: 189
Joined: Sun Jun 16, 2013 6:27 am
Location: Tasmania (Australia)

Re: Long String Division?

Post by TassyJim »

This was written for a different Basic but should convert easily.
Strings were restricted to 255 characters and the only numbers are single precision floats which limits the original.
Hopefully, my comments from 2012 are good enough.

Code: Select all

' integer maths by TassyJim 07 Feb 2012
a$ = "13"
For i = 0 To 15 ' demo of the four operations
    add( a$ , Str$( i ),res$ )
    Print a$;" + ";i;" = ";res$
    minus( 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 biggest( a1$ , try$ ) Then
                    f = d
                    nr$ = try$
                EndIf
            Next d
            c$ = c$ + Str$( f )
            If f > 0 Then
                minus( a1$ , nr$, a2$ )
                a1$ = a2$
            EndIf
        Next i
    EndIf
    c$=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
    c$=trim$(d$)
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$ ))
    z$=String$(dif,"0")
    If Len( a$ ) < Len( b$ ) Then
        a$ = z$+a$
    Else
        b$ = z$+b$
    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 minus( 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
    c$=trim$(c$)
    c$ = s$+c$ ' add the sign
End Sub

function biggest( a$, b$) ' 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 function

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

Code: Select all

; integer maths by TassyJim 07 Feb 2012

Procedure.s md( a$ ,  nr ) ; multiply a$ by a single digit, result in c$
  Protected 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( Mod(hold,10) ) + c$
  Next i
  If carry > 0 
    c$ = Str( carry ) + c$
  EndIf
  ProcedureReturn c$
  EndProcedure

  Procedure.s trimit(a$) ; given a$, leading zeros are stripped. a$ is altered.
    Protected s$, a1$
    
    s$="" :a1$=a$
    If Left(a$,1)="-" ; if the number is negative, preserve the sign
      s$="-"
      a1$=Mid(a1$,2)
    EndIf
    Repeat
      If Left(a1$,1)="0" ; strip leading characters while they are "0"
        a1$=Mid(a1$,2)
      EndIf
    Until Left(a1$,1)<>"0"
    If a1$="" 
      a1$="0"
    EndIf
    t$=s$+a1$ ; replace the sign
    ProcedureReturn t$
  EndProcedure

Procedure.s samelen (a$, b$) ; pads the shorter variable with leading zeros
  dif=Abs(Len( a$ )-Len( b$ ))
  z$=Space(dif)
  z$ = ReplaceString(z$," ","0")
  If Len( a$ ) < Len( b$ )
    c$ = z$+a$
  Else
    c$ = a$
  EndIf
  ProcedureReturn c$
EndProcedure

Procedure biggest( a$, b$) ; biggest = 1 if a$ >= b$
  Protected a1$, b1$       ;preserve a$ and b$
  a1$ = a$ : b1$ = b$
  a1$ = samelen(a1$ , b1$)
  b1$ = samelen(b1$ , a1$)
  If a1$>=b1$ 
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure.s add( a$ , b$ ) ; given a$ and b$, returns the sum in c$
  Protected carry, hold, i,a1$, b1$
  c$="" : a1$=a$ : b1$=b$
  a1$ = samelen(a1$ , b1$)
  b1$ = samelen(b1$ , a1$)
  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( Mod(hold,10 ))
    c$ = Right( x$,1) + c$
  Next i
  If carry > 0 
    c$ = Str( carry ) + c$
    EndIf
    ProcedureReturn c$
  EndProcedure

  Procedure.s minus( a$ , b$ ) ; given a$ and b$, returns the difference in c$
    Protected a1$, b1$, h$, i, hold, borrow, c$
    c$="" : s$="" :a1$=a$ : b1$=b$ ; initialise variables and preserve a$ and b$
    a1$ = samelen(a1$ , b1$)
    b1$ = samelen(b1$ , a1$)
    If a1$<b1$ ; 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( Mod(hold,10 )) + c$
    Next i
    c$=trimit(c$)
    c$ = s$+c$ ; add the sign
    ProcedureReturn c$
  EndProcedure
  
Procedure.s div( a$ , b$ ) ; given a$ and b$, returns a/b in c$
  Protected f, i, d, t, try$, nr$, a1$, b1$, a2$, z$, c$
  a1$=a$ : b1$=b$ : c$="" ; make copies of a$ and b$ to preserve originals
  If Val( b$ ) = 0        ; divide by zero
    c$ = "error"
  Else
    For i = Len( a1$ ) - Len( b1$ ) To 0 Step -1
      f = 0
      nr$ = "0"
      z$=Space(i)
      z$ = ReplaceString(z$," ","0")
      For d = 0 To 9
        try$ = md( b1$ + z$ , d )
        ;big( a1$ , try$, t )
        If biggest( a1$ , try$ ) 
          f = d
          nr$ = try$
        EndIf
      Next d
      c$ = c$ + Str( f )
      If f > 0 
        a2$ = minus( a1$ , nr$ )
        a1$ = a2$
      EndIf
    Next i
  EndIf
  c$=trimit(c$)
  ProcedureReturn c$
EndProcedure

Procedure.s multy( a$ , b$ ) ; given a$ and b$, returns the sum in c$
  Protected i, h$, a1$, b1$, t$, d$, z$, c$
  a1$=a$ : b1$=b$ : c$="" ; make copies of a$ and b$ to preserve originals
  If Len( b1$ ) > Len( a1$ )  ; swap number for greater speed
    h$ = a1$
    a1$ = b1$
    b1$ = h$
  EndIf
  For i = Len( a1$ ) To 1 Step -1
    z$=Space(Len( a1$ )-i)
    z$ = ReplaceString(z$," ","0")
    
    t$ = md( b1$ , Val( Mid( a1$ , i , 1 ) ))
    d$ = add( c$ , t$+ z$ )
    c$=d$
  Next i
  c$=trimit(d$)
  ProcedureReturn c$
  
EndProcedure
 
  a$ = "13"
  For i = 0 To 15 ; demo of the four operations
    res$ = add( a$ , Str( i ) )
    Debug a$+" + "+Str(i)+" = "+res$
    res$ = minus( a$ , Str( i ) )
    Debug a$+" - "+Str(i)+" = "+res$
    res$ = multy( a$ , Str( i ) )
    Debug a$+" * "+Str(i)+" = "+res$
    res$ = div( a$ , Str( i ) )
    Debug a$+" / "+Str(i)+" = "+res$

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

Jim
User avatar
matalog
Enthusiast
Enthusiast
Posts: 305
Joined: Tue Sep 05, 2017 10:07 am

Re: Long String Division?

Post by matalog »

TassyJim wrote: Sat Aug 10, 2024 10:38 pm Converted to PureBasic without any tidying up

Code: Select all

; integer maths by TassyJim 07 Feb 2012

Procedure.s md( a$ ,  nr ) ; multiply a$ by a single digit, result in c$
  Protected 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( Mod(hold,10) ) + c$
  Next i
  If carry > 0 
    c$ = Str( carry ) + c$
  EndIf
  ProcedureReturn c$
  EndProcedure

  Procedure.s trimit(a$) ; given a$, leading zeros are stripped. a$ is altered.
    Protected s$, a1$
    
    s$="" :a1$=a$
    If Left(a$,1)="-" ; if the number is negative, preserve the sign
      s$="-"
      a1$=Mid(a1$,2)
    EndIf
    Repeat
      If Left(a1$,1)="0" ; strip leading characters while they are "0"
        a1$=Mid(a1$,2)
      EndIf
    Until Left(a1$,1)<>"0"
    If a1$="" 
      a1$="0"
    EndIf
    t$=s$+a1$ ; replace the sign
    ProcedureReturn t$
  EndProcedure

Procedure.s samelen (a$, b$) ; pads the shorter variable with leading zeros
  dif=Abs(Len( a$ )-Len( b$ ))
  z$=Space(dif)
  z$ = ReplaceString(z$," ","0")
  If Len( a$ ) < Len( b$ )
    c$ = z$+a$
  Else
    c$ = a$
  EndIf
  ProcedureReturn c$
EndProcedure

Procedure biggest( a$, b$) ; biggest = 1 if a$ >= b$
  Protected a1$, b1$       ;preserve a$ and b$
  a1$ = a$ : b1$ = b$
  a1$ = samelen(a1$ , b1$)
  b1$ = samelen(b1$ , a1$)
  If a1$>=b1$ 
    ProcedureReturn 1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure.s add( a$ , b$ ) ; given a$ and b$, returns the sum in c$
  Protected carry, hold, i,a1$, b1$
  c$="" : a1$=a$ : b1$=b$
  a1$ = samelen(a1$ , b1$)
  b1$ = samelen(b1$ , a1$)
  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( Mod(hold,10 ))
    c$ = Right( x$,1) + c$
  Next i
  If carry > 0 
    c$ = Str( carry ) + c$
    EndIf
    ProcedureReturn c$
  EndProcedure

  Procedure.s minus( a$ , b$ ) ; given a$ and b$, returns the difference in c$
    Protected a1$, b1$, h$, i, hold, borrow, c$
    c$="" : s$="" :a1$=a$ : b1$=b$ ; initialise variables and preserve a$ and b$
    a1$ = samelen(a1$ , b1$)
    b1$ = samelen(b1$ , a1$)
    If a1$<b1$ ; 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( Mod(hold,10 )) + c$
    Next i
    c$=trimit(c$)
    c$ = s$+c$ ; add the sign
    ProcedureReturn c$
  EndProcedure
  
Procedure.s div( a$ , b$ ) ; given a$ and b$, returns a/b in c$
  Protected f, i, d, t, try$, nr$, a1$, b1$, a2$, z$, c$
  a1$=a$ : b1$=b$ : c$="" ; make copies of a$ and b$ to preserve originals
  If Val( b$ ) = 0        ; divide by zero
    c$ = "error"
  Else
    For i = Len( a1$ ) - Len( b1$ ) To 0 Step -1
      f = 0
      nr$ = "0"
      z$=Space(i)
      z$ = ReplaceString(z$," ","0")
      For d = 0 To 9
        try$ = md( b1$ + z$ , d )
        ;big( a1$ , try$, t )
        If biggest( a1$ , try$ ) 
          f = d
          nr$ = try$
        EndIf
      Next d
      c$ = c$ + Str( f )
      If f > 0 
        a2$ = minus( a1$ , nr$ )
        a1$ = a2$
      EndIf
    Next i
  EndIf
  c$=trimit(c$)
  ProcedureReturn c$
EndProcedure

Procedure.s multy( a$ , b$ ) ; given a$ and b$, returns the sum in c$
  Protected i, h$, a1$, b1$, t$, d$, z$, c$
  a1$=a$ : b1$=b$ : c$="" ; make copies of a$ and b$ to preserve originals
  If Len( b1$ ) > Len( a1$ )  ; swap number for greater speed
    h$ = a1$
    a1$ = b1$
    b1$ = h$
  EndIf
  For i = Len( a1$ ) To 1 Step -1
    z$=Space(Len( a1$ )-i)
    z$ = ReplaceString(z$," ","0")
    
    t$ = md( b1$ , Val( Mid( a1$ , i , 1 ) ))
    d$ = add( c$ , t$+ z$ )
    c$=d$
  Next i
  c$=trimit(d$)
  ProcedureReturn c$
  
EndProcedure
 
  a$ = "13"
  For i = 0 To 15 ; demo of the four operations
    res$ = add( a$ , Str( i ) )
    Debug a$+" + "+Str(i)+" = "+res$
    res$ = minus( a$ , Str( i ) )
    Debug a$+" - "+Str(i)+" = "+res$
    res$ = multy( a$ , Str( i ) )
    Debug a$+" * "+Str(i)+" = "+res$
    res$ = div( a$ , Str( i ) )
    Debug a$+" / "+Str(i)+" = "+res$

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

Jim
That's great Jim, thanks. If you add x zeroes at the end of a$ before division, then you get x digits after the decimal point in the division instead of only integer.
Post Reply