Author Topic: String Math  (Read 18647 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #60 on: June 14, 2021, 08:58:55 pm »
Thanks @jack

BTW you mentioned you did not understand my nInverse$(), as I recall I coded it as I learned to do division in school only we are just dividing into 1 so we are always adding 0's to remainder until big enough to divide some more by denominator and find another set of remainder start digits upon which to add zeros... maybe you figured it out already.

This String Math will have to do until you or George or Luke get a full set of operations going with memory works or with decimal math segments building.

Offline david_uwi

  • Newbie
  • Posts: 71
    • View Profile
Re: String Math
« Reply #61 on: June 16, 2021, 02:17:18 pm »
I am always confused when calculation that gives a large number of digits is generally tackled by using strings.
It seems obvious that you could store the digits in an array (rather than a string) which would avoid the VAL and STR$ which are slow.
Calculating the 115 Fibonacci is trivial even doing it the hard way of going through all the numbers 11235...to get to the 115 number. I've posted it before (but as I'm very proud of it) I will post it again.
Code: QB64: [Select]
  1. DIM a(30000) AS INTEGER, b(30000) AS INTEGER
  2. DEFLNG F-I
  3. DEFINT J-N
  4. INPUT "input the fibonacci number to calculate"; fmax
  5. tt = TIMER
  6. b(1) = 1: n = 1
  7. FOR i = 1 TO (fmax + 1) \ 2
  8.     FOR j = 1 TO n
  9.         b(j) = a(j) + b(j) + jc
  10.         IF b(j) > 9999 THEN b(j) = b(j) - 10000: jc = 1 ELSE jc = 0
  11.     NEXT j
  12.     IF jc = 1 THEN n = n + 1: b(n) = 1: jc = 0
  13.     FOR j = 1 TO n
  14.         a(j) = a(j) + b(j) + jc
  15.         IF a(j) > 9999 THEN a(j) = a(j) - 10000: jc = 1 ELSE jc = 0
  16.     NEXT j
  17.     IF jc = 1 THEN n = n + 1: a(n) = 1: jc = 0
  18. FOR j = n TO 1 STEP -1
  19.     IF fmax MOD 2 = 0 THEN
  20.         IF j = n THEN t$ = LTRIM$(STR$(a(j))) ELSE t$ = RIGHT$("0000" + LTRIM$(STR$(a(j))), 4)
  21.         PRINT USING "&"; t$;
  22.     END IF
  23.     IF fmax MOD 2 = 1 THEN
  24.         IF j = n THEN t$ = LTRIM$(STR$(b(j))) ELSE t$ = RIGHT$("0000" + LTRIM$(STR$(b(j))), 4)
  25.         PRINT USING "&"; t$;
  26.     END IF
  27. PRINT: PRINT "number of digits = ";
  28. IF fmax MOD 2 = 1 THEN PRINT (n - 1) * 4 + LEN(LTRIM$(STR$(a(n))))
  29. IF fmax MOD 2 = 0 THEN PRINT (n - 1) * 4 + LEN(LTRIM$(STR$(b(n))))
  30. PRINT "TIME TAKEN= "; TIMER - tt; "SECONDS"

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #62 on: June 16, 2021, 03:23:14 pm »
I am always confused when calculation that gives a large number of digits is generally tackled by using strings.
It seems obvious that you could store the digits in an array (rather than a string) which would avoid the VAL and STR$ which are slow.
Calculating the 115 Fibonacci is trivial even doing it the hard way of going through all the numbers 11235...to get to the 115 number. I've posted it before (but as I'm very proud of it) I will post it again.
Code: QB64: [Select]
  1. DIM a(30000) AS INTEGER, b(30000) AS INTEGER
  2. DEFLNG F-I
  3. DEFINT J-N
  4. INPUT "input the fibonacci number to calculate"; fmax
  5. tt = TIMER
  6. b(1) = 1: n = 1
  7. FOR i = 1 TO (fmax + 1) \ 2
  8.     FOR j = 1 TO n
  9.         b(j) = a(j) + b(j) + jc
  10.         IF b(j) > 9999 THEN b(j) = b(j) - 10000: jc = 1 ELSE jc = 0
  11.     NEXT j
  12.     IF jc = 1 THEN n = n + 1: b(n) = 1: jc = 0
  13.     FOR j = 1 TO n
  14.         a(j) = a(j) + b(j) + jc
  15.         IF a(j) > 9999 THEN a(j) = a(j) - 10000: jc = 1 ELSE jc = 0
  16.     NEXT j
  17.     IF jc = 1 THEN n = n + 1: a(n) = 1: jc = 0
  18. FOR j = n TO 1 STEP -1
  19.     IF fmax MOD 2 = 0 THEN
  20.         IF j = n THEN t$ = LTRIM$(STR$(a(j))) ELSE t$ = RIGHT$("0000" + LTRIM$(STR$(a(j))), 4)
  21.         PRINT USING "&"; t$;
  22.     END IF
  23.     IF fmax MOD 2 = 1 THEN
  24.         IF j = n THEN t$ = LTRIM$(STR$(b(j))) ELSE t$ = RIGHT$("0000" + LTRIM$(STR$(b(j))), 4)
  25.         PRINT USING "&"; t$;
  26.     END IF
  27. PRINT: PRINT "number of digits = ";
  28. IF fmax MOD 2 = 1 THEN PRINT (n - 1) * 4 + LEN(LTRIM$(STR$(a(n))))
  29. IF fmax MOD 2 = 0 THEN PRINT (n - 1) * 4 + LEN(LTRIM$(STR$(b(n))))
  30. PRINT "TIME TAKEN= "; TIMER - tt; "SECONDS"

So what do you get for first 10,000 digit Fibonacci?

I get:
 
10000 digit fibonacci.PNG

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #63 on: June 16, 2021, 03:32:00 pm »
Is fast!
 
david_uwi 10000.PNG


But I never claimed to be faster, just a set of routines in about 412 LOC to extend math beyond Type restrictions of QB64.

Update: for the record, String Math took 21.1692 secs to get to 47,847th term, the first at 10,000 digits.

@david_uwi also for the record we are getting Fibonacci sequence of 115 terms from inverse of STx Number:
"999999999999999999999998999999999999999999999999"
which is so much cooler than merely adding up a bunch of terms.

If you get a whole set of routines in a fair amount of LOC then I will gladly swap out String Math routines in NY minute!

If someone needs something now, here it is, slow as it may be. :)
« Last Edit: June 16, 2021, 03:55:06 pm by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #64 on: June 16, 2021, 04:42:44 pm »
hi bplus
try the reciprocal of 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
it requires about 38,709 digits and gives 432 Fibo numbers starting with 0
here's pseudo code to produce them
Code: [Select]
s$=string$(89,"9")+"8"+string(90,"9")
z$=nInverse(s$)
j=instr(z$,".")
s$=mid(z$,j+1)
j=1
for i=1 to 432
print mid$(s,j,90)
j=j+90
next

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #65 on: June 16, 2021, 04:46:38 pm »
@jack  cool! thanks :)

Confirmed:
Counting 0 as first, 432 terms found the last starts at 38792. I had to increase my number of decimals to 39000 from what I tried the first time, probably not minimum needed to find the 432 terms. 6.81 mins was the time for last run.
« Last Edit: June 16, 2021, 06:25:28 pm by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #66 on: June 16, 2021, 07:42:07 pm »
Is fast!
1.7 seconds
that really fast for string math, well done bplus

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #67 on: June 16, 2021, 08:07:40 pm »
that really fast for string math, well done bplus

I wish, that was David's code I was saying his was fast. I did say later post 21 secs for String Math.

I don't think you will catch me initiating time trials with String Math :)

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #68 on: June 17, 2021, 03:58:03 pm »
hi bplus
I found this interesting document MULTIPLE-LENGTH DIVISION REVISITED

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: String Math
« Reply #69 on: June 17, 2021, 10:51:24 pm »
I read this 3 years ago when I came up with my division routine. It isn't exactly like this, but I got my idea from this paper.

@jack (Jack - I haven't forgotten about you, it is just that my finished division code isn't in the program file I have, and I am waiting to see if my friend has a copy. Either way I will send it to you tomorrow. If I have to rewrite the division code, I will at least send you the write up on how I coded it).


hi bplus
I found this interesting document MULTIPLE-LENGTH DIVISION REVISITED
____________________________________________________________________
George McGinn
Theoretical/Applied Computer Scientist
Member: IEEE, IEEE Computer Society
Technical Council on Software Engineering
IEEE Standards Association
American Association for the Advancement of Science (AAAS)

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #70 on: June 17, 2021, 11:02:08 pm »
thank you George

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #71 on: June 21, 2021, 10:12:19 am »
Hi bplus
I am still trying to get motivated to study division but as soon as I spend 1 minute reading I loose interest
anyway, in my decfloat routines I found to my disgust that if you take the reciprocal of a number consisting of a lot of 9's and then take the reciprocal of the resulting number, the convergence is very slow, for example
n$="99999999999999999999999999999999999999999999999999"
the inverse of that number is ".0000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001"
in sci notation it's 1.00000000000000000000000000000000000000000000000001 E-50
trying to do a reciprocal on that number to get back the original is not easy as there's no way to get a good first approximation, the Newon-Raphson method will eventually converge but it takes many iterations depending on the precision used
I tried it on your math-regulator and it returns .0000000.... instead of the original number
bplus, please explain how you handle big numbers in your nInverse function
« Last Edit: June 21, 2021, 11:42:08 am by jack »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #72 on: June 21, 2021, 05:47:21 pm »
Oh jack did you find another bug!? I will check it out when I get time.

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #73 on: June 21, 2021, 07:35:12 pm »
bplus, there was an old-timer that wrote a bignum package in visual basic 3 or there about, his website has vanished but you can still get his programs from the wayback machine https://web.archive.org/web/20200220020034/http://www.rain.org/~mkummel/tbvault.html
the package to get are bnc and bignum, there may be things in his code to learn from, who knows?

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #74 on: June 21, 2021, 08:19:16 pm »
hi bplus
I extracted the routines needed to do division from bignum, and it actually works
have not cleaned it up for unnecessary constants or variables
Code: QB64: [Select]
  1. 'BIGNUM.BAS v0.n
  2. 'Sep-Dec 1996 by Marc Kummel aka Treebeard.
  3. 'Contact mkummel@rain.org, http://www.rain.org/~mkummel/
  4. ' https://web.archive.org/web/20200220020034/http://www.rain.org/~mkummel/tbvault.html
  5.  
  6. 'Big number arithmetic routines, done with a crypto project in mind.  It's
  7. 'an engaging task to work out these algorithms in BASIC, since we know them
  8. 'so well on paper.  My aim is to minimize string space; then speed.  Not
  9. 'quite "arbitrary precision" since numbers and answer must fit in BASIC
  10. 'string space, 64K with PDS far strings, much less for QBasic.  Don't use
  11. 'the same string twice in one call!  bMul(s$,s$,s$) should figure s=s*s, but
  12. 'it won't work because passed strings are modified (and restored) during the
  13. 'call, so use temporary strings or pass by value.  See bModPower() for an
  14. 'example.  Can be much optimized, but it works and makes sense.
  15. '
  16. '---------------------------------------------------------------------------
  17.  
  18. 'useful globals
  19. Const false = 0, true = Not false, nada = -1
  20. Const zero$ = "0", one$ = "1", two$ = "2", three$ = "3"
  21. Const four$ = "4", five$ = "5"
  22. Const dp$ = ".", neg$ = "-", asc0 = 48
  23. Const basechr$ = "B", basesep$ = "," 'number bases
  24. Const negative = -1, positive = 1 'returned by bComp()
  25. Const maxlongdig = 8 'max digits in long var&
  26. Const maxsegment = 65536 'memory segment size
  27. Const memget = 0, memput = 1, memclr = 2 'memory operations
  28. Const maxstack = 10 'stack depth
  29. Const maxmem = 14 'memory slots (0-9 + constants)
  30. Const pimem = 10, pi2mem = 11, emem = 12 'pi, 2pi, e
  31. Const ln10mem = 13, ln2mem = 14 'natural logs of 10 & 2
  32.  
  33. 'useful shared stuff
  34. Dim Shared digits%
  35. Dim Shared topline%, botline%, topview%, botview%
  36. Dim Shared esc$, null$, error$, abort$
  37.  
  38. 'Trick to give bmem$() its own 64k segment in PDS (but not QB).
  39. 'Watch out for overflows or conflicts with multiple modules.
  40. Common bmem$(), zmem$(), cname$()
  41. Dim bmem$(maxmem), zmem$(1 To maxstack), cname$(10 To maxmem)
  42.  
  43. esc$ = Chr$(27) 'useful strings
  44. null$ = ""
  45. error$ = "error! " 'unhelpful error messages
  46. abort$ = "<abort>"
  47. op$ = "+" 'default action
  48. digits% = 100 'digits for division etc
  49. bignumpath$ = null$ 'path for files (or current dir if null)
  50. prmcntfile$ = "BNPRMCNT.DAT" 'prime count table
  51. logfile$ = "BNLOG.LOG" 'log file
  52. ReDim prmcnt&(0) 'stub for prime count table
  53.  
  54. 'useful constants
  55. cname$(pimem) = "ã": bmem$(pimem) = "3.14159265358979323846264338327"
  56. cname$(pi2mem) = "2ã": bmem$(pi2mem) = "6.28318530717958647692528676654"
  57. cname$(emem) = "e": bmem$(emem) = "2.71828182845904523536028747135"
  58. cname$(ln10mem) = "ln(10)": bmem$(ln10mem) = "2.30258509299404568401799145468"
  59. cname$(ln2mem) = "ln(2)": bmem$(ln2mem) = ".693147180559945309417232121458"
  60.  
  61. 'screen size and window
  62. topline% = 1
  63. botline% = 25
  64. topview% = topline%
  65. botview% = botline% - 2
  66.  
  67. 'screen buffer for ScreenSave() and ScreenRestore()
  68. screenbufsize% = 80 * botline% * 2 'screen size, 2 bytes per character
  69. Dim screenbuf%(screenbufsize% - 1) 'buffer
  70. screenrow% = 1 'cursor row
  71. Def Seg = 0 'video segment for mono or color
  72. If Peek(&H463) = &HB4 Then screenseg& = &HB000 Else screenseg& = &HB800 'color
  73.  
  74. 'trap ctrl-esc for emergency exit.  Speed and size hog, but useful.
  75. KEY 15, Chr$(4) + Chr$(1)
  76. 'On Key(15) GoSub EventTrap
  77. Key(15) On
  78.  
  79. 'start up
  80. View Print topview% To botview% 'text window
  81. Randomize Timer 'I'll make a better RND() sometime
  82. ' LoadPrimeTable                       'prime count table
  83. ' ShowHelp                             'something to look at
  84.  
  85. '========================================================================
  86. n$ = "1"
  87. m$ = "99999999999999999999999999999999999999999999999999"
  88.  
  89. r$ = ""
  90. Call bDiv(n$, m$, r$)
  91. m$ = r$ ' you can't use the destination variable in the source
  92. Call bDiv(n$, m$, r$)
  93. '========================================================================
  94.  
  95.  
  96. 's = |s|
  97. '
  98. Sub bAbs (s$)
  99.     If Left$(s$, 1) = neg$ Then s$ = Mid$(s$, 2)
  100.  
  101. 'return true if s is negative
  102. '
  103. Function bIsNeg% (s$)
  104.     bIsNeg% = (Left$(s$, 1) = neg$)
  105.  
  106. 'return sign of number (-1 or +1)
  107. '
  108. Function bSign% (s$)
  109.     If bIsNeg(s$) Then bSign% = negative Else bSign% = positive
  110.  
  111. 'Strip leading 0s and final "." (but leave something)
  112. '
  113. Sub bStripZero (s$)
  114.     n% = 1
  115.     Do While Mid$(s$, n%, 1) = zero$
  116.         n% = n% + 1
  117.     Loop
  118.     If n% > 1 Then s$ = Mid$(s$, n%)
  119.     If Right$(s$, 1) = dp$ Then s$ = Left$(s$, Len(s$) - 1)
  120.     If Len(s$) = 0 Then s$ = zero$
  121.  
  122. 'Strip trailing 0s to "." (but leave something)
  123. '
  124. Sub bStripTail (s$)
  125.     n% = Len(s$)
  126.     Do While Mid$(s$, n%, 1) = zero$
  127.         n% = n% - 1
  128.         If n% <= 1 Then Exit Do
  129.     Loop
  130.     If n% Then If Mid$(s$, n%, 1) = dp$ Then n% = n% - 1
  131.     s$ = Left$(s$, n%)
  132.     If Len(s$) = 0 Then s$ = zero$
  133.  
  134. 'Strip s$ to whole number and base 10 integer logarithm and sign.  Decimal
  135. 'point is implied after the first digit, and slog% counts places left or
  136. 'right.  bLogPut() reverses the process, and bLogDp() gives info on the
  137. 'decimals. Tricky, but it works and simplifies dividing and multipling.
  138. 'eg s$ -> s$ , slog%
  139. '  660 -> 66 ,  2     (6.6 * 10^ 2)    (or 660,2 if zeroflag%=false)
  140. '  6.6 -> 66 ,  0     (6.6 * 10^ 0)
  141. ' .066 -> 66 , -2     (6.6 * 10^-2)
  142. 'bDiv(), bMul(), and bSqr() use this to trim unnecessary zeros and to locate
  143. 'decimal point.  These set zeroflag% to trim trailing zeros, but bDivIntMod()
  144. 'must set it false in order to figure remainder of division.  A kludge.
  145. '
  146. Sub bLogGet (s$, slog%, sign%, zeroflag%)
  147.     If Left$(s$, 1) = neg$ Then s$ = Mid$(s$, 2): sign% = negative Else sign% = positive
  148.     bStripZero s$
  149.     dpt% = InStr(s$, dp$)
  150.     Select Case dpt%
  151.         Case 0
  152.             slog% = Len(s$) - 1
  153.         Case 1
  154.             n% = dpt% + 1
  155.             Do While Mid$(s$, n%, 1) = zero$
  156.                 n% = n% + 1
  157.             Loop
  158.             s$ = Mid$(s$, n%)
  159.             slog% = dpt% - n%
  160.         Case Else
  161.             s$ = Left$(s$, dpt% - 1) + Mid$(s$, dpt% + 1)
  162.             slog% = dpt% - 2
  163.     End Select
  164.  
  165.     'remove trailing 0's if zeroflag%
  166.     If zeroflag% Then bStripTail s$
  167.  
  168.  
  169. 'Strip a number to "standard form" with no leading or trailing 0s and no
  170. 'final "."  All routines should return all arguments in this form.
  171. '
  172. Sub bClean (s$)
  173.     If Left$(s$, 1) = neg$ Then s$ = Mid$(s$, 2): sign% = true
  174.     bStripZero s$
  175.     If InStr(s$, dp$) Then bStripTail s$
  176.     If sign% And s$ <> zero$ Then s$ = neg$ + s$
  177.  
  178. 'Restore a number from the integer and log figured in bLogGet(). s$ is taken
  179. 'as a number with the decimal after first digit, and decimal is moved slog%
  180. 'places left or right, adding 0s as required. Called by bDiv() and bMul().
  181. '
  182. Sub bLogPut (s$, slog%, sign%)
  183.     last% = Len(s$)
  184.     If Len(s$) = 0 Or s$ = zero$ Then
  185.         s$ = zero$
  186.     ElseIf slog% < 0 Then
  187.         s$ = dp$ + String$(-slog% - 1, zero$) + s$
  188.     ElseIf slog% > last% - 1 Then
  189.         s$ = s$ + String$(slog% - last% + 1, zero$) + dp$
  190.     Else
  191.         s$ = Left$(s$, slog% + 1) + dp$ + Mid$(s$, slog% + 2)
  192.     End If
  193.     bClean s$
  194.     If sign% = negative Then s$ = neg$ + s$
  195.  
  196. 'shift decimal n% digits (minus=left), i.e multiply/divide by 10.
  197. '
  198. Sub bShift (s$, n%)
  199.     bLogGet s$, slog%, sign%, false
  200.     bLogPut s$, slog% + n%, sign%
  201.  
  202. 's = -s
  203. '
  204. Sub bNeg (s$)
  205.     If Left$(s$, 1) = neg$ Then s$ = Mid$(s$, 2) Else s$ = neg$ + s$
  206.  
  207. 'Take whole number and log from bLogGet() and return number of decimal
  208. 'places in the expanded number; OR take string and number of decimal points
  209. 'desired and return the log.  It works both ways.
  210. '
  211. Function bLogDp% (s$, logdp%)
  212.     bLogDp% = Len(s$) - 1 - logdp%
  213.  
  214. 'out = s1 / s2 using fast long-integer algorithm. s2$ must be <= 8 digits.
  215. 's1$ and s2$ must be stripped first, no decimals.
  216. '
  217. Sub bDivLong (s1$, s2$, quotient$, remainder$)
  218.     quotient$ = null$
  219.     remainder& = 0
  220.     divisor& = Val(s2$)
  221.  
  222.     For i% = 1 To digits%
  223.         dividend& = remainder& * 10& + Val(Mid$(s1$, i%, 1))
  224.         dig% = dividend& \ divisor&
  225.         quotient$ = quotient$ + Chr$(asc0 + dig%)
  226.         remainder& = dividend& - dig% * divisor&
  227.     Next i%
  228.  
  229.     If Len(quotient$) = 0 Then quotient$ = zero$
  230.     remainder$ = LTrim$(Str$(remainder&))
  231.  
  232.  
  233. 'out = s1 / s2 using character algorithm, digit by digit, slow but honest.
  234. 's1$ and s2$ must be stripped first, no decimals.
  235. '
  236. Sub bDivChar (s1$, s2$, quotient$, remainder$)
  237.     last1% = Len(s1$) 'length of the dividend
  238.     last2% = Len(s2$) 'length of the divisor
  239.     quotient$ = null$
  240.     remainder$ = null$
  241.  
  242.     For i% = 1 To digits%
  243.         'get next digit of dividend or zero$ if past end
  244.         If i% <= last1% Then
  245.             dvd$ = remainder$ + Mid$(s1$, i%, 1)
  246.         Else
  247.             dvd$ = remainder$ + zero$
  248.         End If
  249.  
  250.         'if dividend < divisor then digit%=0 else have to calculate it.
  251.         'do fast compare using string operations. see bComp%()
  252.         bStripZero dvd$
  253.         ldvd% = Len(dvd$)
  254.         If (ldvd% < last2%) Or ((ldvd% = last2%) And (dvd$ < s2$)) Then
  255.             'divisor is bigger, so digit is 0, easy!
  256.             dig% = 0
  257.             remainder$ = dvd$
  258.  
  259.         Else
  260.             'dividend is bigger, but no more than 9 times bigger.
  261.             'subtract divisor until we get remainder less than divisor.
  262.             'time hog, average is 5 tries through j% loop.  There's a better way.
  263.             For dig% = 1 To 9
  264.                 remainder$ = null$
  265.                 borrow% = 0
  266.                 For j% = 0 To ldvd% - 1
  267.                     n% = last2% - j%
  268.                     If n% < 1 Then n% = 0 Else n% = Val(Mid$(s2$, n%, 1))
  269.                     n% = Val(Mid$(dvd$, ldvd% - j%, 1)) - n% - borrow%
  270.                     If n% >= 0 Then borrow% = 0 Else borrow% = 1: n% = n% + 10
  271.                     remainder$ = Chr$(asc0 + n%) + remainder$
  272.                 Next j%
  273.  
  274.                 'if remainder < divisor then exit
  275.                 bStripZero remainder$
  276.                 lrem% = Len(remainder$)
  277.                 If (lrem% < last2%) Or ((lrem% = last2%) And (remainder$ < s2$)) Then Exit For
  278.  
  279.                 dvd$ = remainder$
  280.                 ldvd% = Len(dvd$)
  281.             Next dig%
  282.  
  283.         End If
  284.         quotient$ = quotient$ + Chr$(asc0 + dig%)
  285.     Next i%
  286.  
  287.  
  288. 'out = s1 / s2
  289. '
  290. Sub bDiv (s1$, s2$, out$)
  291.  
  292.     'strip divisor
  293.     t$ = s2$
  294.     bLogGet t$, slog2%, sign2%, true
  295.  
  296.     'divide by zero?
  297.     If t$ = zero$ Then
  298.         out$ = error$
  299.  
  300.         'do powers of 10 with shifts
  301.     ElseIf t$ = one$ Then
  302.         out$ = s1$
  303.         sign1% = bSign(out$)
  304.         If sign1% = negative Then bAbs out$
  305.         bShift out$, -slog2%
  306.         If sign1% <> sign2% Then bNeg out$
  307.  
  308.         'the hard way
  309.     Else
  310.         'strip all
  311.         s2$ = t$: t$ = null$
  312.         bLogGet s1$, slog1%, sign1%, true
  313.  
  314.         'figure decimal point and sign of answer
  315.         outlog% = slog1% + bLogDp(s2$, slog2%)
  316.         If sign1% <> sign2% Then outsign% = negative Else outsign% = positive
  317.  
  318.         'bump digits past leading zeros and always show whole quotient
  319.         olddigits% = digits%
  320.         digits% = digits% + Len(s2$)
  321.         If digits% < outlog% + 1 Then digits% = outlog% + 1
  322.  
  323.         'do it, ignore remainder
  324.         If Len(s2$) <= maxlongdig Then bDivLong s1$, s2$, out$, t$ Else bDivChar s1$, s2$, out$, t$
  325.  
  326.         'clean up
  327.         bLogPut out$, outlog%, outsign%
  328.         bLogPut s1$, slog1%, sign1%
  329.         bLogPut s2$, slog2%, sign2%
  330.         digits% = olddigits%
  331.     End If
  332.  
  333.  
« Last Edit: June 21, 2021, 08:24:58 pm by jack »