Author Topic: String Math  (Read 15479 times)

0 Members and 1 Guest are viewing this topic.

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: String Math
« Reply #45 on: June 04, 2021, 09:46:15 am »
@jack

I ran it and it does give me the correct answer for SQR(100) where mine is having an issue where the decimals are being carried over (might be part of a subtraction problem in the Math Regulator, but not sure yet, and I did see your post about an issue with the subtraction function).

I am working on converting my n'th root function to string, unless you have one as well. I would test it out along side mine, as the issue I am having with my square root function I believe I will also have with my n'th root function.

@bplus it seems that you didn't bother to run the code I posted, instead you jump to conclusions.
but for completeness here my sqrt$ function that takes care of any exponential notation and is many times faster
Code: QB64: [Select]
  1. Function sqrt$ (n$)
  2.     Dim As String r, tmp, r2
  3.     Dim As Integer d, e, k, l
  4.     r = _Trim$(Str$(Sqr(Val(n$))))
  5.     d = InStr(r, "D")
  6.     If d > 0 Then
  7.         e = Val(Mid$(r, d + 1))
  8.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  9.         l = Len(r)
  10.         If e > 0 Then
  11.             r = r + String$(e - l + 1, "0")
  12.         ElseIf e < 0 Then
  13.             r = "0." + String$(Abs(e) - 1, "0") + r
  14.         End If
  15.     End If
  16.     For k = 1 To 3
  17.         tmp = mr$(r, "*", r)
  18.         tmp = mr$(tmp, "-", n$)
  19.         r2 = mr$(r, "+", r)
  20.         tmp = mr$(tmp, "/", r2)
  21.         r = mr$(r, "-", tmp)
  22.         If Len(r) > 101 Then r = Left$(r, 101)
  23.     Next k 'Loop Until Abs(Val(tmp)) < 1D-100
  24.     sqrt$ = r
  25.  
about 482 times faster
____________________________________________________________________
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 bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #46 on: June 04, 2021, 10:42:04 am »
@bplus it seems that you didn't bother to run the code I posted, instead you jump to conclusions.
...

@jack

I did run the code you provided in reply #33
https://www.qb64.org/forum/index.php?topic=2921.msg133047#msg133047

I suspected it would not work with numbers outside the range of doubles and floats so first I tried 100 with an even amount of zeros added on, I didn't count then but I double checked with 100 + 30 zeros a second time, then I ran a small number .0000000000000000000064 (that's suppose to be 20 zeroes between decimal and 64.

I posted my first results in reply #37
https://www.qb64.org/forum/index.php?topic=2921.msg133053#msg133053

Just to confirm what I saw yesterday I ran the code from reply #33 again this for sure 100 then 30 zeros and . 20-0's and 64
Again my functions takes a very long time but result looks correct and your function doesn't take a long time but results are do not look close to correct:
 
2nd run jacks code.PNG


I have not run the code that corrects for exponents (reply #43 posted this AM) because I am just getting to it now your sqr(2) times 10 to some hefty amount of even number (I assume by the answers) looks very impressive specially with time.

Please forget my comments in #37 I don't know what the heck you're doing in 3 iterations, let the screen shot of my test of your code speak for itself.
« Last Edit: June 04, 2021, 11:05:29 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #47 on: June 04, 2021, 10:48:57 am »
bplus, there's a bug in your subtract routine
Code: QB64: [Select]
  1. result$ = mr$(".00000000000000000000000000000000000000000000200000000000000054307978001764", "-", ".000000000000000000000000000000000000000000002")
  2. Print result$
  3.  
the outputit should be

Confirmed! thanks for heads up.

Apparently the Forum editor can only Quote one Quote box at a time.
« Last Edit: June 04, 2021, 11:15:26 am by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #48 on: June 04, 2021, 11:48:44 am »
here's your MR with nth root, but I there seem to problems with very big numbers, not sure it's due to a MR bug
there's a loss of precision with roots higher than 50
Code: QB64: [Select]
  1. _Title "Math regulator mr test sqr estimating" ' b+ start 2021-06-02
  2. ' divide$ found fix? 2021-06-03 comment in that function
  3. ' 2021-06-03 update with new sqrRoot$ Function
  4.  
  5. Randomize Timer 'now that it's seems to be running silent
  6. 'Screen _NewImage(1200, 700, 32)
  7. '_Delay .25
  8. '_ScreenMove _Middle
  9.     Sub memcpy (ByVal dest As _Offset, Byval source As _Offset, Byval bytes As Long)
  10.  
  11.  
  12. Dim n$, result$
  13. Dim t#
  14. 'Do
  15. '    'remember everything is strings
  16. '    Input "Enter a number to find it's square root "; n$
  17. '    If n$ = "" Then End
  18. '    t# = Timer
  19. '    result$ = sqrRoot$(n$)
  20. '    Print Timer - t#, result$
  21. '    t# = Timer
  22. '    result$ = sqrt$(n$)
  23. '    Print Timer - t#, result$
  24. '    Print "Length ="; Len(result$)
  25. '    Print
  26. 'Loop
  27. 'Print approx_power(x#, y#), x# ^ (1 / y#)
  28.  
  29. n$ = "2"
  30. t# = Timer
  31. result$ = approx_powers$(n$, 2)
  32. Print Timer - t#, result$
  33.  
  34. Function sqrRoot$ (nmbr$)
  35.     Dim n$, guess$, lastGuess$, other$, sum$, imaginary$
  36.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  37.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  38.     Else
  39.         imaginary$ = "": n$ = nmbr$
  40.     End If
  41.     guess$ = mr$(n$, "/", "2")
  42.     other$ = n$
  43.     Do
  44.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  45.             sqrRoot$ = Mid$(other$, 1, 101) + imaginary$
  46.             Exit Function
  47.         Else
  48.             lastGuess$ = guess$
  49.             sum$ = mr$(guess$, "+", other$)
  50.             guess$ = mr$(sum$, "/", "2")
  51.             other$ = mr$(n$, "/", guess$)
  52.         End If
  53.     Loop
  54.  
  55. Function ipower# (x As Double, e As Integer)
  56.     'take x to an integer power
  57.     Dim As Double z, y
  58.     Dim As Integer n
  59.     y = x
  60.     n = Abs(e)
  61.     z = 1#
  62.     While n > 0
  63.         While (n Mod 2) = 0
  64.             n = n \ 2
  65.             y = y * y
  66.         Wend
  67.         n = n - 1
  68.         z = y * z
  69.     Wend
  70.     If e < 0 Then
  71.         ipower = 1# / z
  72.     Else
  73.         ipower = z
  74.     End If
  75.  
  76. Function approx_power# (x#, y#)
  77.     Dim As Double a, b
  78.     Dim As Long tmp
  79.     a = x#: b = 1# / y#
  80.     memcpy _Offset(tmp), _Offset(a) + 4, 4
  81.     tmp = (tmp - 1072632447) * b
  82.     tmp = tmp + 1072632447
  83.     memcpy _Offset(a) + 4, _Offset(tmp), 4
  84.     a = a - (ipower(a, y#) - x#) / (y# * ipower(a, y# - 1))
  85.     a = a - (ipower(a, y#) - x#) / (y# * ipower(a, y# - 1))
  86.     a = a - (ipower(a, y#) - x#) / (y# * ipower(a, y# - 1))
  87.     a = a - (ipower(a, y#) - x#) / (y# * ipower(a, y# - 1))
  88.     approx_power = a
  89.  
  90. Function ipow$ (x As String, e As Integer)
  91.     'take x to an integer power
  92.     Dim As String z, y
  93.     Dim As Integer n
  94.     y = x
  95.     n = Abs(e)
  96.     z = "1"
  97.     While n > 0
  98.         While (n Mod 2) = 0
  99.             n = n \ 2
  100.             y = mr$(y, "*", y)
  101.             If Len(y) > 101 Then y = Left$(y, 101)
  102.         Wend
  103.         n = n - 1
  104.         z = mr$(y, "*", z)
  105.         If Len(z) > 101 Then z = Left$(z, 101)
  106.     Wend
  107.     If e < 0 Then
  108.         ipow = mr$("1", "/", z)
  109.     Else
  110.         ipow = z
  111.     End If
  112.  
  113. Function approx_powers$ (x$, y%)
  114.     Dim As Double a, b
  115.     Dim As Integer d, e, k, l
  116.     Dim As String r, r2, temp, ys
  117.     a = Val(x$): b = y%
  118.     a = approx_power#(a, b)
  119.     r = _Trim$(Str$(a))
  120.     d = InStr(r, "D")
  121.     If d > 0 Then
  122.         e = Val(Mid$(r, d + 1))
  123.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  124.         l = Len(r)
  125.         If e > 0 Then
  126.             r = r + String$(e - l + 1, "0")
  127.         ElseIf e < 0 Then
  128.             r = "0." + String$(Abs(e) - 1, "0") + r
  129.         End If
  130.     End If
  131.     ys = _Trim$(Str$(y%))
  132.     For k = 1 To 3
  133.         temp = ipow$(r, y%)
  134.         temp = mr$(temp, "-", x$)
  135.         r2 = ipow$(r, y% - 1)
  136.         r2 = mr$(ys, "*", r2)
  137.         r2 = mr$(temp, "/", r2)
  138.         r = mr$(r, "-", r2)
  139.     Next k
  140.     If Len(r) > 101 Then r = Left$(r, 101)
  141.     approx_powers = r
  142.  
  143. Function sqrt$ (n$)
  144.     Dim As String r, tmp, r2
  145.     Dim As Integer d, e, k, l
  146.     r = _Trim$(Str$(Sqr(Val(n$))))
  147.     d = InStr(r, "D")
  148.     If d > 0 Then
  149.         e = Val(Mid$(r, d + 1))
  150.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  151.         l = Len(r)
  152.         If e > 0 Then
  153.             r = r + String$(e - l + 1, "0")
  154.         ElseIf e < 0 Then
  155.             r = "0." + String$(Abs(e) - 1, "0") + r
  156.         End If
  157.     End If
  158.     For k = 1 To 3
  159.         tmp = mr$(r, "*", r)
  160.         tmp = mr$(tmp, "-", n$)
  161.         r2 = mr$(r, "+", r)
  162.         tmp = mr$(tmp, "/", r2)
  163.         r = mr$(r, "-", tmp)
  164.         If Len(r) > 101 Then r = Left$(r, 101)
  165.     Next k 'Loop Until Abs(Val(tmp)) < 1D-100
  166.     sqrt$ = r
  167.  
  168. Function mr$ (a$, op$, b$) ' catchy? mr$ for math regulator
  169.     Dim ca$, cb$, aSgn$, bSgn$, postOp$, sgn$
  170.     Dim adp As Integer, bdp As Integer, dp As Integer, lpop As Integer
  171.  
  172.     op$ = _Trim$(op$) 'save fixing each time
  173.     ca$ = _Trim$(a$): cb$ = _Trim$(b$) 'make copies in case we change
  174.     'strip signs and decimals
  175.     If Left$(ca$, 1) = "-" Then
  176.         aSgn$ = "-": ca$ = Mid$(ca$, 2)
  177.     Else
  178.         aSgn$ = "": ca$ = ca$
  179.     End If
  180.     dp = InStr(ca$, ".")
  181.     If dp > 0 Then
  182.         adp = Len(ca$) - dp
  183.         ca$ = Mid$(ca$, 1, dp - 1) + Mid$(ca$, dp + 1)
  184.     Else
  185.         adp = 0
  186.     End If
  187.     If Left$(cb$, 1) = "-" Then
  188.         bSgn$ = "-": cb$ = Mid$(cb$, 2)
  189.     Else
  190.         bSgn$ = "": cb$ = cb$
  191.     End If
  192.     dp = InStr(cb$, ".")
  193.     If dp > 0 Then
  194.         bdp = Len(cb$) - dp
  195.         cb$ = Mid$(cb$, 1, dp - 1) + Mid$(cb$, dp + 1)
  196.     Else
  197.         bdp = 0
  198.     End If
  199.  
  200.     If op$ = "+" Or op$ = "-" Or op$ = "/" Then 'add or subtr  even up strings on right of decimal
  201.         'even up the right sides of decimals if any
  202.         If adp > bdp Then dp = adp Else dp = bdp
  203.         If adp < dp Then ca$ = ca$ + String$(dp - adp, "0")
  204.         If bdp < dp Then cb$ = cb$ + String$(dp - bdp, "0")
  205.     ElseIf op$ = "*" Then
  206.         dp = adp + bdp
  207.     End If
  208.     If op$ = "*" Or op$ = "/" Then
  209.         If aSgn$ = bSgn$ Then sgn$ = "" Else sgn$ = "-"
  210.     End If
  211.     'now according to signs and op$ call add$ or subtr$
  212.     If op$ = "+" Then
  213.         If aSgn$ = bSgn$ Then 'really add
  214.             postOp$ = aSgn$ + add$(ca$, cb$)
  215.         Else 'have a case of subtraction
  216.             If aSgn$ = "-" Then postOp$ = subtr$(cb$, ca$) Else postOp$ = subtr$(ca$, cb$)
  217.         End If
  218.     ElseIf op$ = "-" Then
  219.         If bSgn$ = "-" Then 'really add but switch b sign
  220.             bSgn$ = ""
  221.             If aSgn$ = "-" Then
  222.                 postOp$ = subtr$(cb$, ca$)
  223.             Else 'aSgn = ""
  224.                 postOp$ = add$(ca$, cb$)
  225.             End If
  226.         Else 'bSgn$ =""
  227.             If aSgn$ = "-" Then
  228.                 bSgn$ = "-"
  229.                 postOp$ = aSgn$ + add$(ca$, cb$)
  230.             Else
  231.                 postOp$ = subtr$(ca$, cb$)
  232.             End If
  233.         End If
  234.     ElseIf op$ = "*" Then
  235.         postOp$ = sgn$ + mult$(ca$, cb$)
  236.     ElseIf op$ = "/" Then
  237.         postOp$ = sgn$ + divide$(ca$, cb$)
  238.     End If ' which op
  239.     'put dp back
  240.     If op$ <> "/" Then
  241.         lpop = Len(postOp$) ' put decimal back
  242.         postOp$ = Mid$(postOp$, 1, lpop - dp) + "." + Mid$(postOp$, lpop - dp + 1)
  243.     End If
  244.     mr$ = trim0$(postOp$)
  245.  
  246. Function divide$ (n$, d$) ' goal here is 100 digits precision not 100 digits past decimal
  247.     Dim di$, ndi$, nD As Integer
  248.     If trim0$(n$) = "0" Then divide$ = "0": Exit Function
  249.     If trim0$(d$) = "0" Then divide$ = "div 0": Exit Function
  250.     If trim0$(d$) = "1" Then divide$ = trim0$(n$): Exit Function '8/17 add trim0$
  251.  
  252.     ' aha! found a bug when d$ gets really huge 100 is no where near enough!!!!
  253.     ' 2021-06-03 fix by adding 100 to len(d$), plus have to go a little past 100 for 100 digit precision
  254.     ' need to go past 100 for 100 precise digits (not decimal places)
  255.     di$ = Mid$(nInverse$(d$, Len(d$) + 200), 2) 'chop off decimal point after
  256.     nD = Len(di$)
  257.     ndi$ = mult$(n$, di$)
  258.     ndi$ = Mid$(ndi$, 1, Len(ndi$) - nD) + "." + Right$(String$(nD, "0") + Right$(ndi$, nD), nD)
  259.     divide$ = trim0$(ndi$)
  260.  
  261. Function nInverse$ (n$, DP As Integer) 'assume decimal at very start of the string of digits returned, no rounding
  262.     Dim m$(1 To 9), si$, r$, outstr$, d$
  263.     Dim i As Integer
  264.     For i = 1 To 9
  265.         si$ = _Trim$(Str$(i))
  266.         m$(i) = mult$(si$, n$)
  267.     Next
  268.     outstr$ = ""
  269.     If n$ = "0" Then nInverse$ = "Div 0": Exit Function
  270.     If n$ = "1" Then nInverse$ = "1": Exit Function
  271.     outstr$ = "." 'everything else n > 1 is decimal 8/17
  272.     r$ = "10"
  273.     Do
  274.         While Left$(subtr$(r$, n$), 1) = "-" '   r - n < 0
  275.             outstr$ = outstr$ + "0" '            add 0 to the  output string
  276.             If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function 'check if we've reached DP length
  277.             r$ = r$ + "0"
  278.         Wend
  279.         For i = 9 To 1 Step -1
  280.             If LTE(m$(i), r$) Then d$ = _Trim$(Str$(i)): Exit For
  281.         Next
  282.         outstr$ = outstr$ + d$
  283.         If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function
  284.         r$ = subtr$(r$, mult$(d$, n$)) 'r = r -d*n
  285.         If r$ = "0" Then nInverse$ = outstr$: Exit Function 'found a perfect divisor
  286.         r$ = r$ + "0" 'add another place
  287.     Loop
  288.  
  289. Function mult$ (a$, b$) 'assume both positive integers prechecked as all digits strings
  290.     Dim la As Integer, lb As Integer, m As Integer, g As Integer, dp As Integer
  291.     Dim f18$, f1$, t$, build$, accum$
  292.  
  293.     If trim0$(a$) = "0" Then mult$ = "0": Exit Function
  294.     If trim0$(b$) = "0" Then mult$ = "0": Exit Function
  295.     If trim0$(a$) = "1" Then mult$ = trim0$(b$): Exit Function
  296.     If trim0$(b$) = "1" Then mult$ = trim0$(a$): Exit Function
  297.     'find the longer number and make it a mult of 18 to take 18 digits at a time from it
  298.     la = Len(a$): lb = Len(b$)
  299.     If la > lb Then
  300.         m = Int(la / 18) + 1
  301.         f18$ = Right$(String$(m * 18, "0") + a$, m * 18)
  302.         f1$ = b$
  303.     Else
  304.         m = Int(lb / 18) + 1
  305.         f18$ = Right$(String$(m * 18, "0") + b$, m * 18)
  306.         f1$ = a$
  307.     End If
  308.     For dp = Len(f1$) To 1 Step -1 'dp = digit position of the f1$
  309.         build$ = "" 'line builder
  310.         co = 0
  311.         'now taking 18 digits at a time Thanks Steve McNeill
  312.         For g = 1 To m
  313.             v18 = Val(Mid$(f18$, m * 18 - g * 18 + 1, 18))
  314.             sd = Val(Mid$(f1$, dp, 1))
  315.             t$ = Right$(String$(19, "0") + _Trim$(Str$(v18 * sd + co)), 19)
  316.             co = Val(Mid$(t$, 1, 1))
  317.             build$ = Mid$(t$, 2) + build$
  318.         Next g
  319.         If co Then build$ = _Trim$(Str$(co)) + build$
  320.         If dp = Len(f1$) Then
  321.             accum$ = build$
  322.         Else
  323.             accum$ = add$(accum$, build$ + String$(Len(f1$) - dp, "0"))
  324.         End If
  325.     Next dp
  326.     mult$ = accum$
  327.  
  328. Function subtr$ (sum$, minus$) ' assume both numbers are positive all digits
  329.     Dim m As Integer, g As Integer, p As Integer
  330.     Dim ts$, tm$, sign$, LG$, sm$, t$, result$
  331.  
  332.     ts$ = TrimLead0$(sum$): tm$ = TrimLead0$(minus$)
  333.     If trim0(ts$) = trim0$(tm$) Then subtr$ = "0": Exit Function 'OK proceed with function knowing they are not equal
  334.     tenE18 = 1000000000000000000 'yes!!! no dang E's
  335.     If LTE(ts$, tm$) Then ' which is bigger? minus is bigger
  336.         sign$ = "-"
  337.         m = Int(Len(tm$) / 18) + 1
  338.         LG$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  339.         sm$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  340.     Else 'sum is bigger
  341.         sign$ = ""
  342.         m = Int(Len(ts$) / 18) + 1
  343.         LG$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  344.         sm$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  345.     End If
  346.     'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
  347.     For g = 1 To m
  348.         VB = Val(Mid$(LG$, m * 18 - g * 18 + 1, 18))
  349.         vs = Val(Mid$(sm$, m * 18 - g * 18 + 1, 18))
  350.         If vs > VB Then
  351.             t$ = Right$(String$(18, "0") + _Trim$(Str$(tenE18 - vs + VB)), 18)
  352.             p = (m - g) * 18
  353.             While p > 0 And Mid$(LG$, p, 1) = "0"
  354.                 Mid$(LG$, p, 1) = "9"
  355.                 p = p - 1
  356.             Wend
  357.             If p > 0 Then Mid$(LG$, p, 1) = _Trim$(Str$(Val(Mid$(LG$, p, 1)) - 1))
  358.         Else
  359.             t$ = Right$(String$(18, "0") + _Trim$(Str$(VB - vs)), 18)
  360.         End If
  361.         result$ = t$ + result$
  362.     Next
  363.     subtr$ = sign$ + result$
  364.  
  365. Function add$ (a$, b$) 'add 2 positive integers assume a and b are just numbers no spaces or - signs
  366.     'first thing is to set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
  367.     Dim la As Integer, lb As Integer, m As Integer, g As Integer
  368.     Dim fa$, fb$, t$, new$, result$
  369.     la = Len(a$): lb = Len(b$)
  370.     If la > lb Then m = Int(la / 18) + 1 Else m = Int(lb / 18) + 1
  371.     fa$ = Right$(String$(m * 18, "0") + a$, m * 18)
  372.     fb$ = Right$(String$(m * 18, "0") + b$, m * 18)
  373.  
  374.     'now taking 18 digits at a time Thanks Steve McNeill
  375.     For g = 1 To m
  376.         sa = Val(Mid$(fa$, m * 18 - g * 18 + 1, 18))
  377.         sb = Val(Mid$(fb$, m * 18 - g * 18 + 1, 18))
  378.         t$ = Right$(String$(36, "0") + _Trim$(Str$(sa + sb + co)), 36)
  379.         co = Val(Mid$(t$, 1, 18))
  380.         new$ = Mid$(t$, 19)
  381.         result$ = new$ + result$
  382.     Next
  383.     If co Then result$ = Str$(co) + result$
  384.     add$ = result$
  385.  
  386. ' String Math Helpers -----------------------------------------------
  387.  
  388. 'this function needs TrimLead0$(s$)
  389. Function LTE (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  390.     Dim ca$, cb$, la As Integer, lb As Integer, i As Integer
  391.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  392.     la = Len(ca$): lb = Len(cb$)
  393.     If ca$ = cb$ Then
  394.         LTE = -1
  395.     ElseIf la < lb Then ' a is smaller
  396.         LTE = -1
  397.     ElseIf la > lb Then ' a is bigger
  398.         LTE = 0
  399.     ElseIf la = lb Then ' equal lengths
  400.         For i = 1 To Len(ca$)
  401.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  402.                 LTE = 0: Exit Function
  403.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  404.                 LTE = -1: Exit Function
  405.             End If
  406.         Next
  407.     End If
  408.  
  409. ' ------------------------------------- use these for final display
  410.  
  411. Function TrimLead0$ (s$) 'for treating strings as number (pos integers)
  412.     Dim copys$, i As Integer, find As Integer
  413.     copys$ = _Trim$(s$) 'might as well remove spaces too
  414.     i = 1: find = 0
  415.     While i < Len(copys$) And Mid$(copys$, i, 1) = "0"
  416.         i = i + 1: find = 1
  417.     Wend
  418.     If find = 1 Then copys$ = Mid$(copys$, i)
  419.     If copys$ = "" Then TrimLead0$ = "0" Else TrimLead0$ = copys$
  420.  
  421. Function TrimTail0$ (s$)
  422.     Dim copys$, dp As Integer, i As Integer, find As Integer
  423.     copys$ = _Trim$(s$) 'might as well remove spaces too
  424.     TrimTail0$ = copys$
  425.     dp = InStr(copys$, ".")
  426.     If dp > 0 Then
  427.         i = Len(copys$): find = 0
  428.         While i > dp And Mid$(copys$, i, 1) = "0"
  429.             i = i - 1: find = 1
  430.         Wend
  431.         If find = 1 Then
  432.             If i = dp Then
  433.                 TrimTail0$ = Mid$(copys$, 1, dp - 1)
  434.             Else
  435.                 TrimTail0$ = Mid$(copys$, 1, i)
  436.             End If
  437.         End If
  438.     End If
  439.  
  440. Function trim0$ (s$)
  441.     Dim cs$, si$
  442.     cs$ = s$
  443.     si$ = Left$(cs$, 1)
  444.     If si$ = "-" Then cs$ = Mid$(cs$, 2)
  445.     cs$ = TrimLead0$(cs$)
  446.     cs$ = TrimTail0$(cs$)
  447.     If Right$(cs$, 1) = "." Then cs$ = Mid$(cs$, 1, Len(cs$) - 1)
  448.     If si$ = "-" Then trim0$ = si$ + cs$ Else trim0$ = cs$
  449.  
  450. ' for displaying truncated numbers say to 60 digits
  451. Function showDP$ (num$, nDP As Integer)
  452.     Dim cNum$, dp As Integer, d As Integer, i As Integer
  453.     cNum$ = num$ 'since num$ could get changed
  454.     showDP$ = num$
  455.     dp = InStr(num$, ".")
  456.     If dp > 0 Then
  457.         If Len(Mid$(cNum$, dp + 1)) > nDP Then
  458.             d = Val(Mid$(cNum$, dp + nDP + 1, 1))
  459.             If d > 4 Then
  460.                 cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
  461.                 dp = dp + 1
  462.                 i = dp + nDP
  463.                 While Mid$(cNum$, i, 1) = "9" Or Mid$(cNum$, i, 1) = "."
  464.                     If Mid$(cNum$, i, 1) = "9" Then
  465.                         Mid$(cNum$, i, 1) = "0"
  466.                     End If
  467.                     i = i - 1
  468.                 Wend
  469.                 Mid$(cNum$, i, 1) = _Trim$(Str$(Val(Mid$(cNum$, i, 1)) + 1)) 'last non 9 digit
  470.                 cNum$ = Mid$(cNum$, 1, dp + nDP) 'chop it
  471.                 showDP$ = trim0$(cNum$)
  472.             Else
  473.                 showDP$ = Mid$(cNum$, 1, dp + nDP)
  474.             End If
  475.         End If
  476.     End If
  477.  
« Last Edit: June 06, 2021, 10:30:58 am by jack »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #49 on: June 04, 2021, 06:46:13 pm »
The subtr$ Function is terrible!

I should have checked way larger and smaller numbers with it. I think I just checked it with QB64 Doubles or Floats for errors but the bug doesn't show until numbers are longer than 18 digits.

Apologies to all who wasted time working that code.

Still, our goal is a good one I think.

PS This explains why the attempts with Newton-Raphson were not working with Mr$() Function calls and why I was getting good sqrRoots because I was using the Average Method that did not use subtraction.
« Last Edit: June 04, 2021, 06:56:14 pm by bplus »

Offline George McGinn

  • Global Moderator
  • Forum Regular
  • Posts: 210
    • View Profile
    • Resume
Re: String Math
« Reply #50 on: June 05, 2021, 01:16:38 am »
The sqrt$ also performs subtr$ function. The root_n$ I have now (non-string version) and your power## seems to work fine.

Also, I noticed that for the power## function, when I do 1.2^5 [mr$("1.2", "^", "5")] I get the right digits, but the decimal place isn't put back into the final result (see screen print).

 
Screenshot from 2021-06-05 01-15-22.png
____________________________________________________________________
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 bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #51 on: June 05, 2021, 11:07:29 pm »
Well it took all day to find a simple little change in the subtr$() Function that fixes problems. That was the good news.

The bad news, it is now taking the inverse of STx number to see 115 terms of Fibonacci series (or is it sequence)  about 30 secs to calculate, before it was up in a sneeze. It looks different also at the end but the same 115 terms of Fibonacci can still be found.

OK so the first line in subtr$() fixes the bug that jack pointed out that I confirmed and it also fixes my version of George's version of Newton-Raphson estimates of SQR() but it is definitely slowed down. We now get same sqr roots for 100 + 30-0's and .20-0's 64 for both versions.

Anyway here is the code checks and tests:
Code: QB64: [Select]
  1. _Title "Math regulator mr test sqr estimating" ' b+ start 2021-06-02
  2. ' divide$ found fix? 2021-06-03 comment in that function
  3. ' 2021-06-03 update with new sqrRoot$ Function
  4.  
  5. Randomize Timer 'now that it's seems to be running silent
  6. Screen _NewImage(1200, 700, 32)
  7. _Delay .25
  8.  
  9. ' jack error reported 2021-06-04 confirmed!   fixed
  10. Print mr$(".00000000000000000000000000000000000000000000200000000000000054307978001764", "-", ".000000000000000000000000000000000000000000002")
  11. Print ".00000000000000000000000000000000000000000000000000000000000054307978001764"
  12.  
  13. Dim r$, ruler$
  14. ruler$ = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + Chr$(10)
  15. ruler$ = ruler$ + "0         1         2         3         4         5         6         7         8         9        10        11        12"
  16. ' debug tests
  17. Print mr$("-5", "+", "-2100"), " OK if -2105"
  18. Print mr$("." + String$(20, "0") + "1", "+", "1" + String$(40, "0") + "1") ' first real test of add
  19. Print ruler$
  20. Print Val("." + String$(20, "0") + "1") + Val("1" + String$(40, "0") + "1") ' test print of big and small val
  21. Print mr$("-.00071", "+", ".00036" + String$(35, "0") + "9")
  22. '-.00071
  23. ' .00036000000000000000000000000000000000009
  24. Print "-.00034999999999999999999999999999999999991"
  25. Print ruler$
  26. 'testing a different subtract sub
  27. Print mr$("10", "-", "5"), " 5 OK"
  28. Print mr$("-10", "+", "5"), " -5 OK"
  29. Print mr$("-10", "-", "-5"), " -5 OK"
  30. Print mr$("-10", "-", "5"), " -15  OK  added"
  31. Print mr$("10", "-", "-5"), " 15  OK  added"
  32. Print mr$("-.010", "-", "-5"), "4.99 OK"
  33. Print mr$("-.010", "-", "5"), "-5.01  OK just added"
  34. Print mr$(".010", "-", "5"), " -4.99 OK"
  35. ' jack error reported 2021-06-04 confirmed!  variation below
  36. r$ = mr$(".00000000200000000000000054307978001764", "-", ".0000000020000000000000001") '16 0 wrong  8 wrong
  37. Print "   mr$ rtnd:"; r$
  38. Print "    compare:.00000000000000000000000044307978001764" ' 2021-06-05 finally!
  39. '                  .0000000020000000000000001
  40. '                  .00000000200000000000000054307978001764
  41.  
  42. r$ = mr$(".00000000000000000100000000000000000011", "-", ".000000000000000001000000000000000001") ' bad too
  43. Print "   mr$ rtnd:"; r$
  44. '         ".000000000000000001000000000000000001"
  45. Print "    compare:-.00000000000000000000000000000000000089"
  46. r$ = mr$(".00000000000000000100000000000000000111", "-", ".000000000000000002000000000000000001")
  47. '       ".000000000000000002000000000000000001"
  48. '       ".00000000000000000100000000000000000111"
  49. '       ".00000000000000000099999999999999999989"
  50. Print "   mr$ rtnd:"; r$
  51. Print "    compare:-.00000000000000000099999999999999999989"
  52.  
  53. r$ = mr$(".00000000000000000000000000999", "-", "1")
  54. '-1.00000000000000000000000000000000000000000
  55. '  .00000000000000000000000000999
  56. ' -.99999999999999999999999999001
  57. Print "   mr$ rtnd:"; r$
  58. Print "    compare:-.99999999999999999999999999001"
  59.  
  60. r$ = mr$("1", "+", "-1000000000000000000000000000000000000000")
  61. Print "   mr$ rtnd:"; r$
  62. '1000000000000000000000000000000000000000
  63. '-999999999999999999999999999999999999999
  64. Print "    compare:-999999999999999999999999999999999999999"
  65.  
  66. ' check jack problems with FB translation  2021-06-03  errors must be in FB trans from QB64
  67. Print Mid$(mr$(" .1", "/", "3"), 1, 100) ' too long?
  68. Print Mid$(mr$("1.1", "/", "9"), 1, 100)
  69. Print Mid$(mr$("1.38", "/", "1.2"), 1, 100)
  70. Print ruler$
  71.  
  72. Print "checking inverse of 50 = .02 "; nInverse$("50", 20) 'OK  .020000... length 20
  73. Print ruler$
  74. Print "zzz... see inverse of STx number now takes close to 30 secs with fixed subtr$() sub,"
  75. Print "Use to come up in a sneeze! It also looks different way more space on end but still"
  76. Print "can find 115 Fibonacci terms in it."
  77. Print "    The only difference is I am not trimming leading 0's in subst$() function!"
  78. Print nInverse$("999999999999999999999998999999999999999999999999", 4000) ' wow big delay!
  79.  
  80.  
  81.  
  82. Dim n$, result$
  83.     'remember everything is strings
  84.     Input "Enter a number to find it's square root "; n$
  85.     If n$ = "" Then End
  86.     result$ = sqrRoot$(n$)
  87.     Print result$
  88.     Print "Length ="; Len(result$)
  89.     _Delay 2
  90.     result$ = SRbyNR$(n$)
  91.     Print result$
  92.     Print "Length ="; Len(result$)
  93.     Print
  94.  
  95. Function sqrRoot$ (nmbr$)
  96.     Dim n$, guess$, lastGuess$, other$, sum$, imaginary$, loopcnt
  97.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  98.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  99.     Else
  100.         imaginary$ = "": n$ = nmbr$
  101.     End If
  102.     guess$ = mr$(n$, "/", "2")
  103.     other$ = n$
  104.     Do
  105.         loopcnt = loopcnt + 1
  106.         Print "loop cnt"; loopcnt
  107.  
  108.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  109.             sqrRoot$ = Mid$(other$, 1, 101) + imaginary$ ' try other factor for guess$  sometimes it nails answer without all digits
  110.             Exit Function
  111.         Else
  112.             lastGuess$ = guess$
  113.             sum$ = mr$(guess$, "+", other$)
  114.             guess$ = mr$(sum$, "/", "2")
  115.             other$ = mr$(n$, "/", guess$)
  116.         End If
  117.     Loop
  118.  
  119. Function SRbyNR$ (nmbr$) ' square root by Newton - Ralphson method my interpretation of GeorgeMcGinn
  120.  
  121.     Dim n$, guess$, lastGuess$, dx$, imaginary$, other$, loopcnt
  122.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  123.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  124.     Else
  125.         imaginary$ = "": n$ = nmbr$
  126.     End If
  127.  
  128.     guess$ = mr$(n$, "/", "2") ' get this going first and then try better starting guess later
  129.  
  130.     Do
  131.         loopcnt = loopcnt + 1
  132.         Print "loop cnt"; loopcnt
  133.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  134.             SRbyNR$ = Mid$(other$, 1, 101) + imaginary$
  135.             Exit Function
  136.         Else
  137.             'dx = (x - A / x) / 2: x = x - dx ' Thanks George
  138.             lastGuess$ = guess$
  139.             dx$ = mr$(mr$(guess$, "-", mr$(n$, "/", guess$)), "/", "2")
  140.             guess$ = mr$(guess$, "-", dx$)
  141.             other$ = mr$(n$, "/", guess$) ' try other factor for guess$  sometimes it nails answer without all digits
  142.         End If
  143.     Loop
  144.  
  145.  
  146. Function mr$ (a$, op$, b$) ' catchy? mr$ for math regulator
  147.     Dim ca$, cb$, aSgn$, bSgn$, postOp$, sgn$
  148.     Dim adp As Integer, bdp As Integer, dp As Integer, lpop As Integer
  149.  
  150.     op$ = _Trim$(op$) 'save fixing each time
  151.     ca$ = _Trim$(a$): cb$ = _Trim$(b$) 'make copies in case we change
  152.     'strip signs and decimals
  153.     If Left$(ca$, 1) = "-" Then
  154.         aSgn$ = "-": ca$ = Mid$(ca$, 2)
  155.     Else
  156.         aSgn$ = "": ca$ = ca$
  157.     End If
  158.     dp = InStr(ca$, ".")
  159.     If dp > 0 Then
  160.         adp = Len(ca$) - dp
  161.         ca$ = Mid$(ca$, 1, dp - 1) + Mid$(ca$, dp + 1)
  162.     Else
  163.         adp = 0
  164.     End If
  165.     If Left$(cb$, 1) = "-" Then
  166.         bSgn$ = "-": cb$ = Mid$(cb$, 2)
  167.     Else
  168.         bSgn$ = "": cb$ = cb$
  169.     End If
  170.     dp = InStr(cb$, ".")
  171.     If dp > 0 Then
  172.         bdp = Len(cb$) - dp
  173.         cb$ = Mid$(cb$, 1, dp - 1) + Mid$(cb$, dp + 1)
  174.     Else
  175.         bdp = 0
  176.     End If
  177.  
  178.     If op$ = "+" Or op$ = "-" Or op$ = "/" Then 'add or subtr  even up strings on right of decimal
  179.         'even up the right sides of decimals if any
  180.         If adp > bdp Then dp = adp Else dp = bdp
  181.         If adp < dp Then ca$ = ca$ + String$(dp - adp, "0")
  182.         If bdp < dp Then cb$ = cb$ + String$(dp - bdp, "0")
  183.     ElseIf op$ = "*" Then
  184.         dp = adp + bdp
  185.     End If
  186.     If op$ = "*" Or op$ = "/" Then
  187.         If aSgn$ = bSgn$ Then sgn$ = "" Else sgn$ = "-"
  188.     End If
  189.     'now according to signs and op$ call add$ or subtr$
  190.     If op$ = "+" Then
  191.         If aSgn$ = bSgn$ Then 'really add
  192.             postOp$ = aSgn$ + add$(ca$, cb$)
  193.         Else 'have a case of subtraction
  194.             If aSgn$ = "-" Then postOp$ = subtr$(cb$, ca$) Else postOp$ = subtr$(ca$, cb$)
  195.         End If
  196.     ElseIf op$ = "-" Then
  197.         If bSgn$ = "-" Then 'really add but switch b sign
  198.             bSgn$ = ""
  199.             If aSgn$ = "-" Then
  200.                 postOp$ = subtr$(cb$, ca$)
  201.             Else 'aSgn = ""
  202.                 postOp$ = add$(ca$, cb$)
  203.             End If
  204.         Else 'bSgn$ =""
  205.             If aSgn$ = "-" Then
  206.                 bSgn$ = "-"
  207.                 postOp$ = aSgn$ + add$(ca$, cb$)
  208.             Else
  209.                 postOp$ = subtr$(ca$, cb$)
  210.             End If
  211.         End If
  212.     ElseIf op$ = "*" Then
  213.         postOp$ = sgn$ + mult$(ca$, cb$)
  214.     ElseIf op$ = "/" Then
  215.         postOp$ = sgn$ + divide$(ca$, cb$)
  216.     End If ' which op
  217.     'put dp back
  218.     If op$ <> "/" Then
  219.         lpop = Len(postOp$) ' put decimal back
  220.         postOp$ = Mid$(postOp$, 1, lpop - dp) + "." + Mid$(postOp$, lpop - dp + 1)
  221.     End If
  222.     mr$ = trim0$(postOp$)
  223.  
  224. Function divide$ (n$, d$) ' goal here is 100 digits precision not 100 digits past decimal
  225.     Dim di$, ndi$, nD As Integer
  226.     If trim0$(n$) = "0" Then divide$ = "0": Exit Function
  227.     If trim0$(d$) = "0" Then divide$ = "div 0": Exit Function
  228.     If trim0$(d$) = "1" Then divide$ = trim0$(n$): Exit Function '8/17 add trim0$
  229.  
  230.     ' aha! found a bug when d$ gets really huge 100 is no where near enough!!!!
  231.     ' 2021-06-03 fix by adding 100 to len(d$), plus have to go a little past 100 for 100 digit precision
  232.     ' need to go past 100 for 100 precise digits (not decimal places)
  233.     di$ = Mid$(nInverse$(d$, Len(d$) + 200), 2) 'chop off decimal point after
  234.     nD = Len(di$)
  235.     ndi$ = mult$(n$, di$)
  236.     ndi$ = Mid$(ndi$, 1, Len(ndi$) - nD) + "." + Right$(String$(nD, "0") + Right$(ndi$, nD), nD)
  237.     divide$ = trim0$(ndi$)
  238.  
  239. Function nInverse$ (n$, DP As Integer) 'assume decimal at very start of the string of digits returned, no rounding
  240.     Dim m$(1 To 9), si$, r$, outstr$, d$
  241.     Dim i As Integer
  242.     For i = 1 To 9
  243.         si$ = _Trim$(Str$(i))
  244.         m$(i) = mult$(si$, n$)
  245.     Next
  246.     outstr$ = ""
  247.     If n$ = "0" Then nInverse$ = "Div 0": Exit Function
  248.     If n$ = "1" Then nInverse$ = "1": Exit Function
  249.     outstr$ = "." 'everything else n > 1 is decimal 8/17
  250.     r$ = "10"
  251.     Do
  252.         While Left$(subtr$(r$, n$), 1) = "-" '   r - n < 0
  253.             outstr$ = outstr$ + "0" '            add 0 to the  output string
  254.             If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function 'check if we've reached DP length
  255.             r$ = r$ + "0"
  256.         Wend
  257.         For i = 9 To 1 Step -1
  258.             If LTE(m$(i), r$) Then d$ = _Trim$(Str$(i)): Exit For
  259.         Next
  260.         outstr$ = outstr$ + d$
  261.         If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function
  262.         r$ = subtr$(r$, mult$(d$, n$)) 'r = r -d*n
  263.         If r$ = "0" Then nInverse$ = outstr$: Exit Function 'found a perfect divisor
  264.         r$ = r$ + "0" 'add another place
  265.     Loop
  266.  
  267. Function mult$ (a$, b$) 'assume both positive integers prechecked as all digits strings
  268.     Dim la As Integer, lb As Integer, m As Integer, g As Integer, dp As Integer
  269.     Dim f18$, f1$, t$, build$, accum$
  270.  
  271.     If trim0$(a$) = "0" Then mult$ = "0": Exit Function
  272.     If trim0$(b$) = "0" Then mult$ = "0": Exit Function
  273.     If trim0$(a$) = "1" Then mult$ = trim0$(b$): Exit Function
  274.     If trim0$(b$) = "1" Then mult$ = trim0$(a$): Exit Function
  275.     'find the longer number and make it a mult of 18 to take 18 digits at a time from it
  276.     la = Len(a$): lb = Len(b$)
  277.     If la > lb Then
  278.         m = Int(la / 18) + 1
  279.         f18$ = Right$(String$(m * 18, "0") + a$, m * 18)
  280.         f1$ = b$
  281.     Else
  282.         m = Int(lb / 18) + 1
  283.         f18$ = Right$(String$(m * 18, "0") + b$, m * 18)
  284.         f1$ = a$
  285.     End If
  286.     For dp = Len(f1$) To 1 Step -1 'dp = digit position of the f1$
  287.         build$ = "" 'line builder
  288.         co = 0
  289.         'now taking 18 digits at a time Thanks Steve McNeill
  290.         For g = 1 To m
  291.             v18 = Val(Mid$(f18$, m * 18 - g * 18 + 1, 18))
  292.             sd = Val(Mid$(f1$, dp, 1))
  293.             t$ = Right$(String$(19, "0") + _Trim$(Str$(v18 * sd + co)), 19)
  294.             co = Val(Mid$(t$, 1, 1))
  295.             build$ = Mid$(t$, 2) + build$
  296.         Next g
  297.         If co Then build$ = _Trim$(Str$(co)) + build$
  298.         If dp = Len(f1$) Then
  299.             accum$ = build$
  300.         Else
  301.             accum$ = add$(accum$, build$ + String$(Len(f1$) - dp, "0"))
  302.         End If
  303.     Next dp
  304.     mult$ = accum$
  305.  
  306. Function subtr$ (sum$, minus$) ' assume both numbers are positive all digits
  307.     Dim m As Integer, g As Integer, p As Integer
  308.     Dim ts$, tm$, sign$, LG$, sm$, t$, result$
  309.  
  310.     'ts$ = TrimLead0$(sum$): tm$ = TrimLead0$(minus$)   'orig with decent square root speed
  311.     ts$ = _Trim$(sum$): tm$ = _Trim$(minus$) ' fixed subtr$ 2021-06-05
  312.     If trim0(ts$) = trim0$(tm$) Then subtr$ = "0": Exit Function 'OK proceed with function knowing they are not equal
  313.     tenE18 = 1000000000000000000 'yes!!! no dang E's
  314.     If LTE(ts$, tm$) Then ' which is bigger? minus is bigger
  315.         sign$ = "-"
  316.         m = Int(Len(tm$) / 18) + 1
  317.         LG$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  318.         sm$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  319.     Else 'sum is bigger
  320.         sign$ = ""
  321.         m = Int(Len(ts$) / 18) + 1
  322.         LG$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  323.         sm$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  324.     End If
  325.     'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
  326.     For g = 1 To m
  327.         VB = Val(Mid$(LG$, m * 18 - g * 18 + 1, 18))
  328.         vs = Val(Mid$(sm$, m * 18 - g * 18 + 1, 18))
  329.         If vs > VB Then
  330.             t$ = Right$(String$(18, "0") + _Trim$(Str$(tenE18 - vs + VB)), 18)
  331.             p = (m - g) * 18
  332.             While p > 0 And Mid$(LG$, p, 1) = "0"
  333.                 Mid$(LG$, p, 1) = "9"
  334.                 p = p - 1
  335.             Wend
  336.             If p > 0 Then Mid$(LG$, p, 1) = _Trim$(Str$(Val(Mid$(LG$, p, 1)) - 1))
  337.         Else
  338.             t$ = Right$(String$(18, "0") + _Trim$(Str$(VB - vs)), 18)
  339.         End If
  340.         result$ = t$ + result$
  341.     Next
  342.     subtr$ = sign$ + result$
  343.  
  344. Function add$ (a$, b$) 'add 2 positive integers assume a and b are just numbers no spaces or - signs
  345.     'first thing is to set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
  346.     Dim la As Integer, lb As Integer, m As Integer, g As Integer
  347.     Dim fa$, fb$, t$, new$, result$
  348.     la = Len(a$): lb = Len(b$)
  349.     If la > lb Then m = Int(la / 18) + 1 Else m = Int(lb / 18) + 1
  350.     fa$ = Right$(String$(m * 18, "0") + a$, m * 18)
  351.     fb$ = Right$(String$(m * 18, "0") + b$, m * 18)
  352.  
  353.     'now taking 18 digits at a time Thanks Steve McNeill
  354.     For g = 1 To m
  355.         sa = Val(Mid$(fa$, m * 18 - g * 18 + 1, 18))
  356.         sb = Val(Mid$(fb$, m * 18 - g * 18 + 1, 18))
  357.         t$ = Right$(String$(36, "0") + _Trim$(Str$(sa + sb + co)), 36)
  358.         co = Val(Mid$(t$, 1, 18))
  359.         new$ = Mid$(t$, 19)
  360.         result$ = new$ + result$
  361.     Next
  362.     If co Then result$ = Str$(co) + result$
  363.     add$ = result$
  364.  
  365. ' String Math Helpers -----------------------------------------------
  366.  
  367. 'this function needs TrimLead0$(s$)
  368. Function LTE (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  369.     Dim ca$, cb$, la As Integer, lb As Integer, i As Integer
  370.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  371.     la = Len(ca$): lb = Len(cb$)
  372.     If ca$ = cb$ Then
  373.         LTE = -1
  374.     ElseIf la < lb Then ' a is smaller
  375.         LTE = -1
  376.     ElseIf la > lb Then ' a is bigger
  377.         LTE = 0
  378.     ElseIf la = lb Then ' equal lengths
  379.         For i = 1 To Len(ca$)
  380.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  381.                 LTE = 0: Exit Function
  382.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  383.                 LTE = -1: Exit Function
  384.             End If
  385.         Next
  386.     End If
  387.  
  388. ' ------------------------------------- use these for final display
  389.  
  390. Function TrimLead0$ (s$) 'for treating strings as number (pos integers)
  391.     Dim copys$, i As Integer, find As Integer
  392.     copys$ = _Trim$(s$) 'might as well remove spaces too
  393.     i = 1: find = 0
  394.     While i < Len(copys$) And Mid$(copys$, i, 1) = "0"
  395.         i = i + 1: find = 1
  396.     Wend
  397.     If find = 1 Then copys$ = Mid$(copys$, i)
  398.     If copys$ = "" Then TrimLead0$ = "0" Else TrimLead0$ = copys$
  399.  
  400. Function TrimTail0$ (s$)
  401.     Dim copys$, dp As Integer, i As Integer, find As Integer
  402.     copys$ = _Trim$(s$) 'might as well remove spaces too
  403.     TrimTail0$ = copys$
  404.     dp = InStr(copys$, ".")
  405.     If dp > 0 Then
  406.         i = Len(copys$): find = 0
  407.         While i > dp And Mid$(copys$, i, 1) = "0"
  408.             i = i - 1: find = 1
  409.         Wend
  410.         If find = 1 Then
  411.             If i = dp Then
  412.                 TrimTail0$ = Mid$(copys$, 1, dp - 1)
  413.             Else
  414.                 TrimTail0$ = Mid$(copys$, 1, i)
  415.             End If
  416.         End If
  417.     End If
  418.  
  419. Function trim0$ (s$)
  420.     Dim cs$, si$
  421.     cs$ = s$
  422.     si$ = Left$(cs$, 1)
  423.     If si$ = "-" Then cs$ = Mid$(cs$, 2)
  424.     cs$ = TrimLead0$(cs$)
  425.     cs$ = TrimTail0$(cs$)
  426.     If Right$(cs$, 1) = "." Then cs$ = Mid$(cs$, 1, Len(cs$) - 1)
  427.     If si$ = "-" Then trim0$ = si$ + cs$ Else trim0$ = cs$
  428.  
  429. ' for displaying truncated numbers say to 60 digits
  430. Function showDP$ (num$, nDP As Integer)
  431.     Dim cNum$, dp As Integer, d As Integer, i As Integer
  432.     cNum$ = num$ 'since num$ could get changed
  433.     showDP$ = num$
  434.     dp = InStr(num$, ".")
  435.     If dp > 0 Then
  436.         If Len(Mid$(cNum$, dp + 1)) > nDP Then
  437.             d = Val(Mid$(cNum$, dp + nDP + 1, 1))
  438.             If d > 4 Then
  439.                 cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
  440.                 dp = dp + 1
  441.                 i = dp + nDP
  442.                 While Mid$(cNum$, i, 1) = "9" Or Mid$(cNum$, i, 1) = "."
  443.                     If Mid$(cNum$, i, 1) = "9" Then
  444.                         Mid$(cNum$, i, 1) = "0"
  445.                     End If
  446.                     i = i - 1
  447.                 Wend
  448.                 Mid$(cNum$, i, 1) = _Trim$(Str$(Val(Mid$(cNum$, i, 1)) + 1)) 'last non 9 digit
  449.                 cNum$ = Mid$(cNum$, 1, dp + nDP) 'chop it
  450.                 showDP$ = trim0$(cNum$)
  451.             Else
  452.                 showDP$ = Mid$(cNum$, 1, dp + nDP)
  453.             End If
  454.         End If
  455.     End If
  456.  
  457.  
« Last Edit: June 05, 2021, 11:15:48 pm by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #52 on: June 06, 2021, 02:11:38 am »
hi bplus
I don't understand your nInverse function, here's how I would implement the reciprocal
pseudo code
dim x as double
x=1#/val(n$) ' approximation
r$=_trim$(str$(x))  '<< you need to sift-out exponential notation
' Newton-Raphson iteration to improve the reciprocal - it doubles the accuracy per iteration
do
r$=r$*(2-n$*r$)
loop until satisfied '<< (2-n$*r$) approaches 1
or
do
r$=r$+r$*(1-r$*n$)
loop until satisfied '<<r$*(1-r$*n$) approaches 0

if you do r$=r$+r$*(1-r$*n$) then you could check r$*(1-r$*n$) until it's small enough
3 iterations would give over 120 digits accuracy
« Last Edit: June 06, 2021, 02:23:49 am by jack »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #53 on: June 06, 2021, 04:52:01 am »
your multiply don't work
Code: QB64: [Select]
  1. Print mr$("1.000000000000000000000001000000000000000000000001", "*", "0.000000000000000000000000000000000000000000000001")
  2.  
output
.1000000000000000000000001000000000000000000000001
was trying to test my nInverse but it fails due to the multiply bug
Code: QB64: [Select]
  1. Function nInverse2$ (n$, DP As Integer) 'assume decimal at very start of the string of digits returned, no rounding
  2.     Dim x As Double
  3.     Dim As Integer d, e, k, l
  4.     Dim As String r, r2
  5.     If n$ = "0" Then nInverse2$ = "Div 0": Exit Function
  6.     If n$ = "1" Then nInverse2$ = "1": Exit Function
  7.     x = 1# / Val(n$)
  8.     r = _Trim$(Str$(x))
  9.     d = InStr(r, "D")
  10.     If d > 0 Then
  11.         e = Val(Mid$(r, d + 1))
  12.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  13.         l = Len(r)
  14.         If e > 0 Then
  15.             r = r + String$(e - l + 1, "0")
  16.         ElseIf e < 0 Then
  17.             r = "0." + String$(Abs(e) - 1, "0") + r
  18.         End If
  19.     End If
  20.  
  21.     For k = 1 To 7
  22.         r2 = mr$(n$, "*", r)
  23.         r2 = mr$("2", "-", r2)
  24.         r = mr$(r, "*", r2)
  25.     Next k
  26.     nInverse2$ = r
  27.  
« Last Edit: June 06, 2021, 04:55:01 am by jack »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #54 on: June 06, 2021, 01:02:49 pm »
Simple fix on multiply again problem with trimming leading 0's.

@jack I like your inverse function and started playing with in attempts to control when it should quit.
It works well finding inverse of STx number and the 115 terms of Fibonacci in that sequence.

I am not satisfied with significant digits because a difference between 816 and 817 was just one more iteration in your code loop yet it went from finding 64 terms in 4.22 secs to all 115 terms in around 13 secs. My inverse with fixed subtr$() was taking over 19 secs and needing about 2785 digits.

So your inverse better. I see you are working on reciprical, interesting!

Code: QB64: [Select]
  1. _Title "Math regulator mr test sqr estimating" ' b+ start 2021-06-02
  2. ' divide$ found fix? 2021-06-03 comment in that function
  3. ' 2021-06-03 update with new sqrRoot$ Function
  4. ' 2021-06-06 fixed divide, subtr and mult, all were trimming lead 0's and messing up decimal settings.
  5. ' 2021-06-06 test jack's nInverse2$() on STx # to find 115 terms of Fibannci.
  6.  
  7. Randomize Timer 'now that it's seems to be running silent
  8. Screen _NewImage(1200, 700, 32)
  9. _Delay .25
  10.  
  11. ' jack error reported 2021-06-04 confirmed!   fixed
  12. 'Print mr$(".00000000000000000000000000000000000000000000200000000000000054307978001764", "-", ".000000000000000000000000000000000000000000002")
  13. 'Print ".00000000000000000000000000000000000000000000000000000000000054307978001764"
  14.  
  15. Dim r$, ruler$
  16. ruler$ = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + Chr$(10)
  17. ruler$ = ruler$ + "0         1         2         3         4         5         6         7         8         9        10        11        12"
  18. ' debug tests
  19. 'Print mr$("-5", "+", "-2100"), " OK if -2105"
  20. 'Print mr$("." + String$(20, "0") + "1", "+", "1" + String$(40, "0") + "1") ' first real test of add
  21. 'Print ruler$
  22. 'Print Val("." + String$(20, "0") + "1") + Val("1" + String$(40, "0") + "1") ' test print of big and small val
  23. 'Print mr$("-.00071", "+", ".00036" + String$(35, "0") + "9")
  24. '-.00071
  25. ' .00036000000000000000000000000000000000009
  26. 'Print "-.00034999999999999999999999999999999999991"
  27. 'Print ruler$
  28. 'testing a different subtract sub
  29. 'Print mr$("10", "-", "5"), " 5 OK"
  30. 'Print mr$("-10", "+", "5"), " -5 OK"
  31. 'Print mr$("-10", "-", "-5"), " -5 OK"
  32. 'Print mr$("-10", "-", "5"), " -15  OK  added"
  33. 'Print mr$("10", "-", "-5"), " 15  OK  added"
  34. 'Print mr$("-.010", "-", "-5"), "4.99 OK"
  35. 'Print mr$("-.010", "-", "5"), "-5.01  OK just added"
  36. 'Print mr$(".010", "-", "5"), " -4.99 OK"
  37. ' jack error reported 2021-06-04 confirmed!  variation below
  38. 'r$ = mr$(".00000000200000000000000054307978001764", "-", ".0000000020000000000000001") '16 0 wrong  8 wrong
  39. 'Print "   mr$ rtnd:"; r$
  40. 'Print "    compare:.00000000000000000000000044307978001764" ' 2021-06-05 finally!
  41. '                  .0000000020000000000000001
  42. '                  .00000000200000000000000054307978001764
  43.  
  44. 'r$ = mr$(".00000000000000000100000000000000000011", "-", ".000000000000000001000000000000000001") ' bad too
  45. 'Print "   mr$ rtnd:"; r$
  46. '         ".000000000000000001000000000000000001"
  47. 'Print "    compare:-.00000000000000000000000000000000000089"
  48. 'r$ = mr$(".00000000000000000100000000000000000111", "-", ".000000000000000002000000000000000001")
  49. '       ".000000000000000002000000000000000001"
  50. '       ".00000000000000000100000000000000000111"
  51. '       ".00000000000000000099999999999999999989"
  52. 'Print "   mr$ rtnd:"; r$
  53. 'Print "    compare:-.00000000000000000099999999999999999989"
  54.  
  55. 'r$ = mr$(".00000000000000000000000000999", "-", "1")
  56. '-1.00000000000000000000000000000000000000000
  57. '  .00000000000000000000000000999
  58. ' -.99999999999999999999999999001
  59. 'Print "   mr$ rtnd:"; r$
  60. 'Print "    compare:-.99999999999999999999999999001"
  61.  
  62. 'r$ = mr$("1", "+", "-1000000000000000000000000000000000000000")
  63. 'Print "   mr$ rtnd:"; r$
  64. '1000000000000000000000000000000000000000
  65. '-999999999999999999999999999999999999999
  66. 'Print "    compare:-999999999999999999999999999999999999999"
  67.  
  68. ' check jack problems with FB translation  2021-06-03  errors must be in FB trans from QB64
  69. 'Print Mid$(mr$(" .1", "/", "3"), 1, 100) ' too long?
  70. 'Print Mid$(mr$("1.1", "/", "9"), 1, 100)
  71. 'Print Mid$(mr$("1.38", "/", "1.2"), 1, 100)
  72. 'Print ruler$
  73.  
  74. ' another error reported by jack 2021-06-06 fixed (same problem as subtr$)
  75. Print mr$("1.000000000000000000000001000000000000000000000001", "*", ".000000000000000000000000000000000000000000000001")
  76. Print ".000000000000000000000000000000000000000000000001"
  77. Print "                                                1000000000000000000000001000000000000000000000001"
  78. Print ruler$
  79. 'Print "checking inverse of 50 = .02 "; nInverse$("50", 20) 'OK  .020000... length 20
  80. 'Print ruler$
  81. 'Print
  82. 'Print "zzz... see inverse of STx number now takes close to 30 secs with fixed subtr$() sub,"
  83. 'Print "Use to come up in a sneeze! It also looks different way more space on end but still"
  84. 'Print "can find 115 Fibonacci terms in it."
  85. 'Print "    The only difference is I am not trimming leading 0's in subst$() function!"
  86. 'Sleep
  87. 'Cls
  88. Dim inverseSTx$, start, done
  89. start = Timer(.001)
  90. 'inverseSTx$ = nInverse$("999999999999999999999998999999999999999999999999", 2785) ' wow big delay! 19.52 secs +-
  91. inverseSTx$ = nInverse2$("999999999999999999999998999999999999999999999999", 817)
  92. ' 816 in 4.22 secs only 64 terms   817 sigDigits matching in 12.93 secs gets all 115 Fibonacci Terms
  93. done = Timer(.001) - start
  94. Print Mid$(inverseSTx$, 1, 3000)
  95. Dim As Long startSearch, termN, find
  96. Dim f1$, f2$, searchFor$
  97. f1$ = "1"
  98. f2$ = "1"
  99. startSearch = 1
  100. termN = 2
  101.     searchFor$ = mr$(f1$, "+", f2$)
  102.     find = InStr(startSearch, inverseSTx$, searchFor$)
  103.     If find Then
  104.         termN = termN + 1
  105.         Print "Term Number"; termN; " = "; searchFor$; " found at"; find
  106.         f1$ = f2$
  107.         f2$ = searchFor$
  108.         startSearch = find + Len(searchFor$)
  109.     Else
  110.         Print searchFor$; " not found."
  111.         Exit Do
  112.     End If
  113. Print "Inverse time:"; done
  114.  
  115.  
  116. 'Dim n$, result$
  117. 'Do
  118. '    'remember everything is strings
  119. '    Input "Enter a number to find it's square root "; n$
  120. '    If n$ = "" Then End
  121. '    result$ = sqrRoot$(n$)
  122. '    Print result$
  123. '    Print "Length ="; Len(result$)
  124. '    _Delay 2
  125. '    result$ = SRbyNR$(n$)
  126. '    Print result$
  127. '    Print "Length ="; Len(result$)
  128. '    Print
  129. 'Loop
  130.  
  131. Function sqrRoot$ (nmbr$)
  132.     Dim n$, guess$, lastGuess$, other$, sum$, imaginary$, loopcnt
  133.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  134.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  135.     Else
  136.         imaginary$ = "": n$ = nmbr$
  137.     End If
  138.     guess$ = mr$(n$, "/", "2")
  139.     other$ = n$
  140.     Do
  141.         loopcnt = loopcnt + 1
  142.         Print "loop cnt"; loopcnt
  143.  
  144.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  145.             sqrRoot$ = Mid$(other$, 1, 101) + imaginary$ ' try other factor for guess$  sometimes it nails answer without all digits
  146.             Exit Function
  147.         Else
  148.             lastGuess$ = guess$
  149.             sum$ = mr$(guess$, "+", other$)
  150.             guess$ = mr$(sum$, "/", "2")
  151.             other$ = mr$(n$, "/", guess$)
  152.         End If
  153.     Loop
  154.  
  155. Function SRbyNR$ (nmbr$) ' square root by Newton - Ralphson method my interpretation of GeorgeMcGinn
  156.  
  157.     Dim n$, guess$, lastGuess$, dx$, imaginary$, other$, loopcnt
  158.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  159.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  160.     Else
  161.         imaginary$ = "": n$ = nmbr$
  162.     End If
  163.  
  164.     guess$ = mr$(n$, "/", "2") ' get this going first and then try better starting guess later
  165.  
  166.     Do
  167.         loopcnt = loopcnt + 1
  168.         Print "loop cnt"; loopcnt
  169.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  170.             SRbyNR$ = Mid$(other$, 1, 101) + imaginary$
  171.             Exit Function
  172.         Else
  173.             'dx = (x - A / x) / 2: x = x - dx ' Thanks George
  174.             lastGuess$ = guess$
  175.             dx$ = mr$(mr$(guess$, "-", mr$(n$, "/", guess$)), "/", "2")
  176.             guess$ = mr$(guess$, "-", dx$)
  177.             other$ = mr$(n$, "/", guess$) ' try other factor for guess$  sometimes it nails answer without all digits
  178.         End If
  179.     Loop
  180.  
  181. 'jacks nInverse2$ modified from using 7 interations to ending when a certain amount of significant digits match between r's
  182. Function nInverse2$ (n$, SigDigits As Long) 'assume decimal at very start of the string of digits returned, no rounding
  183.     Dim x As Double
  184.     Dim As Integer d, e, k, l
  185.     Dim As String r, r2, lastR
  186.     If n$ = "0" Then nInverse2$ = "Div 0": Exit Function
  187.     If n$ = "1" Then nInverse2$ = "1": Exit Function
  188.     x = 1# / Val(n$)
  189.     r = _Trim$(Str$(x))
  190.     d = InStr(r, "D")
  191.     If d > 0 Then
  192.         e = Val(Mid$(r, d + 1))
  193.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  194.         l = Len(r)
  195.         If e > 0 Then
  196.             r = r + String$(e - l + 1, "0")
  197.         ElseIf e < 0 Then
  198.             r = "0." + String$(Abs(e) - 1, "0") + r
  199.         End If
  200.     End If
  201.     While Mid$(lastR, 1, SigDigits) <> Mid$(r, 1, SigDigits) ' use to be 7 interations
  202.         lastR = r
  203.         r2 = mr$(n$, "*", r)
  204.         r2 = mr$("2", "-", r2)
  205.         r = mr$(r, "*", r2)
  206.     Wend
  207.     nInverse2$ = r
  208.  
  209. Function mr$ (a$, op$, b$) ' catchy? mr$ for math regulator
  210.     Dim ca$, cb$, aSgn$, bSgn$, postOp$, sgn$
  211.     Dim adp As Integer, bdp As Integer, dp As Integer, lpop As Integer
  212.  
  213.     op$ = _Trim$(op$) 'save fixing each time
  214.     ca$ = _Trim$(a$): cb$ = _Trim$(b$) 'make copies in case we change
  215.     'strip signs and decimals
  216.     If Left$(ca$, 1) = "-" Then
  217.         aSgn$ = "-": ca$ = Mid$(ca$, 2)
  218.     Else
  219.         aSgn$ = "": ca$ = ca$
  220.     End If
  221.     dp = InStr(ca$, ".")
  222.     If dp > 0 Then
  223.         adp = Len(ca$) - dp
  224.         ca$ = Mid$(ca$, 1, dp - 1) + Mid$(ca$, dp + 1)
  225.     Else
  226.         adp = 0
  227.     End If
  228.     If Left$(cb$, 1) = "-" Then
  229.         bSgn$ = "-": cb$ = Mid$(cb$, 2)
  230.     Else
  231.         bSgn$ = "": cb$ = cb$
  232.     End If
  233.     dp = InStr(cb$, ".")
  234.     If dp > 0 Then
  235.         bdp = Len(cb$) - dp
  236.         cb$ = Mid$(cb$, 1, dp - 1) + Mid$(cb$, dp + 1)
  237.     Else
  238.         bdp = 0
  239.     End If
  240.  
  241.     If op$ = "+" Or op$ = "-" Or op$ = "/" Then 'add or subtr  even up strings on right of decimal
  242.         'even up the right sides of decimals if any
  243.         If adp > bdp Then dp = adp Else dp = bdp
  244.         If adp < dp Then ca$ = ca$ + String$(dp - adp, "0")
  245.         If bdp < dp Then cb$ = cb$ + String$(dp - bdp, "0")
  246.     ElseIf op$ = "*" Then
  247.         dp = adp + bdp
  248.     End If
  249.     If op$ = "*" Or op$ = "/" Then
  250.         If aSgn$ = bSgn$ Then sgn$ = "" Else sgn$ = "-"
  251.     End If
  252.     'now according to signs and op$ call add$ or subtr$
  253.     If op$ = "+" Then
  254.         If aSgn$ = bSgn$ Then 'really add
  255.             postOp$ = aSgn$ + add$(ca$, cb$)
  256.         Else 'have a case of subtraction
  257.             If aSgn$ = "-" Then postOp$ = subtr$(cb$, ca$) Else postOp$ = subtr$(ca$, cb$)
  258.         End If
  259.     ElseIf op$ = "-" Then
  260.         If bSgn$ = "-" Then 'really add but switch b sign
  261.             bSgn$ = ""
  262.             If aSgn$ = "-" Then
  263.                 postOp$ = subtr$(cb$, ca$)
  264.             Else 'aSgn = ""
  265.                 postOp$ = add$(ca$, cb$)
  266.             End If
  267.         Else 'bSgn$ =""
  268.             If aSgn$ = "-" Then
  269.                 bSgn$ = "-"
  270.                 postOp$ = aSgn$ + add$(ca$, cb$)
  271.             Else
  272.                 postOp$ = subtr$(ca$, cb$)
  273.             End If
  274.         End If
  275.     ElseIf op$ = "*" Then
  276.         postOp$ = sgn$ + mult$(ca$, cb$)
  277.     ElseIf op$ = "/" Then
  278.         postOp$ = sgn$ + divide$(ca$, cb$)
  279.     End If ' which op
  280.     'put dp back
  281.     If op$ <> "/" Then
  282.         lpop = Len(postOp$) ' put decimal back
  283.         postOp$ = Mid$(postOp$, 1, lpop - dp) + "." + Mid$(postOp$, lpop - dp + 1)
  284.     End If
  285.     mr$ = trim0$(postOp$)
  286.  
  287. Function divide$ (n$, d$) ' goal here is 100 digits precision not 100 digits past decimal
  288.     Dim di$, ndi$, nD As Integer
  289.     If _Trim$(n$) = "0" Then divide$ = "0": Exit Function
  290.     If _Trim$(d$) = "0" Then divide$ = "div 0": Exit Function
  291.     If _Trim$(d$) = "1" Then divide$ = _Trim$(n$): Exit Function
  292.  
  293.     ' aha! found a bug when d$ gets really huge 100 is no where near enough!!!!
  294.     ' 2021-06-03 fix by adding 100 to len(d$), plus have to go a little past 100 for 100 digit precision
  295.     ' need to go past 100 for 100 precise digits (not decimal places)
  296.     di$ = Mid$(nInverse$(d$, Len(d$) + 200), 2) 'chop off decimal point after
  297.     nD = Len(di$)
  298.     ndi$ = mult$(n$, di$)
  299.     ndi$ = Mid$(ndi$, 1, Len(ndi$) - nD) + "." + Right$(String$(nD, "0") + Right$(ndi$, nD), nD)
  300.     divide$ = trim0$(ndi$)
  301.  
  302. Function nInverse$ (n$, DP As Integer) 'assume decimal at very start of the string of digits returned, no rounding
  303.     Dim m$(1 To 9), si$, r$, outstr$, d$
  304.     Dim i As Integer
  305.     For i = 1 To 9
  306.         si$ = _Trim$(Str$(i))
  307.         m$(i) = mult$(si$, n$)
  308.     Next
  309.     outstr$ = ""
  310.     If n$ = "0" Then nInverse$ = "Div 0": Exit Function
  311.     If n$ = "1" Then nInverse$ = "1": Exit Function
  312.     outstr$ = "." 'everything else n > 1 is decimal 8/17
  313.     r$ = "10"
  314.     Do
  315.         While Left$(subtr$(r$, n$), 1) = "-" '   r - n < 0
  316.             outstr$ = outstr$ + "0" '            add 0 to the  output string
  317.             If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function 'check if we've reached DP length
  318.             r$ = r$ + "0"
  319.         Wend
  320.         For i = 9 To 1 Step -1
  321.             If LTE(m$(i), r$) Then d$ = _Trim$(Str$(i)): Exit For
  322.         Next
  323.         outstr$ = outstr$ + d$
  324.         If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function
  325.         r$ = subtr$(r$, mult$(d$, n$)) 'r = r -d*n
  326.         If r$ = "0" Then nInverse$ = outstr$: Exit Function 'found a perfect divisor
  327.         r$ = r$ + "0" 'add another place
  328.     Loop
  329.  
  330. Function mult$ (a$, b$) 'assume both positive integers prechecked as all digits strings
  331.     Dim la As Integer, lb As Integer, m As Integer, g As Integer, dp As Integer
  332.     Dim f18$, f1$, t$, build$, accum$
  333.     ' fixed mult$ don't trim lead 0's 2021-06-06
  334.     If _Trim$(a$) = "0" Then mult$ = "0": Exit Function
  335.     If _Trim$(b$) = "0" Then mult$ = "0": Exit Function
  336.     If _Trim$(a$) = "1" Then mult$ = _Trim$(b$): Exit Function
  337.     If _Trim$(b$) = "1" Then mult$ = _Trim$(a$): Exit Function
  338.     'find the longer number and make it a mult of 18 to take 18 digits at a time from it
  339.     la = Len(a$): lb = Len(b$)
  340.     If la > lb Then
  341.         m = Int(la / 18) + 1
  342.         f18$ = Right$(String$(m * 18, "0") + a$, m * 18)
  343.         f1$ = b$
  344.     Else
  345.         m = Int(lb / 18) + 1
  346.         f18$ = Right$(String$(m * 18, "0") + b$, m * 18)
  347.         f1$ = a$
  348.     End If
  349.     For dp = Len(f1$) To 1 Step -1 'dp = digit position of the f1$
  350.         build$ = "" 'line builder
  351.         co = 0
  352.         'now taking 18 digits at a time Thanks Steve McNeill
  353.         For g = 1 To m
  354.             v18 = Val(Mid$(f18$, m * 18 - g * 18 + 1, 18))
  355.             sd = Val(Mid$(f1$, dp, 1))
  356.             t$ = Right$(String$(19, "0") + _Trim$(Str$(v18 * sd + co)), 19)
  357.             co = Val(Mid$(t$, 1, 1))
  358.             build$ = Mid$(t$, 2) + build$
  359.         Next g
  360.         If co Then build$ = _Trim$(Str$(co)) + build$
  361.         If dp = Len(f1$) Then
  362.             accum$ = build$
  363.         Else
  364.             accum$ = add$(accum$, build$ + String$(Len(f1$) - dp, "0"))
  365.         End If
  366.     Next dp
  367.     mult$ = accum$
  368.  
  369. Function subtr$ (sum$, minus$) ' assume both numbers are positive all digits
  370.     Dim m As Integer, g As Integer, p As Integer
  371.     Dim ts$, tm$, sign$, LG$, sm$, t$, result$
  372.  
  373.     'ts$ = TrimLead0$(sum$): tm$ = TrimLead0$(minus$)   'orig with decent square root speed
  374.     ts$ = _Trim$(sum$): tm$ = _Trim$(minus$) ' fixed subtr$ 2021-06-05
  375.     If trim0(ts$) = trim0$(tm$) Then subtr$ = "0": Exit Function 'OK proceed with function knowing they are not equal
  376.     tenE18 = 1000000000000000000 'yes!!! no dang E's
  377.     If LTE(ts$, tm$) Then ' which is bigger? minus is bigger
  378.         sign$ = "-"
  379.         m = Int(Len(tm$) / 18) + 1
  380.         LG$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  381.         sm$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  382.     Else 'sum is bigger
  383.         sign$ = ""
  384.         m = Int(Len(ts$) / 18) + 1
  385.         LG$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  386.         sm$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  387.     End If
  388.     'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
  389.     For g = 1 To m
  390.         VB = Val(Mid$(LG$, m * 18 - g * 18 + 1, 18))
  391.         vs = Val(Mid$(sm$, m * 18 - g * 18 + 1, 18))
  392.         If vs > VB Then
  393.             t$ = Right$(String$(18, "0") + _Trim$(Str$(tenE18 - vs + VB)), 18)
  394.             p = (m - g) * 18
  395.             While p > 0 And Mid$(LG$, p, 1) = "0"
  396.                 Mid$(LG$, p, 1) = "9"
  397.                 p = p - 1
  398.             Wend
  399.             If p > 0 Then Mid$(LG$, p, 1) = _Trim$(Str$(Val(Mid$(LG$, p, 1)) - 1))
  400.         Else
  401.             t$ = Right$(String$(18, "0") + _Trim$(Str$(VB - vs)), 18)
  402.         End If
  403.         result$ = t$ + result$
  404.     Next
  405.     subtr$ = sign$ + result$
  406.  
  407. Function add$ (a$, b$) 'add 2 positive integers assume a and b are just numbers no spaces or - signs
  408.     'first thing is to set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
  409.     Dim la As Integer, lb As Integer, m As Integer, g As Integer
  410.     Dim fa$, fb$, t$, new$, result$
  411.     la = Len(a$): lb = Len(b$)
  412.     If la > lb Then m = Int(la / 18) + 1 Else m = Int(lb / 18) + 1
  413.     fa$ = Right$(String$(m * 18, "0") + a$, m * 18)
  414.     fb$ = Right$(String$(m * 18, "0") + b$, m * 18)
  415.  
  416.     'now taking 18 digits at a time Thanks Steve McNeill
  417.     For g = 1 To m
  418.         sa = Val(Mid$(fa$, m * 18 - g * 18 + 1, 18))
  419.         sb = Val(Mid$(fb$, m * 18 - g * 18 + 1, 18))
  420.         t$ = Right$(String$(36, "0") + _Trim$(Str$(sa + sb + co)), 36)
  421.         co = Val(Mid$(t$, 1, 18))
  422.         new$ = Mid$(t$, 19)
  423.         result$ = new$ + result$
  424.     Next
  425.     If co Then result$ = Str$(co) + result$
  426.     add$ = result$
  427.  
  428. ' String Math Helpers -----------------------------------------------
  429.  
  430. 'this function needs TrimLead0$(s$) a and b have decimal removed and a and b lengths aligned on right
  431. Function LTE (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  432.     Dim ca$, cb$, la As Integer, lb As Integer, i As Integer
  433.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  434.     la = Len(ca$): lb = Len(cb$)
  435.     If ca$ = cb$ Then
  436.         LTE = -1
  437.     ElseIf la < lb Then ' a is smaller
  438.         LTE = -1
  439.     ElseIf la > lb Then ' a is bigger
  440.         LTE = 0
  441.     ElseIf la = lb Then ' equal lengths
  442.         For i = 1 To Len(ca$)
  443.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  444.                 LTE = 0: Exit Function
  445.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  446.                 LTE = -1: Exit Function
  447.             End If
  448.         Next
  449.     End If
  450.  
  451. ' ------------------------------------- use these for final display
  452.  
  453. Function TrimLead0$ (s$) 'for treating strings as number (pos integers)
  454.     Dim copys$, i As Integer, find As Integer
  455.     copys$ = _Trim$(s$) 'might as well remove spaces too
  456.     i = 1: find = 0
  457.     While i < Len(copys$) And Mid$(copys$, i, 1) = "0"
  458.         i = i + 1: find = 1
  459.     Wend
  460.     If find = 1 Then copys$ = Mid$(copys$, i)
  461.     If copys$ = "" Then TrimLead0$ = "0" Else TrimLead0$ = copys$
  462.  
  463. Function TrimTail0$ (s$)
  464.     Dim copys$, dp As Integer, i As Integer, find As Integer
  465.     copys$ = _Trim$(s$) 'might as well remove spaces too
  466.     TrimTail0$ = copys$
  467.     dp = InStr(copys$, ".")
  468.     If dp > 0 Then
  469.         i = Len(copys$): find = 0
  470.         While i > dp And Mid$(copys$, i, 1) = "0"
  471.             i = i - 1: find = 1
  472.         Wend
  473.         If find = 1 Then
  474.             If i = dp Then
  475.                 TrimTail0$ = Mid$(copys$, 1, dp - 1)
  476.             Else
  477.                 TrimTail0$ = Mid$(copys$, 1, i)
  478.             End If
  479.         End If
  480.     End If
  481.  
  482. Function trim0$ (s$)
  483.     Dim cs$, si$
  484.     cs$ = s$
  485.     si$ = Left$(cs$, 1)
  486.     If si$ = "-" Then cs$ = Mid$(cs$, 2)
  487.     cs$ = TrimLead0$(cs$)
  488.     cs$ = TrimTail0$(cs$)
  489.     If Right$(cs$, 1) = "." Then cs$ = Mid$(cs$, 1, Len(cs$) - 1)
  490.     If si$ = "-" Then trim0$ = si$ + cs$ Else trim0$ = cs$
  491.  
  492. ' for displaying truncated numbers say to 60 digits
  493. Function showDP$ (num$, nDP As Integer)
  494.     Dim cNum$, dp As Integer, d As Integer, i As Integer
  495.     cNum$ = num$ 'since num$ could get changed
  496.     showDP$ = num$
  497.     dp = InStr(num$, ".")
  498.     If dp > 0 Then
  499.         If Len(Mid$(cNum$, dp + 1)) > nDP Then
  500.             d = Val(Mid$(cNum$, dp + nDP + 1, 1))
  501.             If d > 4 Then
  502.                 cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
  503.                 dp = dp + 1
  504.                 i = dp + nDP
  505.                 While Mid$(cNum$, i, 1) = "9" Or Mid$(cNum$, i, 1) = "."
  506.                     If Mid$(cNum$, i, 1) = "9" Then
  507.                         Mid$(cNum$, i, 1) = "0"
  508.                     End If
  509.                     i = i - 1
  510.                 Wend
  511.                 Mid$(cNum$, i, 1) = _Trim$(Str$(Val(Mid$(cNum$, i, 1)) + 1)) 'last non 9 digit
  512.                 cNum$ = Mid$(cNum$, 1, dp + nDP) 'chop it
  513.                 showDP$ = trim0$(cNum$)
  514.             Else
  515.                 showDP$ = Mid$(cNum$, 1, dp + nDP)
  516.             End If
  517.         End If
  518.     End If
  519.  
  520.  
  521.  
« Last Edit: June 06, 2021, 01:04:24 pm by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #55 on: June 06, 2021, 01:45:34 pm »
bplus
if you would set all your routines to a limit of say 128 digits - integer + fractional, then your operations would be relatively fast, nInverse would require only 3 iterations to give 128 digits of accuracy - you could dispense the loop and loop-test
as it is, your strings grow huge and the routines become very slow, that's why in my sqrt$ routine I would keep trimming the resulting strings
< edit > or you could go to 256 digits, nInverse would only require 4 iterations
« Last Edit: June 06, 2021, 01:49:44 pm by jack »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #56 on: June 06, 2021, 05:37:13 pm »
here's a different way to print the Fibonacci numbers
Code: QB64: [Select]
  1. _Title "Math regulator mr test sqr estimating" ' b+ start 2021-06-02
  2. ' divide$ found fix? 2021-06-03 comment in that function
  3. ' 2021-06-03 update with new sqrRoot$ Function
  4. ' 2021-06-06 fixed divide, subtr and mult, all were trimming lead 0's and messing up decimal settings.
  5. ' 2021-06-06 test jack's nInverse2$() on STx # to find 115 terms of Fibannci.
  6.  
  7. Randomize Timer 'now that it's seems to be running silent
  8. Screen _NewImage(1200, 1000, 32)
  9. _Delay .25
  10.  
  11. ' jack error reported 2021-06-04 confirmed!   fixed
  12. 'Print mr$(".00000000000000000000000000000000000000000000200000000000000054307978001764", "-", ".000000000000000000000000000000000000000000002")
  13. 'Print ".00000000000000000000000000000000000000000000000000000000000054307978001764"
  14.  
  15. Dim r$, ruler$
  16. ruler$ = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + Chr$(10)
  17. ruler$ = ruler$ + "0         1         2         3         4         5         6         7         8         9        10        11        12"
  18. ' debug tests
  19. 'Print mr$("-5", "+", "-2100"), " OK if -2105"
  20. 'Print mr$("." + String$(20, "0") + "1", "+", "1" + String$(40, "0") + "1") ' first real test of add
  21. 'Print ruler$
  22. 'Print Val("." + String$(20, "0") + "1") + Val("1" + String$(40, "0") + "1") ' test print of big and small val
  23. 'Print mr$("-.00071", "+", ".00036" + String$(35, "0") + "9")
  24. '-.00071
  25. ' .00036000000000000000000000000000000000009
  26. 'Print "-.00034999999999999999999999999999999999991"
  27. 'Print ruler$
  28. 'testing a different subtract sub
  29. 'Print mr$("10", "-", "5"), " 5 OK"
  30. 'Print mr$("-10", "+", "5"), " -5 OK"
  31. 'Print mr$("-10", "-", "-5"), " -5 OK"
  32. 'Print mr$("-10", "-", "5"), " -15  OK  added"
  33. 'Print mr$("10", "-", "-5"), " 15  OK  added"
  34. 'Print mr$("-.010", "-", "-5"), "4.99 OK"
  35. 'Print mr$("-.010", "-", "5"), "-5.01  OK just added"
  36. 'Print mr$(".010", "-", "5"), " -4.99 OK"
  37. ' jack error reported 2021-06-04 confirmed!  variation below
  38. 'r$ = mr$(".00000000200000000000000054307978001764", "-", ".0000000020000000000000001") '16 0 wrong  8 wrong
  39. 'Print "   mr$ rtnd:"; r$
  40. 'Print "    compare:.00000000000000000000000044307978001764" ' 2021-06-05 finally!
  41. '                  .0000000020000000000000001
  42. '                  .00000000200000000000000054307978001764
  43.  
  44. 'r$ = mr$(".00000000000000000100000000000000000011", "-", ".000000000000000001000000000000000001") ' bad too
  45. 'Print "   mr$ rtnd:"; r$
  46. '         ".000000000000000001000000000000000001"
  47. 'Print "    compare:-.00000000000000000000000000000000000089"
  48. 'r$ = mr$(".00000000000000000100000000000000000111", "-", ".000000000000000002000000000000000001")
  49. '       ".000000000000000002000000000000000001"
  50. '       ".00000000000000000100000000000000000111"
  51. '       ".00000000000000000099999999999999999989"
  52. 'Print "   mr$ rtnd:"; r$
  53. 'Print "    compare:-.00000000000000000099999999999999999989"
  54.  
  55. 'r$ = mr$(".00000000000000000000000000999", "-", "1")
  56. '-1.00000000000000000000000000000000000000000
  57. '  .00000000000000000000000000999
  58. ' -.99999999999999999999999999001
  59. 'Print "   mr$ rtnd:"; r$
  60. 'Print "    compare:-.99999999999999999999999999001"
  61.  
  62. 'r$ = mr$("1", "+", "-1000000000000000000000000000000000000000")
  63. 'Print "   mr$ rtnd:"; r$
  64. '1000000000000000000000000000000000000000
  65. '-999999999999999999999999999999999999999
  66. 'Print "    compare:-999999999999999999999999999999999999999"
  67.  
  68. ' check jack problems with FB translation  2021-06-03  errors must be in FB trans from QB64
  69. 'Print Mid$(mr$(" .1", "/", "3"), 1, 100) ' too long?
  70. 'Print Mid$(mr$("1.1", "/", "9"), 1, 100)
  71. 'Print Mid$(mr$("1.38", "/", "1.2"), 1, 100)
  72. 'Print ruler$
  73.  
  74. ' another error reported by jack 2021-06-06 fixed (same problem as subtr$)
  75. Print mr$("1.000000000000000000000001000000000000000000000001", "*", ".000000000000000000000000000000000000000000000001")
  76. Print ".000000000000000000000000000000000000000000000001"
  77. Print "                                                1000000000000000000000001000000000000000000000001"
  78. Print ruler$
  79. 'Print "checking inverse of 50 = .02 "; nInverse$("50", 20) 'OK  .020000... length 20
  80. 'Print ruler$
  81. 'Print
  82. 'Print "zzz... see inverse of STx number now takes close to 30 secs with fixed subtr$() sub,"
  83. 'Print "Use to come up in a sneeze! It also looks different way more space on end but still"
  84. 'Print "can find 115 Fibonacci terms in it."
  85. 'Print "    The only difference is I am not trimming leading 0's in subst$() function!"
  86. 'Sleep
  87. 'Cls
  88. Dim inverseSTx$, start, done
  89. start = Timer(.001)
  90. 'inverseSTx$ = nInverse$("999999999999999999999998999999999999999999999999", 2785) ' wow big delay! 19.52 secs +-
  91. inverseSTx$ = nInverse2$("999999999999999999999998999999999999999999999999", 817)
  92. ' 816 in 4.22 secs only 64 terms   817 sigDigits matching in 12.93 secs gets all 115 Fibonacci Terms
  93. done = Timer(.001) - start
  94.  
  95. Print Mid$(inverseSTx$, 1, 3000)
  96. Dim As Long startSearch, termN, find
  97. Dim f1$, f2$, searchFor$
  98. Dim As Long i, j
  99. Print "inverseSTx$ length = "; Len(inverseSTx$)
  100. j = InStr(inverseSTx$, ".")
  101. inverseSTx$ = Mid$(inverseSTx$, j + 1)
  102. j = 1
  103. For i = 1 To 58
  104.     Print Mid$(inverseSTx$, j, 24), Mid$(inverseSTx$, j + 24, 24)
  105.     j = j + 48
  106.  
  107. 'f1$ = "1"
  108. 'f2$ = "1"
  109. 'startSearch = 1
  110. 'termN = 2
  111. 'Do
  112. '    searchFor$ = mr$(f1$, "+", f2$)
  113. '    find = InStr(startSearch, inverseSTx$, searchFor$)
  114. '    If find Then
  115. '        termN = termN + 1
  116. '        Print "Term Number"; termN; " = "; searchFor$; " found at"; find
  117. '        f1$ = f2$
  118. '        f2$ = searchFor$
  119. '        startSearch = find + Len(searchFor$)
  120. '    Else
  121. '        Print searchFor$; " not found."
  122. '        Exit Do
  123. '    End If
  124. 'Loop
  125. 'Print "Inverse time:"; done
  126.  
  127.  
  128. 'Dim n$, result$
  129. 'Do
  130. '    'remember everything is strings
  131. '    Input "Enter a number to find it's square root "; n$
  132. '    If n$ = "" Then End
  133. '    result$ = sqrRoot$(n$)
  134. '    Print result$
  135. '    Print "Length ="; Len(result$)
  136. '    _Delay 2
  137. '    result$ = SRbyNR$(n$)
  138. '    Print result$
  139. '    Print "Length ="; Len(result$)
  140. '    Print
  141. 'Loop
  142.  
  143. Function sqrRoot$ (nmbr$)
  144.     Dim n$, guess$, lastGuess$, other$, sum$, imaginary$, loopcnt
  145.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  146.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  147.     Else
  148.         imaginary$ = "": n$ = nmbr$
  149.     End If
  150.     guess$ = mr$(n$, "/", "2")
  151.     other$ = n$
  152.     Do
  153.         loopcnt = loopcnt + 1
  154.         Print "loop cnt"; loopcnt
  155.  
  156.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  157.             sqrRoot$ = Mid$(other$, 1, 101) + imaginary$ ' try other factor for guess$  sometimes it nails answer without all digits
  158.             Exit Function
  159.         Else
  160.             lastGuess$ = guess$
  161.             sum$ = mr$(guess$, "+", other$)
  162.             guess$ = mr$(sum$, "/", "2")
  163.             other$ = mr$(n$, "/", guess$)
  164.         End If
  165.     Loop
  166.  
  167. Function SRbyNR$ (nmbr$) ' square root by Newton - Ralphson method my interpretation of GeorgeMcGinn
  168.  
  169.     Dim n$, guess$, lastGuess$, dx$, imaginary$, other$, loopcnt
  170.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  171.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  172.     Else
  173.         imaginary$ = "": n$ = nmbr$
  174.     End If
  175.  
  176.     guess$ = mr$(n$, "/", "2") ' get this going first and then try better starting guess later
  177.  
  178.     Do
  179.         loopcnt = loopcnt + 1
  180.         Print "loop cnt"; loopcnt
  181.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then ' go past 100 matching digits for 100 digit precision
  182.             SRbyNR$ = Mid$(other$, 1, 101) + imaginary$
  183.             Exit Function
  184.         Else
  185.             'dx = (x - A / x) / 2: x = x - dx ' Thanks George
  186.             lastGuess$ = guess$
  187.             dx$ = mr$(mr$(guess$, "-", mr$(n$, "/", guess$)), "/", "2")
  188.             guess$ = mr$(guess$, "-", dx$)
  189.             other$ = mr$(n$, "/", guess$) ' try other factor for guess$  sometimes it nails answer without all digits
  190.         End If
  191.     Loop
  192.  
  193. 'jacks nInverse2$ modified from using 7 interations to ending when a certain amount of significant digits match between r's
  194. Function nInverse2$ (n$, SigDigits As Long) 'assume decimal at very start of the string of digits returned, no rounding
  195.     Dim x As Double
  196.     Dim As Integer d, e, k, l
  197.     Dim As String r, r2, lastR
  198.     If n$ = "0" Then nInverse2$ = "Div 0": Exit Function
  199.     If n$ = "1" Then nInverse2$ = "1": Exit Function
  200.     x = 1# / Val(n$)
  201.     r = _Trim$(Str$(x))
  202.     d = InStr(r, "D")
  203.     If d > 0 Then
  204.         e = Val(Mid$(r, d + 1))
  205.         r = Left$(r, 1) + Mid$(Left$(r, d - 1), 3)
  206.         l = Len(r)
  207.         If e > 0 Then
  208.             r = r + String$(e - l + 1, "0")
  209.         ElseIf e < 0 Then
  210.             r = "0." + String$(Abs(e) - 1, "0") + r
  211.         End If
  212.     End If
  213.     While Mid$(lastR, 1, SigDigits) <> Mid$(r, 1, SigDigits) ' use to be 7 interations
  214.         lastR = r
  215.         r2 = mr$(n$, "*", r)
  216.         r2 = mr$("2", "-", r2)
  217.         r = mr$(r, "*", r2)
  218.     Wend
  219.     nInverse2$ = r
  220.  
  221. Function mr$ (a$, op$, b$) ' catchy? mr$ for math regulator
  222.     Dim ca$, cb$, aSgn$, bSgn$, postOp$, sgn$
  223.     Dim adp As Integer, bdp As Integer, dp As Integer, lpop As Integer
  224.  
  225.     op$ = _Trim$(op$) 'save fixing each time
  226.     ca$ = _Trim$(a$): cb$ = _Trim$(b$) 'make copies in case we change
  227.     'strip signs and decimals
  228.     If Left$(ca$, 1) = "-" Then
  229.         aSgn$ = "-": ca$ = Mid$(ca$, 2)
  230.     Else
  231.         aSgn$ = "": ca$ = ca$
  232.     End If
  233.     dp = InStr(ca$, ".")
  234.     If dp > 0 Then
  235.         adp = Len(ca$) - dp
  236.         ca$ = Mid$(ca$, 1, dp - 1) + Mid$(ca$, dp + 1)
  237.     Else
  238.         adp = 0
  239.     End If
  240.     If Left$(cb$, 1) = "-" Then
  241.         bSgn$ = "-": cb$ = Mid$(cb$, 2)
  242.     Else
  243.         bSgn$ = "": cb$ = cb$
  244.     End If
  245.     dp = InStr(cb$, ".")
  246.     If dp > 0 Then
  247.         bdp = Len(cb$) - dp
  248.         cb$ = Mid$(cb$, 1, dp - 1) + Mid$(cb$, dp + 1)
  249.     Else
  250.         bdp = 0
  251.     End If
  252.  
  253.     If op$ = "+" Or op$ = "-" Or op$ = "/" Then 'add or subtr  even up strings on right of decimal
  254.         'even up the right sides of decimals if any
  255.         If adp > bdp Then dp = adp Else dp = bdp
  256.         If adp < dp Then ca$ = ca$ + String$(dp - adp, "0")
  257.         If bdp < dp Then cb$ = cb$ + String$(dp - bdp, "0")
  258.     ElseIf op$ = "*" Then
  259.         dp = adp + bdp
  260.     End If
  261.     If op$ = "*" Or op$ = "/" Then
  262.         If aSgn$ = bSgn$ Then sgn$ = "" Else sgn$ = "-"
  263.     End If
  264.     'now according to signs and op$ call add$ or subtr$
  265.     If op$ = "+" Then
  266.         If aSgn$ = bSgn$ Then 'really add
  267.             postOp$ = aSgn$ + add$(ca$, cb$)
  268.         Else 'have a case of subtraction
  269.             If aSgn$ = "-" Then postOp$ = subtr$(cb$, ca$) Else postOp$ = subtr$(ca$, cb$)
  270.         End If
  271.     ElseIf op$ = "-" Then
  272.         If bSgn$ = "-" Then 'really add but switch b sign
  273.             bSgn$ = ""
  274.             If aSgn$ = "-" Then
  275.                 postOp$ = subtr$(cb$, ca$)
  276.             Else 'aSgn = ""
  277.                 postOp$ = add$(ca$, cb$)
  278.             End If
  279.         Else 'bSgn$ =""
  280.             If aSgn$ = "-" Then
  281.                 bSgn$ = "-"
  282.                 postOp$ = aSgn$ + add$(ca$, cb$)
  283.             Else
  284.                 postOp$ = subtr$(ca$, cb$)
  285.             End If
  286.         End If
  287.     ElseIf op$ = "*" Then
  288.         postOp$ = sgn$ + mult$(ca$, cb$)
  289.     ElseIf op$ = "/" Then
  290.         postOp$ = sgn$ + divide$(ca$, cb$)
  291.     End If ' which op
  292.     'put dp back
  293.     If op$ <> "/" Then
  294.         lpop = Len(postOp$) ' put decimal back
  295.         postOp$ = Mid$(postOp$, 1, lpop - dp) + "." + Mid$(postOp$, lpop - dp + 1)
  296.     End If
  297.     mr$ = trim0$(postOp$)
  298.  
  299. Function divide$ (n$, d$) ' goal here is 100 digits precision not 100 digits past decimal
  300.     Dim di$, ndi$, nD As Integer
  301.     If _Trim$(n$) = "0" Then divide$ = "0": Exit Function
  302.     If _Trim$(d$) = "0" Then divide$ = "div 0": Exit Function
  303.     If _Trim$(d$) = "1" Then divide$ = _Trim$(n$): Exit Function
  304.  
  305.     ' aha! found a bug when d$ gets really huge 100 is no where near enough!!!!
  306.     ' 2021-06-03 fix by adding 100 to len(d$), plus have to go a little past 100 for 100 digit precision
  307.     ' need to go past 100 for 100 precise digits (not decimal places)
  308.     di$ = Mid$(nInverse$(d$, Len(d$) + 200), 2) 'chop off decimal point after
  309.     nD = Len(di$)
  310.     ndi$ = mult$(n$, di$)
  311.     ndi$ = Mid$(ndi$, 1, Len(ndi$) - nD) + "." + Right$(String$(nD, "0") + Right$(ndi$, nD), nD)
  312.     divide$ = trim0$(ndi$)
  313.  
  314. Function nInverse$ (n$, DP As Integer) 'assume decimal at very start of the string of digits returned, no rounding
  315.     Dim m$(1 To 9), si$, r$, outstr$, d$
  316.     Dim i As Integer
  317.     For i = 1 To 9
  318.         si$ = _Trim$(Str$(i))
  319.         m$(i) = mult$(si$, n$)
  320.     Next
  321.     outstr$ = ""
  322.     If n$ = "0" Then nInverse$ = "Div 0": Exit Function
  323.     If n$ = "1" Then nInverse$ = "1": Exit Function
  324.     outstr$ = "." 'everything else n > 1 is decimal 8/17
  325.     r$ = "10"
  326.     Do
  327.         While Left$(subtr$(r$, n$), 1) = "-" '   r - n < 0
  328.             outstr$ = outstr$ + "0" '            add 0 to the  output string
  329.             If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function 'check if we've reached DP length
  330.             r$ = r$ + "0"
  331.         Wend
  332.         For i = 9 To 1 Step -1
  333.             If LTE(m$(i), r$) Then d$ = _Trim$(Str$(i)): Exit For
  334.         Next
  335.         outstr$ = outstr$ + d$
  336.         If Len(outstr$) = DP Then nInverse$ = outstr$: Exit Function
  337.         r$ = subtr$(r$, mult$(d$, n$)) 'r = r -d*n
  338.         If r$ = "0" Then nInverse$ = outstr$: Exit Function 'found a perfect divisor
  339.         r$ = r$ + "0" 'add another place
  340.     Loop
  341.  
  342. Function mult$ (a$, b$) 'assume both positive integers prechecked as all digits strings
  343.     Dim la As Integer, lb As Integer, m As Integer, g As Integer, dp As Integer
  344.     Dim f18$, f1$, t$, build$, accum$
  345.     ' fixed mult$ don't trim lead 0's 2021-06-06
  346.     If _Trim$(a$) = "0" Then mult$ = "0": Exit Function
  347.     If _Trim$(b$) = "0" Then mult$ = "0": Exit Function
  348.     If _Trim$(a$) = "1" Then mult$ = _Trim$(b$): Exit Function
  349.     If _Trim$(b$) = "1" Then mult$ = _Trim$(a$): Exit Function
  350.     'find the longer number and make it a mult of 18 to take 18 digits at a time from it
  351.     la = Len(a$): lb = Len(b$)
  352.     If la > lb Then
  353.         m = Int(la / 18) + 1
  354.         f18$ = Right$(String$(m * 18, "0") + a$, m * 18)
  355.         f1$ = b$
  356.     Else
  357.         m = Int(lb / 18) + 1
  358.         f18$ = Right$(String$(m * 18, "0") + b$, m * 18)
  359.         f1$ = a$
  360.     End If
  361.     For dp = Len(f1$) To 1 Step -1 'dp = digit position of the f1$
  362.         build$ = "" 'line builder
  363.         co = 0
  364.         'now taking 18 digits at a time Thanks Steve McNeill
  365.         For g = 1 To m
  366.             v18 = Val(Mid$(f18$, m * 18 - g * 18 + 1, 18))
  367.             sd = Val(Mid$(f1$, dp, 1))
  368.             t$ = Right$(String$(19, "0") + _Trim$(Str$(v18 * sd + co)), 19)
  369.             co = Val(Mid$(t$, 1, 1))
  370.             build$ = Mid$(t$, 2) + build$
  371.         Next g
  372.         If co Then build$ = _Trim$(Str$(co)) + build$
  373.         If dp = Len(f1$) Then
  374.             accum$ = build$
  375.         Else
  376.             accum$ = add$(accum$, build$ + String$(Len(f1$) - dp, "0"))
  377.         End If
  378.     Next dp
  379.     mult$ = accum$
  380.  
  381. Function subtr$ (sum$, minus$) ' assume both numbers are positive all digits
  382.     Dim m As Integer, g As Integer, p As Integer
  383.     Dim ts$, tm$, sign$, LG$, sm$, t$, result$
  384.  
  385.     'ts$ = TrimLead0$(sum$): tm$ = TrimLead0$(minus$)   'orig with decent square root speed
  386.     ts$ = _Trim$(sum$): tm$ = _Trim$(minus$) ' fixed subtr$ 2021-06-05
  387.     If trim0(ts$) = trim0$(tm$) Then subtr$ = "0": Exit Function 'OK proceed with function knowing they are not equal
  388.     tenE18 = 1000000000000000000 'yes!!! no dang E's
  389.     If LTE(ts$, tm$) Then ' which is bigger? minus is bigger
  390.         sign$ = "-"
  391.         m = Int(Len(tm$) / 18) + 1
  392.         LG$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  393.         sm$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  394.     Else 'sum is bigger
  395.         sign$ = ""
  396.         m = Int(Len(ts$) / 18) + 1
  397.         LG$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  398.         sm$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  399.     End If
  400.     'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
  401.     For g = 1 To m
  402.         VB = Val(Mid$(LG$, m * 18 - g * 18 + 1, 18))
  403.         vs = Val(Mid$(sm$, m * 18 - g * 18 + 1, 18))
  404.         If vs > VB Then
  405.             t$ = Right$(String$(18, "0") + _Trim$(Str$(tenE18 - vs + VB)), 18)
  406.             p = (m - g) * 18
  407.             While p > 0 And Mid$(LG$, p, 1) = "0"
  408.                 Mid$(LG$, p, 1) = "9"
  409.                 p = p - 1
  410.             Wend
  411.             If p > 0 Then Mid$(LG$, p, 1) = _Trim$(Str$(Val(Mid$(LG$, p, 1)) - 1))
  412.         Else
  413.             t$ = Right$(String$(18, "0") + _Trim$(Str$(VB - vs)), 18)
  414.         End If
  415.         result$ = t$ + result$
  416.     Next
  417.     subtr$ = sign$ + result$
  418.  
  419. Function add$ (a$, b$) 'add 2 positive integers assume a and b are just numbers no spaces or - signs
  420.     'first thing is to set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
  421.     Dim la As Integer, lb As Integer, m As Integer, g As Integer
  422.     Dim fa$, fb$, t$, new$, result$
  423.     la = Len(a$): lb = Len(b$)
  424.     If la > lb Then m = Int(la / 18) + 1 Else m = Int(lb / 18) + 1
  425.     fa$ = Right$(String$(m * 18, "0") + a$, m * 18)
  426.     fb$ = Right$(String$(m * 18, "0") + b$, m * 18)
  427.  
  428.     'now taking 18 digits at a time Thanks Steve McNeill
  429.     For g = 1 To m
  430.         sa = Val(Mid$(fa$, m * 18 - g * 18 + 1, 18))
  431.         sb = Val(Mid$(fb$, m * 18 - g * 18 + 1, 18))
  432.         t$ = Right$(String$(36, "0") + _Trim$(Str$(sa + sb + co)), 36)
  433.         co = Val(Mid$(t$, 1, 18))
  434.         new$ = Mid$(t$, 19)
  435.         result$ = new$ + result$
  436.     Next
  437.     If co Then result$ = Str$(co) + result$
  438.     add$ = result$
  439.  
  440. ' String Math Helpers -----------------------------------------------
  441.  
  442. 'this function needs TrimLead0$(s$) a and b have decimal removed and a and b lengths aligned on right
  443. Function LTE (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  444.     Dim ca$, cb$, la As Integer, lb As Integer, i As Integer
  445.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  446.     la = Len(ca$): lb = Len(cb$)
  447.     If ca$ = cb$ Then
  448.         LTE = -1
  449.     ElseIf la < lb Then ' a is smaller
  450.         LTE = -1
  451.     ElseIf la > lb Then ' a is bigger
  452.         LTE = 0
  453.     ElseIf la = lb Then ' equal lengths
  454.         For i = 1 To Len(ca$)
  455.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  456.                 LTE = 0: Exit Function
  457.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  458.                 LTE = -1: Exit Function
  459.             End If
  460.         Next
  461.     End If
  462.  
  463. ' ------------------------------------- use these for final display
  464.  
  465. Function TrimLead0$ (s$) 'for treating strings as number (pos integers)
  466.     Dim copys$, i As Integer, find As Integer
  467.     copys$ = _Trim$(s$) 'might as well remove spaces too
  468.     i = 1: find = 0
  469.     While i < Len(copys$) And Mid$(copys$, i, 1) = "0"
  470.         i = i + 1: find = 1
  471.     Wend
  472.     If find = 1 Then copys$ = Mid$(copys$, i)
  473.     If copys$ = "" Then TrimLead0$ = "0" Else TrimLead0$ = copys$
  474.  
  475. Function TrimTail0$ (s$)
  476.     Dim copys$, dp As Integer, i As Integer, find As Integer
  477.     copys$ = _Trim$(s$) 'might as well remove spaces too
  478.     TrimTail0$ = copys$
  479.     dp = InStr(copys$, ".")
  480.     If dp > 0 Then
  481.         i = Len(copys$): find = 0
  482.         While i > dp And Mid$(copys$, i, 1) = "0"
  483.             i = i - 1: find = 1
  484.         Wend
  485.         If find = 1 Then
  486.             If i = dp Then
  487.                 TrimTail0$ = Mid$(copys$, 1, dp - 1)
  488.             Else
  489.                 TrimTail0$ = Mid$(copys$, 1, i)
  490.             End If
  491.         End If
  492.     End If
  493.  
  494. Function trim0$ (s$)
  495.     Dim cs$, si$
  496.     cs$ = s$
  497.     si$ = Left$(cs$, 1)
  498.     If si$ = "-" Then cs$ = Mid$(cs$, 2)
  499.     cs$ = TrimLead0$(cs$)
  500.     cs$ = TrimTail0$(cs$)
  501.     If Right$(cs$, 1) = "." Then cs$ = Mid$(cs$, 1, Len(cs$) - 1)
  502.     If si$ = "-" Then trim0$ = si$ + cs$ Else trim0$ = cs$
  503.  
  504. ' for displaying truncated numbers say to 60 digits
  505. Function showDP$ (num$, nDP As Integer)
  506.     Dim cNum$, dp As Integer, d As Integer, i As Integer
  507.     cNum$ = num$ 'since num$ could get changed
  508.     showDP$ = num$
  509.     dp = InStr(num$, ".")
  510.     If dp > 0 Then
  511.         If Len(Mid$(cNum$, dp + 1)) > nDP Then
  512.             d = Val(Mid$(cNum$, dp + nDP + 1, 1))
  513.             If d > 4 Then
  514.                 cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
  515.                 dp = dp + 1
  516.                 i = dp + nDP
  517.                 While Mid$(cNum$, i, 1) = "9" Or Mid$(cNum$, i, 1) = "."
  518.                     If Mid$(cNum$, i, 1) = "9" Then
  519.                         Mid$(cNum$, i, 1) = "0"
  520.                     End If
  521.                     i = i - 1
  522.                 Wend
  523.                 Mid$(cNum$, i, 1) = _Trim$(Str$(Val(Mid$(cNum$, i, 1)) + 1)) 'last non 9 digit
  524.                 cNum$ = Mid$(cNum$, 1, dp + nDP) 'chop it
  525.                 showDP$ = trim0$(cNum$)
  526.             Else
  527.                 showDP$ = Mid$(cNum$, 1, dp + nDP)
  528.             End If
  529.         End If
  530.     End If
  531.  

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: String Math
« Reply #57 on: June 06, 2021, 11:32:23 pm »

Marked as best answer by bplus on June 14, 2021, 12:04:56 pm

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: String Math
« Reply #58 on: June 14, 2021, 04:04:41 pm »
Here is current state of the art for String Math. A number of fixes and improvements including sqrRoot$(), approx 412 LOC for the copy/paste procedures into your app.

Code: QB64: [Select]
  1. _Title "String Math 2021-06-14" ' b+ from SM2 (2021 June) a bunch of experiments to fix and improve speeds.
  2. ' June 2021 fix some old String Math procedures, better nInverse with new LT frunction, remove experimental procedures.
  3. ' Now with decent sqrRoot it works independent of Mr$() = Math Regulator that handles signs and decimals and calls to
  4. ' add$(), subtr$, mult$, divide$ (100 significant digits),  add$(), subtr$, mult$ are exact!
  5. ' If you need higher precsion divide, I recommend use nInverse on denominator (integer)
  6. ' then add sign and decimal and mult$() that number with numerator to get divsion answer in higher precision than 100.
  7. ' (See how Mr$() handles division and just call nInverse$ with what precision you need.)
  8. ' The final function showDP$() is for displaying these number to a set amount of Decimal Places.
  9.  
  10. ' The main code is sampler of tests performed with these functions.
  11.  
  12. Randomize Timer 'now that it's seems to be running silent
  13. Screen _NewImage(1200, 700, 32)
  14. _Delay .25
  15.  
  16. 'test new stuff
  17. 'Print mult3$("11", "1001")
  18. 'End
  19.  
  20. Dim r$, ruler$
  21. ruler$ = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + Chr$(10)
  22. ruler$ = ruler$ + "0         1         2         3         4         5         6         7         8         9        10        11        12"
  23.  
  24. ' jack error reported 2021-06-04 confirmed!   fixed
  25. Print mr$(".00000000000000000000000000000000000000000000200000000000000054307978001764", "-", ".000000000000000000000000000000000000000000002")
  26. Print ".00000000000000000000000000000000000000000000000000000000000054307978001764"
  27. ' debug tests
  28. Print mr$("-5", "+", "-2100"), " OK if -2105"
  29. Print mr$("." + String$(20, "0") + "1", "+", "1" + String$(40, "0") + "1") ' first real test of add
  30. Print ruler$
  31. Print Val("." + String$(20, "0") + "1") + Val("1" + String$(40, "0") + "1") ' test print of big and small val
  32. Print mr$("-.00071", "+", ".00036" + String$(35, "0") + "9")
  33. '-.00071
  34. ' .00036000000000000000000000000000000000009
  35. Print "-.00034999999999999999999999999999999999991"
  36.  
  37. 'testing a different subtract sub
  38. Print mr$("10", "-", "5"), " 5 OK"
  39. Print mr$("-10", "+", "5"), " -5 OK"
  40. Print mr$("-10", "-", "-5"), " -5 OK"
  41. Print mr$("-10", "-", "5"), " -15  OK  added"
  42. Print mr$("10", "-", "-5"), " 15  OK  added"
  43. Print mr$("-.010", "-", "-5"), "4.99 OK"
  44. Print mr$("-.010", "-", "5"), "-5.01  OK just added"
  45. Print mr$(".010", "-", "5"), " -4.99 OK"
  46. ' jack error reported 2021-06-04 confirmed!  variation below
  47. r$ = mr$(".00000000200000000000000054307978001764", "-", ".0000000020000000000000001") '16 0 wrong  8 wrong
  48. Print "   mr$ rtnd:"; r$
  49. Print "    compare:.00000000000000000000000044307978001764" ' 2021-06-05 finally!
  50. '                  .0000000020000000000000001
  51. '                  .00000000200000000000000054307978001764
  52.  
  53. r$ = mr$(".00000000000000000100000000000000000011", "-", ".000000000000000001000000000000000001") ' bad too
  54. Print "   mr$ rtnd:"; r$
  55. '         ".000000000000000001000000000000000001"
  56. Print "    compare:-.00000000000000000000000000000000000089"
  57. r$ = mr$(".00000000000000000100000000000000000111", "-", ".000000000000000002000000000000000001")
  58. '       ".000000000000000002000000000000000001"
  59. '       ".00000000000000000100000000000000000111"
  60. '       ".00000000000000000099999999999999999989"
  61. Print "   mr$ rtnd:"; r$
  62. Print "    compare:-.00000000000000000099999999999999999989"
  63.  
  64. r$ = mr$(".00000000000000000000000000999", "-", "1")
  65. '-1.00000000000000000000000000000000000000000
  66. '  .00000000000000000000000000999
  67. ' -.99999999999999999999999999001
  68. Print "   mr$ rtnd:"; r$
  69. Print "    compare:-.99999999999999999999999999001"
  70.  
  71. r$ = mr$("1", "+", "-1000000000000000000000000000000000000000")
  72. Print "   mr$ rtnd:"; r$
  73. '1000000000000000000000000000000000000000
  74. '-999999999999999999999999999999999999999
  75. Print "    compare:-999999999999999999999999999999999999999"
  76.  
  77. ' check jack problems with FB translation  2021-06-03  errors must be in FB trans from QB64
  78. Print Mid$(mr$(" .1", "/", "3"), 1, 100) ' too long?
  79. Print Mid$(mr$("1.1", "/", "9"), 1, 100)
  80. Print Mid$(mr$("1.38", "/", "1.2"), 1, 100)
  81.  
  82. ' another error reported by jack 2021-06-06 fixed (same problem as subtr$)
  83. Print mr$("1.000000000000000000000001000000000000000000000001", "*", ".000000000000000000000000000000000000000000000001")
  84. Print ".000000000000000000000000000000000000000000000001"
  85. Print "                                                1000000000000000000000001000000000000000000000001"
  86. Print ruler$
  87. Print "checking inverse of 50 = .02 "; nInverse$("50", 20) 'OK  .020000... length 20
  88. Print "zzz... see inverse of STx number now takes 2.2 secs with fixed subtr$() sub,"
  89. Print "can find 115 Fibonacci terms in it."
  90. Dim inverseSTx$, start, done
  91. start = Timer(.001)
  92. inverseSTx$ = nInverse$("999999999999999999999998999999999999999999999999", 2785) ' now 2.2 secs with new subtr from 19 secs
  93. 'inverseSTx$ = nInverse2$("999999999999999999999998999999999999999999999999", 817) ' 13 sec damn added 7 secs! now 19.xx
  94. ' 816 in 4.22 secs only 64 terms   817 sigDigits matching in 12.93 secs gets all 115 Fibonacci Terms
  95. done = Timer(.001) - start
  96. Print Mid$(inverseSTx$, 1, 3000)
  97. Print "Inverse time:"; done; "   zzz... press any to search for Fibonacci Terms"
  98. Dim As Long startSearch, termN, find
  99. Dim f1$, f2$, searchFor$
  100. f1$ = "1"
  101. f2$ = "1"
  102. startSearch = 1
  103. termN = 2
  104.     searchFor$ = mr$(f1$, "+", f2$)
  105.     find = InStr(startSearch, inverseSTx$, searchFor$)
  106.     If find Then
  107.         termN = termN + 1
  108.         Print "Term Number"; termN; " = "; searchFor$; " found at"; find
  109.         f1$ = f2$
  110.         f2$ = searchFor$
  111.         startSearch = find + Len(searchFor$)
  112.     Else
  113.         Print searchFor$; " not found."
  114.         Exit Do
  115.     End If
  116. ' test factorial speed
  117. Dim fact$, i As _Unsigned _Integer64, refFact$, cont$
  118. Input "Press y for yes, let's do 10000 factorial test, takes quite a bit of time (3.25 mins) "; fact$
  119. If fact$ = "y" Then
  120.     start = Timer(.001)
  121.     fact$ = "1"
  122.     For i = 2 To 10000
  123.         fact$ = TrimLead0$(mult$(fact$, _Trim$(Str$(i))))
  124.         If i Mod 100 = 0 Then Print i; "factorial length ="; Len(fact$)
  125.     Next
  126.     done = Timer(.001) - start
  127.     Print i, Len(fact$), done
  128.     ' save it
  129.     Open "calc 10000!.txt" For Output As #1
  130.     Print #1, fact$
  131.     Close #1
  132.     Beep
  133.     Print Len(fact$), done, "   zzz... press any to compare to reference 10000!."
  134.     Sleep
  135.     _KeyClear
  136.     If _FileExists("10000!.txt") Then
  137.         Open "10000!.txt" For Input As #1
  138.         Input #1, refFact$
  139.         Close #1
  140.         Print "Comparing fact$ to reference fact$:"
  141.         For i = 1 To Len(fact$)
  142.             If Mid$(fact$, i, 1) <> Mid$(refFact$, i, 1) Then
  143.                 Print i, Mid$(fact$, i, 1), Mid$(refFact$, i, 1)
  144.                 Beep
  145.                 Input "Mismatch! Continue? y for yes "; cont$
  146.                 If cont$ <> "y" Then Exit For
  147.             End If
  148.         Next
  149.         Print "Compare finished, mismatchs already noted if any."
  150.     Else
  151.         Print "Can't find 10000!.txt reference file."
  152.     End If
  153.     _KeyClear
  154.     Print "zzz... press any to start sqr estimating"
  155.     Sleep
  156.     _KeyClear
  157.  
  158. Dim n$, result$
  159.     'remember everything is strings
  160.     Input "Enter a number to find it's square root, just enter to quit "; n$
  161.     If n$ = "" Then End
  162.     result$ = sqrRoot$(n$)
  163.     Print result$
  164.     Print "Length ="; Len(result$)
  165.     Print
  166.  
  167. ' =========  String Math Procedure start here (aprox 412 LOC for copy/paste into your app) ======
  168.  
  169. Function sqrRoot$ (nmbr$)
  170.     Dim n$, guess$, lastGuess$, other$, sum$, imaginary$, loopcnt
  171.     If Left$(nmbr$, 1) = "-" Then 'handle neg numbers
  172.         imaginary$ = "*i": n$ = Mid$(nmbr$, 2)
  173.     Else
  174.         imaginary$ = "": n$ = nmbr$
  175.     End If
  176.     guess$ = mr$(n$, "/", "2")
  177.     other$ = n$
  178.     Do
  179.         loopcnt = loopcnt + 1
  180.         If (Mid$(guess$, 1, 105) = Mid$(lastGuess$, 1, 105)) Then
  181.             ' go past 100 matching digits for 100 digit precision
  182.             sqrRoot$ = Mid$(other$, 1, 101) + imaginary$
  183.             ' try other factor for guess$  sometimes it nails answer without all digits
  184.             Exit Function
  185.         Else
  186.             lastGuess$ = guess$
  187.             sum$ = mr$(guess$, "+", other$)
  188.             guess$ = mr$(sum$, "/", "2")
  189.             other$ = mr$(n$, "/", guess$)
  190.         End If
  191.     Loop
  192.  
  193. Function add$ (a$, b$) 'add 2 positive integers assume a and b are just numbers no - signs
  194.     'set a and b numbers to same length and multiple of 18 so can take 18 digits at a time
  195.     Dim As Long la, lb, m, g
  196.     Dim fa$, fb$, t$, new$, result$
  197.     la = Len(a$): lb = Len(b$)
  198.     If la > lb Then m = Int(la / 18) + 1 Else m = Int(lb / 18) + 1
  199.     fa$ = Right$(String$(m * 18, "0") + a$, m * 18)
  200.     fb$ = Right$(String$(m * 18, "0") + b$, m * 18)
  201.  
  202.     'now taking 18 digits at a time Thanks Steve McNeill
  203.     For g = 1 To m
  204.         sa = Val(Mid$(fa$, (m - g) * 18 + 1, 18))
  205.         sb = Val(Mid$(fb$, (m - g) * 18 + 1, 18))
  206.         t$ = Right$(String$(36, "0") + _Trim$(Str$(sa + sb + co)), 36)
  207.         co = Val(Mid$(t$, 1, 18))
  208.         new$ = Mid$(t$, 19)
  209.         result$ = new$ + result$
  210.     Next
  211.     If co Then result$ = Str$(co) + result$
  212.     add$ = result$
  213.  
  214. ' This is used in nInverse$ not by Mr$ because there it saves time!
  215. Function subtr1$ (a$, b$)
  216.     Dim As Long la, lb, lResult, i, ca, cb, w
  217.     Dim result$, fa$, fb$
  218.  
  219.     la = Len(a$): lb = Len(b$)
  220.     If la > lb Then lResult = la Else lResult = lb
  221.     result$ = Space$(lResult)
  222.     fa$ = result$: fb$ = result$
  223.     Mid$(fa$, lResult - la + 1) = a$
  224.     Mid$(fb$, lResult - lb + 1) = b$
  225.     For i = lResult To 1 Step -1
  226.         ca = Val(Mid$(fa$, i, 1))
  227.         cb = Val(Mid$(fb$, i, 1))
  228.         If cb > ca Then ' borrow 10
  229.             Mid$(result$, i, 1) = Right$(Str$(10 + ca - cb), 1)
  230.             w = i - 1
  231.             While w > 0 And Mid$(fa$, w, 1) = "0"
  232.                 Mid$(fa$, w, 1) = "9"
  233.                 w = w - 1
  234.             Wend
  235.             Mid$(fa$, w, 1) = Right$(Str$(Val(Mid$(fa$, w, 1)) - 1), 1)
  236.         Else
  237.             Mid$(result$, i, 1) = Right$(Str$(ca - cb), 1)
  238.         End If
  239.     Next
  240.     subtr1$ = result$
  241.  
  242. ' 2021-06-08 fix up with new mr call that decides the sign and puts the greater number first
  243. Function subtr$ (sum$, minus$) ' assume both numbers are positive all digits
  244.     Dim As Long m, g, p
  245.     Dim ts$, tm$, sign$, LG$, sm$, t$, result$
  246.  
  247.     ts$ = _Trim$(sum$): tm$ = _Trim$(minus$) ' fixed subtr$ 2021-06-05
  248.     If trim0(ts$) = trim0$(tm$) Then subtr$ = "0": Exit Function 'proceed knowing not equal
  249.     tenE18 = 1000000000000000000 'yes!!! no dang E's
  250.     sign$ = ""
  251.     m = Int(Len(ts$) / 18) + 1
  252.     LG$ = Right$(String$(m * 18, "0") + ts$, m * 18)
  253.     sm$ = Right$(String$(m * 18, "0") + tm$, m * 18)
  254.  
  255.     'now taking 18 digits at a time From Steve I learned we can do more than 1 digit at a time
  256.     For g = 1 To m
  257.         VB = Val(Mid$(LG$, m * 18 - g * 18 + 1, 18))
  258.         vs = Val(Mid$(sm$, m * 18 - g * 18 + 1, 18))
  259.         If vs > VB Then
  260.             t$ = Right$(String$(18, "0") + _Trim$(Str$(tenE18 - vs + VB)), 18)
  261.             p = (m - g) * 18
  262.             While p > 0 And Mid$(LG$, p, 1) = "0"
  263.                 Mid$(LG$, p, 1) = "9"
  264.                 p = p - 1
  265.             Wend
  266.             If p > 0 Then Mid$(LG$, p, 1) = _Trim$(Str$(Val(Mid$(LG$, p, 1)) - 1))
  267.         Else
  268.             t$ = Right$(String$(18, "0") + _Trim$(Str$(VB - vs)), 18)
  269.         End If
  270.         result$ = t$ + result$
  271.     Next
  272.     subtr$ = result$
  273.  
  274. Function TrimLead0$ (s$) 'for treating strings as number (pos integers)
  275.     Dim copys$
  276.     Dim As Long i, find
  277.     copys$ = _Trim$(s$) 'might as well remove spaces too
  278.     i = 1: find = 0
  279.     While i < Len(copys$) And Mid$(copys$, i, 1) = "0"
  280.         i = i + 1: find = 1
  281.     Wend
  282.     If find = 1 Then copys$ = Mid$(copys$, i)
  283.     If copys$ = "" Then TrimLead0$ = "0" Else TrimLead0$ = copys$
  284.  
  285. ' catchy? mr$ for math regulator  cop$ = " + - * / " 1 of 4 basic arithmetics
  286. ' Fixed so that add and subtract have signs calc'd in Mr and correct call to add or subtract made
  287. ' with bigger minus smaller in subtr$() call
  288. Function mr$ (a$, cop$, b$)
  289.     Dim op$, ca$, cb$, aSgn$, bSgn$, postOp$, sgn$
  290.     Dim As Long adp, bdp, dp, lpop, aLTb
  291.  
  292.     op$ = _Trim$(cop$) 'save fixing each time
  293.     ca$ = _Trim$(a$): cb$ = _Trim$(b$) 'make copies in case we change
  294.     'strip signs and decimals
  295.     If Left$(ca$, 1) = "-" Then
  296.         aSgn$ = "-": ca$ = Mid$(ca$, 2)
  297.     Else
  298.         aSgn$ = ""
  299.     End If
  300.     dp = InStr(ca$, ".")
  301.     If dp > 0 Then
  302.         adp = Len(ca$) - dp
  303.         ca$ = Mid$(ca$, 1, dp - 1) + Mid$(ca$, dp + 1)
  304.     Else
  305.         adp = 0
  306.     End If
  307.     If Left$(cb$, 1) = "-" Then
  308.         bSgn$ = "-": cb$ = Mid$(cb$, 2)
  309.     Else
  310.         bSgn$ = ""
  311.     End If
  312.     dp = InStr(cb$, ".")
  313.     If dp > 0 Then
  314.         bdp = Len(cb$) - dp
  315.         cb$ = Mid$(cb$, 1, dp - 1) + Mid$(cb$, dp + 1)
  316.     Else
  317.         bdp = 0
  318.     End If
  319.     If op$ = "+" Or op$ = "-" Or op$ = "/" Then 'add or subtr  even up strings on right of decimal
  320.         'even up the right sides of decimals if any
  321.         If adp > bdp Then dp = adp Else dp = bdp
  322.         If adp < dp Then ca$ = ca$ + String$(dp - adp, "0")
  323.         If bdp < dp Then cb$ = cb$ + String$(dp - bdp, "0")
  324.     ElseIf op$ = "*" Then
  325.         dp = adp + bdp
  326.     End If
  327.     If op$ = "*" Or op$ = "/" Then
  328.         If aSgn$ = bSgn$ Then sgn$ = "" Else sgn$ = "-"
  329.     End If
  330.  
  331.     'now according to signs and op$ call add$ or subtr$
  332.     If op$ = "-" Then ' make it adding according to signs because that is done for + next!
  333.         If bSgn$ = "-" Then bSgn$ = "" Else bSgn$ = "-" ' flip bSgn$ with op$
  334.         op$ = "+" ' turn this over to + op already done! below
  335.     End If
  336.     If op$ = "+" Then
  337.         If aSgn$ = bSgn$ Then 'really add
  338.             postOp$ = add$(ca$, cb$)
  339.             sgn$ = aSgn$
  340.         ElseIf aSgn$ <> bSgn$ Then 'have a case of subtraction
  341.             'but which is first and which is 2nd and should final sign be pos or neg
  342.             If TrimLead0$(ca$) = TrimLead0(cb$) Then 'remove case a = b
  343.                 mr$ = "0": Exit Function
  344.             Else
  345.                 aLTb = LTE(ca$, cb$)
  346.                 If aSgn$ = "-" Then
  347.                     If aLTb Then ' b - a = pos
  348.                         postOp$ = subtr$(cb$, ca$)
  349.                         sgn$ = ""
  350.                     Else '  a > b so a - sgn wins  - (a - b)
  351.                         postOp$ = subtr$(ca$, cb$)
  352.                         sgn$ = "-"
  353.                     End If
  354.                 Else ' b has the - sgn
  355.                     If aLTb Then ' result is -
  356.                         postOp$ = subtr$(cb$, ca$)
  357.                         sgn$ = "-"
  358.                     Else ' result is pos
  359.                         postOp$ = subtr$(ca$, cb$)
  360.                         sgn$ = ""
  361.                     End If
  362.                 End If
  363.             End If
  364.         End If
  365.     ElseIf op$ = "*" Then
  366.         postOp$ = mult$(ca$, cb$)
  367.     ElseIf op$ = "/" Then
  368.         postOp$ = divide$(ca$, cb$)
  369.     End If ' which op
  370.     If op$ <> "/" Then 'put dp back
  371.         lpop = Len(postOp$) ' put decimal back if there is non zero stuff following it
  372.         If Len(Mid$(postOp$, lpop - dp + 1)) Then ' fix 1 extra dot appearing in 10000! ?!
  373.             If TrimLead0$(Mid$(postOp$, lpop - dp + 1)) <> "0" Then '  .0   or .00 or .000  ??
  374.                 postOp$ = Mid$(postOp$, 1, lpop - dp) + "." + Mid$(postOp$, lpop - dp + 1)
  375.             End If
  376.         End If
  377.     End If
  378.     mr$ = trim0$(postOp$) 'trim lead 0's then tack on sign
  379.     If mr$ <> "0" Then mr$ = sgn$ + mr$
  380.  
  381. Function divide$ (n$, d$) ' goal here is 100 digits precision not 100 digits past decimal
  382.     Dim di$, ndi$
  383.     Dim As Long nD
  384.     If n$ = "0" Then divide$ = "0": Exit Function
  385.     If d$ = "0" Then divide$ = "div 0": Exit Function
  386.     If d$ = "1" Then divide$ = n$: Exit Function
  387.  
  388.     ' aha! found a bug when d$ gets really huge 100 is no where near enough!!!!
  389.     ' 2021-06-03 fix by adding 100 to len(d$), plus have to go a little past 100 like 200
  390.     di$ = Mid$(nInverse$(d$, Len(d$) + 200), 2) 'chop off decimal point after
  391.     nD = Len(di$)
  392.     ndi$ = mult$(n$, di$)
  393.     ndi$ = Mid$(ndi$, 1, Len(ndi$) - nD) + "." + Right$(String$(nD, "0") + Right$(ndi$, nD), nD)
  394.     divide$ = ndi$
  395.  
  396. ' This uses Subtr1$ is Positive Integer only!
  397. ' DP = Decimal places = says when to quit if don't find perfect divisor before
  398. Function nInverse$ (n$, DP As Long) 'assume decimal at very start of the string of digits returned
  399.     Dim m$(1 To 9), si$, r$, outstr$, d$
  400.     Dim i As Long
  401.     For i = 1 To 9
  402.         si$ = _Trim$(Str$(i))
  403.         m$(i) = mult$(si$, n$)
  404.     Next
  405.     outstr$ = ""
  406.     If n$ = "0" Then nInverse$ = "Div 0": Exit Function
  407.     If n$ = "1" Then nInverse$ = "1": Exit Function
  408.     outstr$ = "." 'everything else n > 1 is decimal 8/17
  409.     r$ = "10"
  410.     Do
  411.         While LT(r$, n$) ' 2021-06-08 this should be strictly Less Than
  412.             outstr$ = outstr$ + "0" '            add 0 to the  output string
  413.             If Len(outstr$) = DP + 1 Then nInverse$ = outstr$: Exit Function 'DP length?
  414.             r$ = r$ + "0"
  415.         Wend
  416.         For i = 9 To 1 Step -1
  417.             If LTE(m$(i), r$) Then d$ = _Trim$(Str$(i)): Exit For
  418.         Next
  419.         outstr$ = outstr$ + d$
  420.         If Len(outstr$) = DP + 1 Then nInverse$ = outstr$: Exit Function
  421.         r$ = subtr1$(r$, mult$(d$, n$)) 'r = r -d*n    ' 2021-06-08 subtr1 works faster
  422.         If TrimLead0$(r$) = "0" Then nInverse$ = outstr$: Exit Function ' add trimlead0$ 6/08
  423.         r$ = r$ + "0" 'add another place
  424.     Loop
  425.  
  426. Function mult$ (a$, b$) 'assume both positive integers prechecked as all digits strings
  427.     Dim As Long la, lb, m, g, dp
  428.     Dim As _Unsigned _Integer64 v18, sd, co
  429.     Dim f18$, f1$, t$, build$, accum$
  430.  
  431.     If a$ = "0" Then mult$ = "0": Exit Function
  432.     If b$ = "0" Then mult$ = "0": Exit Function
  433.     If a$ = "1" Then mult$ = b$: Exit Function
  434.     If b$ = "1" Then mult$ = a$: Exit Function
  435.     'find the longer number and make it a mult of 18 to take 18 digits at a time from it
  436.     la = Len(a$): lb = Len(b$)
  437.     If la > lb Then
  438.         m = Int(la / 18) + 1
  439.         f18$ = Right$(String$(m * 18, "0") + a$, m * 18)
  440.         f1$ = b$
  441.     Else
  442.         m = Int(lb / 18) + 1
  443.         f18$ = Right$(String$(m * 18, "0") + b$, m * 18)
  444.         f1$ = a$
  445.     End If
  446.     For dp = Len(f1$) To 1 Step -1 'dp = digit position of the f1$
  447.         build$ = "" 'line builder
  448.         co = 0
  449.         'now taking 18 digits at a time Thanks Steve McNeill
  450.         For g = 1 To m
  451.             v18 = Val(Mid$(f18$, (m - g) * 18 + 1, 18))
  452.             sd = Val(Mid$(f1$, dp, 1))
  453.             t$ = Right$(String$(19, "0") + _Trim$(Str$(v18 * sd + co)), 19)
  454.             co = Val(Mid$(t$, 1, 1))
  455.             build$ = Mid$(t$, 2) + build$
  456.         Next g
  457.         If co Then build$ = _Trim$(Str$(co)) + build$
  458.         If dp = Len(f1$) Then
  459.             accum$ = build$
  460.         Else
  461.             accum$ = add$(accum$, build$ + String$(Len(f1$) - dp, "0"))
  462.         End If
  463.     Next dp
  464.     mult$ = accum$
  465.  
  466. 'this function needs TrimLead0$(s$)
  467. Function LTE (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  468.     Dim ca$, cb$
  469.     Dim As Long la, lb, i
  470.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  471.     la = Len(ca$): lb = Len(cb$)
  472.     If ca$ = cb$ Then
  473.         LTE = -1
  474.     ElseIf la < lb Then ' a is smaller
  475.         LTE = -1
  476.     ElseIf la > lb Then ' a is bigger
  477.         LTE = 0
  478.     ElseIf la = lb Then ' equal lengths
  479.         For i = 1 To Len(ca$)
  480.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  481.                 LTE = 0: Exit Function
  482.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  483.                 LTE = -1: Exit Function
  484.             End If
  485.         Next
  486.     End If
  487.  
  488. 'need this for ninverse faster than subtr$ for sign
  489. Function LT (a$, b$) ' a$ Less Than or Equal b$  comparison of 2 strings
  490.     Dim ca$, cb$
  491.     Dim As Long la, lb, i
  492.     ca$ = TrimLead0$(a$): cb$ = TrimLead0(b$)
  493.     la = Len(ca$): lb = Len(cb$)
  494.     If la < lb Then ' a is smaller
  495.         LT = -1
  496.     ElseIf la > lb Then ' a is bigger
  497.         LT = 0
  498.     ElseIf la = lb Then ' equal lengths
  499.         For i = 1 To Len(ca$)
  500.             If Val(Mid$(ca$, i, 1)) > Val(Mid$(cb$, i, 1)) Then
  501.                 LT = 0: Exit Function
  502.             ElseIf Val(Mid$(ca$, i, 1)) < Val(Mid$(cb$, i, 1)) Then
  503.                 LT = -1: Exit Function
  504.             End If
  505.         Next
  506.     End If
  507.  
  508. Function TrimTail0$ (s$)
  509.     Dim copys$
  510.     Dim As Long dp, i, find
  511.     copys$ = _Trim$(s$) 'might as well remove spaces too
  512.     TrimTail0$ = copys$
  513.     dp = InStr(copys$, ".")
  514.     If dp > 0 Then
  515.         i = Len(copys$): find = 0
  516.         While i > dp And Mid$(copys$, i, 1) = "0"
  517.             i = i - 1: find = 1
  518.         Wend
  519.         If find = 1 Then
  520.             If i = dp Then
  521.                 TrimTail0$ = Mid$(copys$, 1, dp - 1)
  522.             Else
  523.                 TrimTail0$ = Mid$(copys$, 1, i)
  524.             End If
  525.         End If
  526.     End If
  527.  
  528. Function trim0$ (s$)
  529.     Dim cs$, si$
  530.     cs$ = s$
  531.     si$ = Left$(cs$, 1)
  532.     If si$ = "-" Then cs$ = Mid$(cs$, 2)
  533.     cs$ = TrimLead0$(cs$)
  534.     cs$ = TrimTail0$(cs$)
  535.     If Right$(cs$, 1) = "." Then cs$ = Mid$(cs$, 1, Len(cs$) - 1)
  536.     If si$ = "-" Then trim0$ = si$ + cs$ Else trim0$ = cs$
  537.  
  538. ' for displaying truncated numbers say to 60 digits
  539. Function showDP$ (num$, nDP As Long)
  540.     Dim cNum$
  541.     Dim As Long dp, d, i
  542.     cNum$ = num$ 'since num$ could get changed
  543.     showDP$ = num$
  544.     dp = InStr(num$, ".")
  545.     If dp > 0 Then
  546.         If Len(Mid$(cNum$, dp + 1)) > nDP Then
  547.             d = Val(Mid$(cNum$, dp + nDP + 1, 1))
  548.             If d > 4 Then
  549.                 cNum$ = "0" + cNum$ ' tack on another 0 just in case 9's all the way to left
  550.                 dp = dp + 1
  551.                 i = dp + nDP
  552.                 While Mid$(cNum$, i, 1) = "9" Or Mid$(cNum$, i, 1) = "."
  553.                     If Mid$(cNum$, i, 1) = "9" Then
  554.                         Mid$(cNum$, i, 1) = "0"
  555.                     End If
  556.                     i = i - 1
  557.                 Wend
  558.                 Mid$(cNum$, i, 1) = _Trim$(Str$(Val(Mid$(cNum$, i, 1)) + 1)) 'last non 9 digit
  559.                 cNum$ = Mid$(cNum$, 1, dp + nDP) 'chop it
  560.                 showDP$ = trim0$(cNum$)
  561.             Else
  562.                 showDP$ = Mid$(cNum$, 1, dp + nDP)
  563.             End If
  564.         End If
  565.     End If
  566.  

The test code in main code area calculates 10000! and compares it to a reference file, if found.

Here is a copy if you'd like, the 3rd line in file is a link to where I got the number for reference in
10000!.txt:

* 10000!.txt (Filesize: 34.88 KB, Downloads: 116)
« Last Edit: June 14, 2021, 04:07:11 pm by bplus »

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: String Math
« Reply #59 on: June 14, 2021, 06:50:23 pm »
congrats bplus, 98 seconds for the factorial on my PC