Author Topic: Yuck String Math or What's wrong with FOO?  (Read 12468 times)

0 Members and 1 Guest are viewing this topic.

Offline MWheatley

  • Newbie
  • Posts: 64
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #30 on: March 20, 2019, 08:55:12 am »
As a rule, I don’t like string math simply for the speed (sloooow), and I don’t have any real need for it usually.  LONGs get the majority of my work done, with _FLOATS used only when necessary (and even less often, SINGLE or DOUBLE), and string math is just a novelty needed by others much more than by me.  ;)

Out of interest, what sort of things do you use LONGs for?

Malcolm

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #31 on: March 20, 2019, 10:31:01 am »
As a rule, I don’t like string math simply for the speed (sloooow), and I don’t have any real need for it usually.  LONGs get the majority of my work done, with _FLOATS used only when necessary (and even less often, SINGLE or DOUBLE), and string math is just a novelty needed by others much more than by me.  ;)

Out of interest, what sort of things do you use LONGs for?

Malcolm

Signed INTEGERs only have a range of -32,7678 to 32,767 whereas LONG has a range of about 10 digits.

If you just squared the width of a screen you are likely to exceed INTEGER range.
« Last Edit: March 20, 2019, 10:33:01 am by bplus »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #32 on: March 27, 2019, 11:51:23 pm »
I use LONG in my String Math routine, as LEN() is limited by the LONG variable type limits. Oh, speaking of which, I posted the latest version here: https://www.tapatalk.com/groups/qbasic/viewtopic.php?f=648955&t=39442&p=212636#p212636

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #33 on: April 06, 2019, 02:48:03 pm »
Well, I'm a little bit excited about the first unit testing results in my string math routine. I've ran it a 10 times with all good results. It will pause when a potential problem arises, but, so far, all of those seem to be generated from the higher degree of accuracy with more digits used in many of the string math operations. The pause at least allows me to view and compare, and so far, so good. I'm only using 17+ digits for now. If the first 12 of the 16 digit QB numeric result matches the string math result, it counts it as accepted and moves on. If not, it pauses.

Here is a screen shot where it paused on a 17 digit limit, rounding enabled. I checked in on a calculator to see if it missed a rounding opportunity, and as you can see, it actually didn't!

  [ You are not allowed to view this attachment ]  

So far, I've only tested limits between 17 to 140 digits, rounding enabled, show rounding, and no to everything else. Here's the code I'm testing. Press any key, if it pauses, to keep testing. If anyone does test it and finds a fail, please take a screen shot and post it. Also, let me know the parameters you tested it with, especially the digit limit.

Code: QB64: [Select]
  1. WIDTH 156, 43
  2. INPUT "Limit Display: "; limit&&
  3. LINE INPUT "Use Rounding? Y/N: "; ans$
  4. IF UCASE$(ans$) = "Y" THEN
  5.     round_total% = -1
  6.     LINE INPUT "Show if Rounded? Y/N: "; ans$
  7.     IF UCASE$(ans$) = "Y" THEN show_rounding% = -1 ELSE show_rounding% = 0
  8.     round_total% = 0
  9. LINE INPUT "Display in Scientific Notation? Y/N: "; ans$
  10. IF UCASE$(ans$) = "Y" THEN
  11.     snconvert% = -1
  12.     snconvert% = 0
  13.     LINE INPUT "Display in Dollars and Cents? Y/N: "; ans$
  14.     IF UCASE$(ans$) = "Y" THEN currency_display% = -1 ELSE currency_display% = 0
  15.     LINE INPUT "Display Results with Commas? Y/N: "; ans$
  16. IF UCASE$(ans$) = "Y" THEN comma_display% = -1 ELSE comma_display% = 0
  17.     DO
  18.         '''LINE INPUT "Number: "; stringmathb$
  19.         ' UNIT TESTING============================
  20.         stringmathb$ = LTRIM$(STR$(RND * 1000000))
  21.         '=========================================
  22.         IF UCASE$(stringmathb$) = "C" THEN RUN
  23.         origb$ = stringmathb$
  24.         CALL stringmath(stringmatha$, operator$, stringmathb$, runningtotal$, snconvert%, round_total%, show_rounding%, comma_display%, currency_display%, limit&&)
  25.         IF stringmathb$ <> "invalid number" AND stringmathb$ <> "overflow" THEN
  26.             EXIT DO
  27.         ELSE
  28.             ' UNIT TESTING============================
  29.             IF stringmathb$ = "overflow" THEN
  30.                 operator% = RND * 3
  31.                 SELECT CASE operator%
  32.                     CASE 0: operator$ = "+"
  33.                     CASE 1: operator$ = "-"
  34.                     CASE 2: operator$ = "*"
  35.                     CASE 3: operator$ = "/"
  36.                 END SELECT
  37.                 PRINT stringmathb$
  38.                 PRINT "Change Operator: "; operator$: orig_operator$ = operator$
  39.                 ' UNIT TESTING============================
  40.                 ''' PRINT stringmathb$
  41.             ELSE
  42.                 PRINT stringmathb$
  43.                 END
  44.             END IF
  45.         END IF
  46.     LOOP
  47.     IF operator$ <> "" THEN
  48.         DO UNTIL INSTR(origa$, ",") = 0
  49.             origa$ = MID$(origa$, 1, INSTR(origa$, ",") - 1) + MID$(origa$, INSTR(origa$, ",") + 1)
  50.         LOOP
  51.         DO UNTIL INSTR(origb$, ",") = 0
  52.             origb$ = MID$(origb$, 1, INSTR(origb$, ",") - 1) + MID$(origb$, INSTR(origb$, ",") + 1)
  53.         LOOP
  54.         IF INSTR(origb$, "$") THEN origb$ = MID$(origb$, 1, INSTR(origb$, "$") - 1) + MID$(origb$, INSTR(origb$, "$") + 1)
  55.         SELECT CASE orig_operator$
  56.             CASE "+"
  57.                 runningtotal# = VAL(origa$) + VAL(origb$)
  58.             CASE "-"
  59.                 runningtotal# = VAL(origa$) - VAL(origb$)
  60.             CASE "*"
  61.                 runningtotal# = VAL(origa$) * VAL(origb$)
  62.             CASE "/"
  63.                 runningtotal# = VAL(origa$) / VAL(origb$)
  64.             CASE "C", "c"
  65.                 RUN
  66.         END SELECT
  67.         origa$ = LTRIM$(STR$(runningtotal#))
  68.         COLOR 8, 0: PRINT "Numeric Total: "; origa$: COLOR 7, 0
  69.         PRINT "String Total:  "; runningtotal$
  70.         ' UNIT TESTING============================
  71.         q1$ = LTRIM$(STR$(runningtotal#))
  72.         q2$ = runningtotal$
  73.         IF INSTR(q1$, ".") THEN q1$ = MID$(q1$, 1, INSTR(q1$, ".") - 1) + MID$(q1$, INSTR(q1$, ".") + 1)
  74.         IF INSTR(q2$, ".") THEN q2$ = MID$(q2$, 1, INSTR(q2$, ".") - 1) + MID$(q2$, INSTR(q2$, ".") + 1)
  75.         IF RIGHT$(UCASE$(q2$), 1) = "R" THEN q2$ = MID$(q2$, 1, LEN(q2$) - 1)
  76.         FOR i% = 1 TO 12
  77.             IF MID$(q1$, i%, 1) <> MID$(q2$, i%, 1) THEN
  78.                  DO
  79.                      _LIMIT 10
  80.                  LOOP UNTIL INKEY$ <> ""
  81.             EXIT FOR
  82.             END IF
  83.         NEXT
  84.         '===========================================
  85.     ELSE
  86.         origa$ = runningtotal$: IF INSTR(origa$, "$") THEN origa$ = MID$(origa$, 1, INSTR(origa$, "$") - 1) + MID$(origa$, INSTR(origa$, "$") + 1)
  87.     END IF
  88.     COLOR 2, 0: PRINT "Operator: +-/*: ";: COLOR 7, 0
  89.     DO
  90.         operator% = RND * 3
  91.         SELECT CASE operator%
  92.             CASE 0: operator$ = "+"
  93.             CASE 1: operator$ = "-"
  94.             CASE 2: operator$ = "*"
  95.             CASE 3: operator$ = "/"
  96.         END SELECT
  97.         EXIT DO
  98.  
  99.         operator$ = INKEY$
  100.         IF LEN(operator$) THEN
  101.             IF operator$ = CHR$(27) THEN SYSTEM
  102.             IF INSTR("-+/*=8cC", operator$) THEN EXIT DO
  103.         END IF
  104.     LOOP
  105.     IF UCASE$(operator$) = "C" THEN RUN
  106.     IF operator$ = "=" THEN operator$ = "+"
  107.     IF operator$ = "8" THEN operator$ = "*"
  108.     orig_operator$ = operator$
  109.     PRINT operator$
  110.  
  111. SUB stringmath (stringmatha$, operator$, stringmathb$, runningtotal$, snconvert%, round_total%, show_rounding%, comma_display%, currency_display%, limit&&)
  112. stringmathround$ = ""
  113. IF limit&& > 2147483640 THEN limit&& = 2147483640
  114. IF limit&& = 0 THEN limit&& = 70 ' Default.
  115.  
  116. IF RIGHT$(UCASE$(runningtotal$), 1) = "R" THEN runningtotal$ = MID$(runningtotal$, 1, LEN(runningtotal$) - 1) 'Strip off rounding designation.
  117. ' Check running total. If S.N. convert to numeric for operations.
  118. IF INSTR(runningtotal$, ",") <> 0 OR INSTR(runningtotal$, "e") <> 0 THEN
  119.     holdstringmathb$ = stringmathb$
  120.     stringmathb$ = runningtotal$
  121.     IF INSTR(runningtotal$, ",") <> 0 THEN GOSUB comma_removal ELSE GOSUB scientific_to_numeric
  122.     runningtotal$ = stringmathb$: stringmathb$ = holdstringmathb$: holdstringmathb$ = ""
  123. ' Check input number. If S.N. convert to numeric for operations.
  124. IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN
  125.     GOSUB validate_string_number
  126.     IF stringmathb$ = "invalid number" THEN EXIT SUB
  127.     GOSUB scientific_to_numeric
  128.  
  129. IF runningtotal$ = "" THEN
  130.     GOSUB validate_string_number
  131.     IF stringmathb$ = "invalid number" THEN EXIT SUB
  132.  
  133.     IF LEFT$(stringmathb$, 1) = "-" THEN
  134.         stringmathb$ = MID$(stringmathb$, 2)
  135.         n2sign$ = "-"
  136.     ELSE
  137.         n2sign$ = ""
  138.     END IF
  139.     GOSUB limit_round_convert
  140.     IF stringmathb$ = "overflow" THEN
  141.         n2sign$ = "": PRINT "Validated: "; stringmathb$: EXIT SUB
  142.     END IF
  143.     runningtotal$ = n2sign$ + stringmathb$: n2sign$ = ""
  144.     IF stringmathround$ <> "" THEN runningtotal$ = runningtotal$ + stringmathround$
  145.     PRINT "Validated: "; runningtotal$
  146.     IF INSTR(LCASE$(stringmathb$), "e") <> 0 THEN BEEP: GOSUB scientific_to_numeric
  147.     GOSUB validate_string_number
  148.     PRINT "Validated: "; stringmathb$
  149.     IF stringmathb$ = "invalid number" THEN EXIT SUB
  150.     IF INSTR(UCASE$(stringmathb$), "e") <> 0 THEN GOSUB scientific_to_numeric
  151. IF runningtotal$ <> "" THEN stringmatha$ = runningtotal$
  152.  
  153. SELECT CASE operator$
  154.     CASE "+", "-"
  155.         string_add_subtract:
  156.         IF INSTR(stringmatha$, ".") <> 0 THEN ' Evaluate sum for decimal fraction.
  157.             sumplace& = LEN(stringmatha$) - INSTR(stringmatha$, ".")
  158.             stringmatha$ = MID$(stringmatha$, 1, INSTR(stringmatha$, ".") - 1) + MID$(stringmatha$, INSTR(stringmatha$, ".") + 1) ' Strip out decimal
  159.         END IF
  160.         IF INSTR(stringmathb$, ".") <> 0 THEN ' Evaluate number for decimal fraction.
  161.             numplace& = LEN(stringmathb$) - INSTR(stringmathb$, ".")
  162.             stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Strip out decimal
  163.         END IF
  164.         IF sumplace& > numplace& THEN addsubplace& = sumplace& ELSE addsubplace& = numplace&
  165.         IF sumplace& > addsubplace& THEN
  166.             stringmatha$ = stringmatha$ + STRING$(sumplace& - addsubplace&, "0")
  167.         ELSEIF addsubplace& > sumplace& THEN
  168.             stringmatha$ = stringmatha$ + STRING$(addsubplace& - sumplace&, "0")
  169.         END IF
  170.         IF numplace& > addsubplace& THEN
  171.             stringmathb$ = stringmathb$ + STRING$(numplace& - addsubplace&, "0")
  172.         ELSEIF addsubplace& > numplace& THEN
  173.             stringmathb$ = stringmathb$ + STRING$(addsubplace& - numplace&, "0")
  174.         END IF ' END Decimal evaluations.
  175.  
  176.         IF LEFT$(stringmatha$, 1) = "-" THEN sign_input$ = "-" ELSE sign_input$ = "+"
  177.         IF LEFT$(stringmathb$, 1) = "-" THEN sign_total$ = "-" ELSE sign_total$ = "+"
  178.  
  179.         addsubsign% = 0
  180.         SELECT CASE sign_input$ + operator$ + sign_total$
  181.             CASE "+++", "+--"
  182.                 operator$ = "+"
  183.                 IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  184.             CASE "++-", "+-+"
  185.                 operator$ = "-"
  186.                 IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  187.                 IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$: addsubsign% = -1
  188.             CASE "---", "-++"
  189.                 operator$ = "-"
  190.                 IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
  191.                 IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  192.                 IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$ ELSE addsubsign% = -1
  193.             CASE "--+", "-+-"
  194.                 operator$ = "+"
  195.                 IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
  196.                 IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  197.                 addsubsign% = -1
  198.         END SELECT
  199.  
  200.         IF LEN(stringmatha$) > LEN(stringmathb$) THEN
  201.             stringmathb$ = STRING$(LEN(stringmatha$) - LEN(stringmathb$), "0") + stringmathb$
  202.         ELSEIF LEN(stringmatha$) < LEN(stringmathb$) THEN
  203.             stringmatha$ = STRING$(LEN(stringmathb$) - LEN(stringmatha$), "0") + stringmatha$
  204.         END IF
  205.         addsubx1$ = ""
  206.  
  207.         SELECT CASE operator$
  208.             CASE "+", "="
  209.                 FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
  210.                     addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) + VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
  211.                     IF addsubx1% > 9 THEN addsubx1% = addsubx1% - 10: addsubcarry% = 1 ELSE addsubcarry% = 0
  212.                     addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
  213.                 NEXT
  214.                 IF addsubcarry% THEN addsubx1$ = "1" + addsubx1$: addsubcarry% = 0
  215.                 GOSUB replace_decimal
  216.             CASE "-"
  217.                 FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
  218.                     addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) - VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
  219.                     IF addsubx1% < 0 THEN addsubx1% = addsubx1% + 10: addsubcarry% = -1 ELSE addsubcarry% = 0
  220.                     addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
  221.                 NEXT
  222.                 IF addsubx1$ <> "" AND addsubx1$ <> STRING$(LEN(addsubx1$), "0") THEN GOSUB replace_decimal
  223.                 DO UNTIL LEFT$(addsubx1$, 1) <> "0" ' Remove leading zeros.
  224.                     addsubx1$ = MID$(addsubx1$, 2)
  225.                 LOOP
  226.                 IF addsubx1$ = "" THEN
  227.                     addsubx1$ = "0": addsubsign% = 0
  228.                 ELSE
  229.                     IF addsubcarry% THEN addsubx1$ = "-" + addsubx1$: addsubcarry% = 0
  230.                 END IF
  231.         END SELECT
  232.  
  233.         IF addsubsign% THEN
  234.             IF LEFT$(addsubx1$, 1) = "-" THEN addsubx1$ = MID$(addsubx1$, 2) ELSE addsubx1$ = "-" + addsubx1$
  235.         END IF
  236.         stringmatha$ = addsubx1$: addsubx1$ = ""
  237.         IF operationdivision% THEN RETURN
  238.         stringmathb$ = stringmatha$: stringmatha$ = ""
  239.         IF LEFT$(stringmathb$, 1) = "-" THEN
  240.             stringmathb$ = MID$(stringmathb$, 2)
  241.             n2sign$ = "-"
  242.         ELSE
  243.             n2sign$ = ""
  244.         END IF
  245.         GOSUB limit_round_convert
  246.         IF stringmathb$ = "overflow" THEN n2sign$ = "": EXIT SUB
  247.         GOSUB sm_converter
  248.         runningtotal$ = n2sign$ + stringmathb$: n2sign$ = ""
  249.  
  250.     CASE "*"
  251.         string_multiply:
  252.         fac1$ = stringmatha$: fac2$ = stringmathb$ ' Make numbers whole numbers and remove any - sign.
  253.         IF LEFT$(fac1$, 1) = "-" THEN fac1$ = MID$(fac1$, 2): m_sign% = -1
  254.         IF LEFT$(fac2$, 1) = "-" THEN fac2$ = MID$(fac2$, 2): IF m_sign% THEN m_sign% = 0 ELSE m_sign% = -1
  255.         IF INSTR(fac1$, ".") <> 0 THEN m_decimal_places& = LEN(fac1$) - INSTR(fac1$, "."): fac1$ = MID$(fac1$, 1, INSTR(fac1$, ".") - 1) + MID$(fac1$, INSTR(fac1$, ".") + 1)
  256.         IF INSTR(fac2$, ".") <> 0 THEN m_decimal_places& = m_decimal_places& + LEN(fac2$) - INSTR(fac2$, "."): fac2$ = MID$(fac2$, 1, INSTR(fac2$, ".") - 1) + MID$(fac2$, INSTR(fac2$, ".") + 1)
  257.         FOR m_i& = LEN(fac2$) TO 1 STEP -1 ' Multiply each charter top and bottom.
  258.             m_k& = m_l&
  259.             m_x2$ = MID$(fac2$, m_i&, 1)
  260.             FOR m_j& = LEN(fac1$) TO 1 STEP -1
  261.                 m_x1$ = MID$(fac1$, m_j&, 1)
  262.                 IF m_product$ <> "" THEN
  263.                     m_add$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0")
  264.                     m_t& = 0: m_xproduct$ = "": m_carry% = 0
  265.                     DO ' Add multiplied characters together.
  266.                         m_x3$ = MID$(m_add$, LEN(m_add$) - m_t&, 1)
  267.                         m_x4$ = MID$(m_product$, LEN(m_product$) - m_t&, 1)
  268.                         IF m_x3$ = "" AND m_x4$ = "" THEN
  269.                             IF m_carry% THEN m_xproduct$ = "1" + m_xproduct$
  270.                             EXIT DO
  271.                         END IF
  272.                         m_g% = VAL(m_x3$) + VAL(m_x4$) + m_carry%
  273.                         IF m_g% >= 10 THEN m_g% = m_g% - 10: m_carry% = 1 ELSE m_carry% = 0
  274.                         m_xproduct$ = LTRIM$(STR$(m_g%)) + m_xproduct$
  275.                         m_t& = m_t& + 1
  276.                     LOOP
  277.                     m_product$ = m_xproduct$: m_xproduct$ = ""
  278.                 ELSE
  279.                     m_product$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0") ' First loop makes variable here.
  280.                 END IF
  281.                 m_k& = m_k& + 1 ' Adds trailing zeros multiplication
  282.             NEXT
  283.             m_l& = m_l& + 1 ' Used to reset value for m_k& adding one trailing zer for each loop.
  284.         NEXT
  285.         fac1$ = "": fac2$ = "": m_l& = 0: m_k& = 0: m_t& = 0
  286.         IF m_decimal_places& > LEN(m_product$) THEN m_product$ = STRING$(m_decimal_places& - LEN(m_product$), "0") + m_product$ ' Add any leading zeros to a decimal. Ex: .02 * .01 is factored as 002. It needs one leading zero before adding the decimal point, .0002.
  287.         IF m_decimal_places& AND m_product$ <> "0" THEN ' Replace any decimal point.
  288.             m_product$ = MID$(m_product$, 1, LEN(m_product$) - m_decimal_places&) + "." + MID$(m_product$, LEN(m_product$) - m_decimal_places& + 1)
  289.         END IF
  290.         DO UNTIL LEFT$(m_product$, 1) <> "0" ' Remove leading zeros.
  291.             m_product$ = MID$(m_product$, 2)
  292.         LOOP
  293.         IF m_decimal_places& THEN
  294.             DO UNTIL RIGHT$(m_product$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
  295.                 m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1)
  296.             LOOP
  297.         END IF
  298.         IF m_product$ = "" THEN m_product$ = "0": m_sign% = 0
  299.         IF RIGHT$(m_product$, 1) = "." THEN m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1) ' Remove decimal from the end of an integer total.
  300.         IF operationdivision% THEN m_sign% = 0: RETURN
  301.         stringmathb$ = m_product$: m_product$ = "": GOSUB limit_round_convert
  302.         IF stringmathb$ = "overflow" THEN EXIT SUB
  303.         GOSUB sm_converter
  304.         runningtotal$ = stringmathb$: stringmathb$ = ""
  305.         IF m_sign% THEN runningtotal$ = "-" + runningtotal$: m_sign% = 0
  306.  
  307.     CASE "/"
  308.         operationdivision% = -1
  309.         divbuffer& = LEN(stringmathb$) - LEN(stringmatha$)
  310.         IF divbuffer& < 0 THEN divbuffer& = 0
  311.         d2dividend$ = stringmatha$
  312.         d1divisor$ = stringmathb$
  313.         IF LEFT$(d1divisor$, 1) = "0" AND LEN(d1divisor$) = 1 THEN PRINT "Division by zero not allowed.": END
  314.         IF LEFT$(d1divisor$, 1) = "-" THEN divsign% = -1: d1divisor$ = MID$(d1divisor$, 2)
  315.         IF LEFT$(d2dividend$, 1) = "-" THEN
  316.             IF divsign% THEN
  317.                 divsign% = 0
  318.             ELSE
  319.                 divsign% = -1
  320.             END IF
  321.             d2dividend$ = MID$(d2dividend$, 2)
  322.         END IF
  323.         IF INSTR(d1divisor$, ".") <> 0 THEN
  324.             DO UNTIL RIGHT$(d1divisor$, 1) <> "0"
  325.                 d1divisor$ = MID$(d1divisor$, 1, LEN(d1divisor$) - 1) ' Strip off trailing zeros
  326.             LOOP
  327.             divplace& = LEN(d1divisor$) - INSTR(d1divisor$, ".")
  328.             d1divisor$ = MID$(d1divisor$, 1, INSTR(d1divisor$, ".") - 1) + MID$(d1divisor$, INSTR(d1divisor$, ".") + 1) ' Strip off decimal point.
  329.             DO UNTIL LEFT$(d1divisor$, 1) <> "0"
  330.                 d1divisor$ = MID$(d1divisor$, 2) ' Strip off leading zeros for divisors smaller than .1
  331.             LOOP
  332.         END IF
  333.  
  334.         IF INSTR(d2dividend$, ".") <> 0 THEN
  335.             d2dividend$ = d2dividend$ + STRING$(divplace& - LEN(d2dividend$) - INSTR(d2dividend$, "."), "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
  336.             divplace2& = INSTR(d2dividend$, ".")
  337.             DO UNTIL RIGHT$(d2dividend$, 1) <> "0"
  338.                 d2dividend$ = MID$(d2dividend$, 1, LEN(d2dividend$) - 1) ' Strip off trailing zeros
  339.             LOOP
  340.             d2dividend$ = MID$(d2dividend$, 1, INSTR(d2dividend$, ".") - 1) + MID$(d2dividend$, INSTR(d2dividend$, ".") + 1) ' Strip off decimal point.
  341.         ELSE
  342.             d2dividend$ = d2dividend$ + STRING$(divplace&, "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
  343.             divplace& = 0
  344.         END IF
  345.         DO
  346.             DO
  347.                 divremainder& = divremainder& + 1: divremainder$ = divremainder$ + MID$(d2dividend$, divremainder&, 1)
  348.                 IF MID$(d2dividend$, divremainder&, 1) = "" THEN
  349.                     IF divremainder$ = STRING$(LEN(divremainder$), "0") AND LEN(quotient$) > LEN(d2dividend$) THEN divflag% = -1: EXIT DO
  350.                     divcarry& = divcarry& + 1
  351.                     IF divcarry& = 1 THEN divplace3& = divremainder& - 1
  352.                     IF divcarry& > limit&& + 1 + divbuffer& THEN
  353.                         divflag% = -2: EXIT DO
  354.                     END IF
  355.                     divremainder$ = divremainder$ + "0" ' No more digits to bring down.
  356.                 END IF
  357.                 IF LEN(divremainder$) > LEN(d1divisor$) OR LEN(divremainder$) = LEN(d1divisor$) AND divremainder$ >= d1divisor$ THEN EXIT DO
  358.                 quotient$ = quotient$ + "0"
  359.             LOOP
  360.             IF divflag% THEN divflag% = 0: EXIT DO
  361.             FOR div_i% = 9 TO 1 STEP -1
  362.                 stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
  363.                 m_product$ = "": GOSUB string_multiply
  364.                 tempcutd$ = divremainder$ ' divremainder$ can be 00 or other leading zero values.
  365.                 DO
  366.                     IF LEN(tempcutd$) = 1 THEN EXIT DO
  367.                     IF LEFT$(tempcutd$, 1) = "0" THEN
  368.                         tempcutd$ = MID$(tempcutd$, 2)
  369.                     ELSE
  370.                         EXIT DO
  371.                     END IF
  372.                 LOOP
  373.                 IF LEN(tempcutd$) > LEN(m_product$) OR LEN(tempcutd$) = LEN(m_product$) AND m_product$ <= tempcutd$ THEN EXIT FOR
  374.             NEXT
  375.             quotient$ = quotient$ + LTRIM$(STR$(div_i%))
  376.             stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
  377.             m_product$ = "": GOSUB string_multiply
  378.             operator$ = "-"
  379.             stringmatha$ = divremainder$
  380.             stringmathb$ = m_product$
  381.             GOSUB string_add_subtract
  382.             divremainder$ = stringmatha$
  383.             operator$ = "/"
  384.         LOOP
  385.         IF divplace& = 0 AND divplace2& = 0 THEN divplace& = divplace3&
  386.         IF divplace2& THEN divplace& = divplace& + divplace2& - 1
  387.         IF quotient$ = "" THEN divplace& = 0 ' dividend is zero.
  388.         IF divplace& OR divplace2& THEN
  389.             quotient$ = MID$(quotient$, 1, divplace&) + "." + MID$(quotient$, divplace& + 1)
  390.             DO UNTIL RIGHT$(quotient$, 1) <> "0"
  391.                 quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off trailing zeros
  392.             LOOP
  393.             IF RIGHT$(quotient$, 1) = "." THEN quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off abandoned decimal.
  394.         END IF
  395.         DO UNTIL LEFT$(quotient$, 1) <> "0"
  396.             quotient$ = MID$(quotient$, 2) ' Strip off leading zeros
  397.         LOOP
  398.         IF quotient$ = "" THEN quotient$ = "0": divsign% = 0
  399.         operationdivision% = 0
  400.         stringmathb$ = quotient$: quotient$ = "": GOSUB limit_round_convert
  401.         IF stringmathb$ = "overflow" THEN divsign% = 0: EXIT SUB
  402.         GOSUB sm_converter
  403.         runningtotal$ = stringmathb$: stringmathb$ = ""
  404.         IF divsign% THEN runningtotal$ = "-" + runningtotal$
  405. IF stringmathround$ <> "" THEN runningtotal$ = runningtotal$ + stringmathround$
  406.  
  407. validate_string_number:
  408. vsn_negcnt& = 0: vsn_poscnt& = 0: vsn_depresent& = 0: decimalcnt& = 0: vsn_numberpresent& = 0: vsn_zerospresent& = 0
  409. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-" ELSE sm_sign$ = ""
  410. IF LEFT$(stringmathb$, 1) = "+" THEN IF sm_sign$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 2) ELSE stringmathb$ = "invalid number": RETURN
  411. IF INSTR(UCASE$(stringmathb$), "D") OR INSTR(UCASE$(stringmathb$), "E") THEN ' Evaluate for Scientific Notation.
  412.     FOR sm_i& = 1 TO LEN(stringmathb$)
  413.         validatenum$ = MID$(UCASE$(stringmathb$), sm_i&, 1)
  414.         SELECT CASE validatenum$
  415.             CASE "+"
  416.                 IF vsn_depresent& THEN vsn_poscnt& = vsn_poscnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  417.             CASE "-"
  418.                 IF vsn_depresent& THEN vsn_negcnt& = vsn_negcnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  419.             CASE "0" TO "9"
  420.                 vsn_numberpresent& = -1
  421.             CASE "D", "E"
  422.                 vsn_depresent& = vsn_depresent& + 1
  423.                 IF decimalcnt& = 0 AND sm_i& <> 2 OR vsn_depresent& > 1 OR vsn_numberpresent& = 0 OR vsn_negcnt& > 1 OR vsn_poscnt& > 1 OR vsn_negcnt& = 1 AND vsn_poscnt& >= 1 THEN vsn_numberpresent& = 0: EXIT FOR
  424.                 vsn_numberpresent& = 0
  425.                 MID$(stringmathb$, sm_i&, 1) = "e" ' Standardize
  426.             CASE "."
  427.                 decimalcnt& = decimalcnt& + 1
  428.                 IF sm_i& <> 2 THEN vsn_numberpresent& = 0: EXIT FOR
  429.             CASE ELSE
  430.                 vsn_numberpresent& = 0: EXIT FOR
  431.         END SELECT
  432.     NEXT
  433.     IF decimalcnt& = 0 THEN stringmathb$ = MID$(stringmathb$, 1, 1) + "." + MID$(stringmathb$, 2) ' Standardize "."
  434.     IF vsn_numberpresent& = 0 OR vsn_negcnt& = 1 AND vsn_poscnt& = 1 OR decimalcnt& > 1 OR INSTR(stringmathb$, ".") <> 2 THEN stringmathb$ = "invalid number": RETURN
  435.     vsn_depresent& = INSTR(stringmathb$, "e")
  436.     sm_x$ = MID$(stringmathb$, vsn_depresent& + 1, 1) ' Standardize exponent "+" these two lines.
  437.     IF sm_x$ <> "+" AND sm_x$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 1, vsn_depresent&) + "+" + MID$(stringmathb$, vsn_depresent& + 1)
  438.     IF MID$(stringmathb$, vsn_depresent& + 2, 1) = "0" THEN
  439.         IF MID$(stringmathb$, vsn_depresent& + 3, 1) <> "" THEN stringmathb$ = "invalid number": RETURN ' No leading zeros allowed in exponent notation.
  440.     END IF
  441.     jjed& = INSTR(stringmathb$, "e") ' Get position of notation.
  442.     valexpside$ = MID$(stringmathb$, jjed&) ' These two lines break up into number and notation
  443.     stringmathb$ = MID$(stringmathb$, 1, jjed& - 1) ' stringmathb$ is +- single digit whole number, decimal point and decimal number. valexpside$ is notation, sign and exponent.
  444.     DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove any trailing zeros for number. Example 1.0d3 or 1.0000d3, etc.
  445.         stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  446.     LOOP
  447.     IF VAL(MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1)) = 0 THEN
  448.         IF RIGHT$(stringmathb$, 1) = "." THEN
  449.             stringmathb$ = "0.e+0" ' Handles all types of zero entries.
  450.         ELSE
  451.             stringmathb$ = "invalid number": RETURN
  452.         END IF
  453.         RETURN
  454.     END IF
  455.     stringmathb$ = sm_sign$ + stringmathb$ + valexpside$
  456.     RETURN
  457.     FOR sm_i& = 1 TO LEN(stringmathb$)
  458.         validatenum$ = MID$(stringmathb$, sm_i&, 1)
  459.         SELECT CASE validatenum$
  460.             CASE "."
  461.                 decimalcnt& = decimalcnt& + 1
  462.             CASE "0"
  463.                 vsn_zerospresent& = -1
  464.             CASE "1" TO "9"
  465.                 vsn_numberpresent& = -1
  466.             CASE "$"
  467.             CASE ELSE
  468.                 stringmathb$ = "invalid number": RETURN
  469.         END SELECT
  470.     NEXT
  471.     IF decimalcnt& > 1 OR vsn_negcnt& > 1 OR vsn_poscnt& > 1 OR vsn_negcnt& >= 1 AND vsn_poscnt& >= 1 THEN
  472.         stringmathb$ = "invalid number": RETURN
  473.     END IF
  474.     IF INSTR(stringmathb$, "$") THEN GOSUB currency_validate
  475.     IF INSTR(stringmathb$, ",") THEN
  476.         GOSUB comma_validation
  477.         IF stringmathb$ = "invalid number" THEN RETURN
  478.         GOSUB comma_removal
  479.     END IF
  480.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  481.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Strip off any leading zeros.
  482.         stringmathb$ = MID$(stringmathb$, 2)
  483.     LOOP
  484.     stringmathb$ = sm_sign$ + stringmathb$
  485.     IF INSTR(stringmathb$, ".") THEN
  486.         DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Strip off any trailing zeros in a decimal.
  487.             stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  488.         LOOP
  489.     END IF
  490.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  491.     IF vsn_numberpresent& = 0 THEN
  492.         IF vsn_zerospresent& THEN
  493.             stringmathb$ = "0"
  494.         ELSE
  495.             stringmathb$ = "invalid number"
  496.         END IF
  497.     END IF
  498.  
  499. ' Convert to commas, currency, S.N., etc.
  500. sm_converter:
  501. IF comma_display% THEN GOSUB comma_placement
  502. IF currency_display% THEN GOSUB currency_convert
  503. IF snconvert% THEN GOSUB numeric_to_scientific
  504.  
  505. ' Add in commas.
  506. comma_placement:
  507. GOSUB comma_prep
  508. sm_i& = 0: sm_j& = 0: sm_seed& = 0
  509. sm_seed& = LEN(temp_stringmathb1$) MOD 3: IF sm_seed& = 0 THEN sm_seed& = 3
  510. sm_m1& = LEN(temp_stringmathb1$)
  511. sm_m2& = (LEN(temp_stringmathb1$) - 1) \ 3
  512. sm_replace$ = SPACE$(sm_m1& + sm_m2&)
  513. DO WHILE sm_i& < sm_m1&
  514.     MID$(sm_replace$, sm_j& + 1, sm_seed& + 1) = MID$(temp_stringmathb1$, sm_i& + 1, sm_seed&) + ","
  515.     sm_i& = sm_i& + sm_seed&: sm_j& = sm_j& + sm_seed& + 1: sm_seed& = 3
  516. sm_replace$ = RTRIM$(sm_replace$)
  517. IF RIGHT$(sm_replace$, 1) = "," THEN
  518.     stringmathb$ = MID$(sm_replace$, 1, LEN(sm_replace$) - 1)
  519.     stringmathb$ = sm_replace$
  520. sm_replace$ = "": temp_stringmathb1$ = ""
  521.  
  522. ' Validate comma entry.
  523. comma_validation:
  524. GOSUB comma_prep
  525. IF INSTR(temp_stringmathb2$, ",") <> 0 OR temp_stringmathb1$ = STRING$(LEN(temp_stringmathb1$), ",") THEN
  526.     stringmathb$ = "invalid number" ' Decimal part has comma or entry is all commas.
  527.     FOR sm_i& = LEN(temp_stringmathb1$) TO 1 STEP -1
  528.         sm_j% = sm_j% + 1
  529.         IF sm_j% = 4 THEN
  530.             IF MID$(temp_stringmathb1$, sm_i&, 1) <> "," THEN stringmathb$ = "invalid number": EXIT FOR
  531.             sm_j% = 0
  532.         END IF
  533.     NEXT
  534.     IF stringmathb$ <> "invalid number" THEN
  535.         stringmathb$ = sm_sign$ + temp_stringmathb1$ + temp_stringmathb2$
  536.     END IF
  537. temp_stringmathb1$ = "": temp_stringmathb2$ = "": sm_i& = 0: sm_j% = 0: sm_sign$ = "": sm_dollar$ = ""
  538.  
  539. comma_removal:
  540. sm_i& = 0: sm_j& = 0: sm_seed& = 0
  541. sm_replace$ = SPACE$(LEN(stringmathb$))
  542.     sm_i& = INSTR(sm_seed& + 1, stringmathb$, ",")
  543.     IF sm_i& = 0 THEN EXIT DO
  544.     MID$(sm_replace$, sm_j& + 1, sm_i& - sm_seed& + 1) = MID$(stringmathb$, sm_seed& + 1, sm_i& - sm_seed& - 1)
  545.     sm_j& = sm_j& + sm_i& - sm_seed& - 1
  546.     sm_seed& = sm_i&
  547. stringmathb$ = RTRIM$(sm_replace$) + MID$(stringmathb$, sm_seed& + 1): sm_replace$ = ""
  548.  
  549. comma_prep:
  550. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-"
  551. temp_stringmathb1$ = stringmathb$: stringmathb$ = ""
  552. IF INSTR(temp_stringmathb1$, ".") THEN
  553.     temp_stringmathb2$ = MID$(temp_stringmathb1$, INSTR(temp_stringmathb1$, ".")) ' Decimal part
  554.     temp_stringmathb1$ = MID$(temp_stringmathb1$, 1, INSTR(temp_stringmathb1$, ".") - 1) ' Non-decimal part
  555. IF LEFT$(temp_stringmathb1$, 1) = "$" THEN temp_stringmathb1$ = MID$(temp_stringmathb1$, 2): sm_dollar$ = "$"
  556.  
  557. currency_validate:
  558. IF LEFT$(stringmathb$, 2) = "$-" OR LEFT$(stringmathb$, 2) = "$+" THEN stringmathb$ = "invalid number": RETURN
  559. IF LEFT$(stringmathb$, 1) = "$" THEN stringmathb$ = MID$(stringmathb$, 2)
  560. IF INSTR(stringmathb$, "$") THEN stringmathb$ = "invalid number": RETURN
  561. sm_dollar$ = "$"
  562.  
  563. currency_convert:
  564. IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN GOSUB scientific_to_numeric
  565. IF INSTR(stringmathb$, ",") = 0 THEN GOSUB comma_placement
  566. IF INSTR(stringmathb$, ".") = 0 THEN stringmathb$ = stringmathb$ + ".00"
  567. IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = stringmathb$ + "00"
  568. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = stringmathb$ + "0"
  569. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = "invalid number": RETURN
  570. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  571. stringmathb$ = sm_sign$ + "$" + stringmathb$
  572.  
  573. numeric_to_scientific:
  574. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): n2sign$ = "-"
  575. IF INSTR(stringmathb$, ".") = 0 THEN exponentvalue&& = LEN(stringmathb$) - 1 ELSE exponentvalue&& = INSTR(stringmathb$, ".") - 2 ' Exponent is one less than number of digits for whole number an two less than the placement of the decimal point for a fraction.
  576. stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1)
  577. IF LEFT$(stringmathb$, 1) = "0" AND LEN(stringmathb$) > 1 OR exponentvalue&& = -1 THEN
  578.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Remove leading zeros to consider rounding.
  579.         stringmathb$ = MID$(stringmathb$, 2)
  580.         exponentvalue&& = exponentvalue&& - 1
  581.     LOOP
  582.     esign$ = "-"
  583.     esign$ = "+"
  584. DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove trailing zeros.
  585.     stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  586. IF stringmathb$ = "" THEN stringmathb$ = "0": esign$ = "+": exponentvalue&& = 0
  587. stringmathb$ = LEFT$(stringmathb$, 1) + "." + MID$(stringmathb$, 2)
  588. IF stringmathb$ = "0." THEN n2sign$ = "": esign$ = "+"
  589. stringmathb$ = stringmathb$ + "e" + esign$ + LTRIM$(STR$(ABS(exponentvalue&&))) ' S.N formed here.
  590. IF stringmathb$ <> "overflow" THEN
  591.     stringmathb$ = n2sign$ + stringmathb$
  592. n2sign$ = "": esign$ = "": exponentvalue&& = 0
  593.  
  594. scientific_to_numeric:
  595. IF INSTR(UCASE$(stringmathb$), "D") THEN MID$(stringmathb$, INSTR(UCASE$(stringmathb$), "D"), 1) = "e"
  596. IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 2) = "0" THEN ' The numeric value is the number without the zero exponent.
  597.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, "e") - 1)
  598.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  599.     RETURN
  600.     IF LEFT$(stringmathb$, 1) = "-" THEN stn_sign$ = "-": stringmathb$ = MID$(stringmathb$, 2)
  601.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Remove decimal point.
  602.     stn_i& = INSTR(stringmathb$, "e") - 1 ' Length of the numric part.
  603.     IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 1, 1) = "-" THEN
  604.         stringmathb$ = "." + STRING$(VAL(MID$(stringmathb$, stn_i& + 3)) - 1, "0") + MID$(stringmathb$, 1, stn_i&) ' Decimal point followed by exponent value in zeros added in front of numeric part.
  605.     ELSE
  606.         IF stn_i& - 1 > VAL(MID$(stringmathb$, stn_i& + 3)) THEN stn_point$ = "." ' - 1 for decimal place. Ex 2.034d+2 is 2034 here where 3 places to the right . could be moved before . disappears. > so no trailing decimal results.
  607.         stringmathb$ = MID$(MID$(stringmathb$, 1, stn_i&), 1, VAL(MID$(stringmathb$, stn_i& + 3)) + 1) + stn_point$ + MID$(MID$(stringmathb$, 1, stn_i&), VAL(MID$(stringmathb$, stn_i& + 3)) + 2, stn_i& - VAL(MID$(stringmathb$, stn_i& + 3)) - 1) + STRING$(VAL(MID$(stringmathb$, stn_i& + 2)) - (stn_i& - 1), "0")
  608.     END IF
  609. IF stringmathb$ = "0" THEN stn_sign$ = ""
  610. stringmathb$ = stn_sign$ + stringmathb$
  611. stn_sign$ = "": stn_point$ = ""
  612.  
  613. limit_round_convert:
  614. ' Try SN if whole number is too large (as it may be trailing zeros) or decimal is beyond limit.
  615. IF LEFT$(stringmathb$, 2) = ".0" AND LEN(stringmathb$) > limit&& + 1 OR INSTR(stringmathb$, ".") > limit&& + 1 OR INSTR(stringmathb$, ".") = 0 AND LEN(stringmathb$) > limit&& THEN
  616.     IF limit&& > 1 THEN
  617.         GOSUB numeric_to_scientific ' Retry as S.N.
  618.         IF LEN(stringmathb$) > limit&& + 3 THEN ' Needs rounding.
  619.             snotation$ = MID$(stringmathb$, INSTR(UCASE$(stringmathb$), "E"))
  620.             exponentvalue&& = VAL(MID$(snotation$, 2)) ' Get positive or negative sign.
  621.             snexponent$ = MID$(stringmathb$, INSTR(UCASE$(stringmathb$), "E") + 2)
  622.             stringmathb$ = MID$(stringmathb$, 1, INSTR(UCASE$(stringmathb$), "E") - 1)
  623.             '''IF LEN(stringmathb$) + LEN(snexponent$) > limit&& + 1 AND exponentvalue&& >= limit&& THEN BEEP
  624.             IF exponentvalue&& >= limit&& THEN
  625.                 stringmathb$ = MID$(stringmathb$, 1, exponentvalue&& + 3)
  626.             ELSE
  627.                 stringmathb$ = MID$(stringmathb$, 1, limit&& - LEN(snexponent$) + 2)
  628.             END IF
  629.             GOSUB string_rounding_method
  630.             IF LEFT$(stringmathb$, 3) = "10." THEN
  631.                 stringmathb$ = "1." + MID$(stringmathb$, 4)
  632.                 ' Add one to the exponent.
  633.                 FOR round_i& = LEN(snexponent$) TO 1 STEP -1
  634.                     round_x$ = CHR$(ASC(MID$(snexponent$, round_i&, 1)) + 1)
  635.                     IF round_x$ <> CHR$(47) THEN ' Decimal point + 1. Ignore.
  636.                         IF round_x$ = CHR$(58) THEN
  637.                             MID$(snexponent$, round_i&, 1) = "0": carry$ = "1"
  638.                         ELSE
  639.                             MID$(snexponent$, round_i&, 1) = round_x$: carry$ = "": EXIT FOR
  640.                         END IF
  641.                     END IF
  642.                 NEXT
  643.                 snexponent$ = carry$ + snexponent$: carry$ = ""
  644.             END IF
  645.             stringmathb$ = stringmathb$ + MID$(snotation$, 1, 2) + snexponent$
  646.             IF LEN(snexponent$) + LEN(MID$(stringmathb$, 1, INSTR(UCASE$(stringmathb$), "E") - 1)) > limit&& + 1 THEN
  647.                 stringmathb$ = "overflow"
  648.             END IF
  649.             exponentvalue&& = 0
  650.         END IF
  651.     ELSE
  652.         IF INSTR(stringmathb$, ".") > 0 AND INSTR(stringmathb$, ".") <= limit&& THEN
  653.             stringmathb$ = MID$(stringmathb$, 1, limit&& + 2)
  654.             IF round_total% = -1 AND RIGHT$(stringmathb$, 1) > "4" THEN
  655.                 GOSUB string_rounding_method
  656.             ELSE
  657.                 stringmathb$ = MID$(stringmathb$, 1, limit&& + 1)
  658.                 IF show_rounding% THEN stringmathround$ = "r"
  659.             END IF
  660.         ELSE
  661.             stringmathb$ = "overflow"
  662.         END IF
  663.     END IF
  664.     RETURN
  665. IF LEN(stringmathb$) > limit&& AND INSTR(stringmathb$, ".") = 0 OR LEN(stringmathb$) > limit&& + 1 AND INSTR(stringmathb$, ".") <> 0 THEN
  666.     IF INSTR(stringmathb$, ".") = 0 THEN
  667.         stringmathb$ = MID$(stringmathb$, 1, limit&& + 1)
  668.     ELSE
  669.         stringmathb$ = MID$(stringmathb$, 1, limit&& + 2)
  670.     END IF
  671.     GOSUB string_rounding_method
  672.     IF LEN(stringmathb$) > limit&& + lrc_decimalpoint& THEN ' Ex: limit&& = 4 9999.9 1.e+4
  673.         GOSUB numeric_to_scientific
  674.     ELSE
  675.         IF LEN(stringmathb$) > limit&& + lrc_decimalpoint& THEN stringmathb$ = "overflow"
  676.     END IF
  677.  
  678. replace_decimal:
  679. IF addsubplace& THEN
  680.     addsubx1$ = STRING$(addsubplace& - LEN(addsubx1$), "0") + addsubx1$
  681.     addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - addsubplace&) + "." + MID$(addsubx1$, LEN(addsubx1$) - addsubplace& + 1)
  682.     DO UNTIL RIGHT$(addsubx1$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
  683.         addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1)
  684.         addsubplace& = addsubplace& - 1
  685.     LOOP
  686.     IF RIGHT$(addsubx1$, 1) = "." THEN addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1) ' Number is now an integer.
  687.  
  688. string_rounding_method:
  689. IF INSTR(stringmathb$, ".") THEN lrc_decimalpoint& = 1 ELSE lrc_decimalpoint& = 0
  690. IF MID$(stringmathb$, LEN(stringmathb$), 1) > "4" THEN
  691.     FOR round_i& = LEN(stringmathb$) - 1 TO 1 STEP -1
  692.         round_x$ = CHR$(ASC(MID$(stringmathb$, round_i&, 1)) + 1)
  693.         IF round_x$ <> CHR$(47) THEN ' Decimal point + 1. Ignore.
  694.             IF round_x$ = CHR$(58) THEN
  695.                 MID$(stringmathb$, round_i&, 1) = "0": carry$ = "1"
  696.             ELSE
  697.                 MID$(stringmathb$, round_i&, 1) = round_x$: carry$ = "": EXIT FOR
  698.             END IF
  699.         END IF
  700.     NEXT
  701.     stringmathb$ = carry$ + MID$(stringmathb$, 1, LEN(stringmathb$) - 1): carry$ = ""
  702.     IF show_rounding% THEN stringmathround$ = "R"
  703.     stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  704.     IF show_rounding% THEN stringmathround$ = "r"
  705.  
  706. IF lrc_decimalpoint& THEN
  707.     DO UNTIL RIGHT$(stringmathb$, 1) <> "0"
  708.         stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  709.     LOOP
  710.     IF stringmathb$ = "" OR stringmathb$ = "." THEN stringmathb$ = "0": lrc_decimalpoint& = 0
  711.     IF RIGHT$(stringmathb$, 1) = "." AND exponentvalue&& = 0 THEN
  712.         stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1): lrc_decimalpoint& = 0
  713.     END IF

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #34 on: April 10, 2019, 01:16:43 pm »
Was the rounding oddity about "round to the nearest even number" functionality?

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #35 on: April 10, 2019, 02:11:43 pm »
Do you mean in the screen shot I posted? If so, I was worried when my routine left the figure as all 9's. I thought the only way it wouldn't round up to 649146.5 is if the digit after that last 9 in 649146.49999999999 was an 8. So I checked it with a calculator, and it was an 8. That got rounded up as a nine, the last digit of the 17 digit limit I set for that operation. So it did round correctly. Also, I use a capital "R" at the end, to indicate it rounded up. A lowercase "r" would indicate it rounded down.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #36 on: April 10, 2019, 04:37:58 pm »
I only know that BASIC in some form rounds up or down based on even whole numbers:

... -6, -4, -2, 0, 2, 4, 6 ...

So 1.5 and 2.5 would both round to 2.  I have never liked this style of rounding, I learned 0.5 rounds up, and -0.5 rounds up or down, depending on the type of rounding.  I don't like even-number rounding, because it creates uneven data sets:

0, 0, 2, 2, 4, 4 ...

Anyhow, probably not related, but one more odd way BASIC can round things internally.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #37 on: April 10, 2019, 06:51:13 pm »
I used round up for 5 and over, round down for 4 and under. That's a standard. The other way I think is called "Banker's Rounding." That's where if the rounding digit is 5, and there are no other non-zero digits trailing it, you look at the number immediately preceding the rounding number, and round up only if that preceding number is even.

I'm still on the fence if I would consider changing to that.

Pete

Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #38 on: April 10, 2019, 06:58:23 pm »
I used round up for 5 and over, round down for 4 and under. That's a standard. The other way I think is called "Banker's Rounding." That's where if the rounding digit is 5, and there are no other non-zero digits trailing it, you look at the number immediately preceding the rounding number, and round up only if that preceding number is even.

I'm still on the fence if I would consider changing to that.

Pete

Banker's Rounding sounds like a more "fair" form of rounding.  0.5 is halfway, going up or down are both wrong, heh.  Dividing whether it goes up or down half the time is fair, but I didn't understand what you meant about the other digits causing the rounding.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #39 on: April 10, 2019, 07:43:03 pm »
Example: 2.315 and 2.325 round to hundredths.

In Banker's Rounding, we have both digits in the thousandth ending in a 5, so both numbers are eligible to be rounded.

Next we look at the digit in front of each 5.

2.315 (The digit in front of the 5 is a 1, and odd number.)

2.325 (The digit in front of the 5 is a 2, an even number.)

In Banker's Rounding, we round up the value of an odd number in front of the trailing "5" digit to an even number and we leave even numbers alone.

So, 2.315 gets changed to 2.325 and 2.125 stays as 2.325.

Now, to get to hundredths, we drop the 5 off of each, and end up with both being...

2.32

And I'm glad I did an example this time, because I just re-read my last post and I should have ended that last sentence with odd, not even, as in...

I used round up for 5 and over, round down for 4 and under. That's a standard. The other way I think is called "Banker's Rounding." That's where if the rounding digit is 5, and there are no other non-zero digits trailing it, you look at the number immediately preceding the rounding number, and round up only if that preceding number is odd.

So both round to 2.32—instead of 2.325 rounding up to 2.33—when rounded off to the nearest 100th. The rationale for the third rule is that approximately half of the time the number will be rounded up and the other half of the time it will be rounded down.

Sorry for messing that up in my previous post.

Pete
« Last Edit: April 11, 2019, 12:56:49 pm by Pete »
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #40 on: April 11, 2019, 10:50:10 am »
I don't like rounding. I say if you want to round to the 3rd digit past the decimal then show me the 4th digit. I thought that rounding affects the accuracy of calculations negatively, but I can't seem to find people saying that.

My rounding pun
Farmer Brown had 290 cows but it was 300 once he rounded up
QB64 is the best!

Offline jack

  • Seasoned Forum Regular
  • Posts: 408
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #41 on: April 11, 2019, 11:53:16 am »
maybe your pun should be "Farmer Brown thought he had 290 cows but it was 300 once he rounded up"

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #42 on: April 11, 2019, 12:31:11 pm »
"After losing his 290 cows, Farmer Brown later that day rounded up his 300 cows."

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Yuck String Math or What's wrong with FOO?
« Reply #43 on: April 11, 2019, 02:42:27 pm »
You guys should quit picking on us farmers, when it comes to math.  We’re rather good at it.  To illustrate the point, let me tell you a tale my Grandpa told.

Back in the early 1900’s, everyone’s child was in a rush to head off to the city and get “educated” proper.  It turns out, Grandpa’s neighbor’s children all went off and headed to college.  While the oldest was getting his PHD, and the youngest was just starting, their father passed away.  All three children rushed home for the funeral and reading of the will.

In the will, their father divided up his herd of horses in the following manner.  The first born was supposed to get one half of the herd, the second child was supposed to get one third, while the youngest boy should’ve gotten one ninth.

Now, since their father had seventeen horses, they had no idea of what to do.  No mater how they proposed settling the issue, they just couldn’t make the numbers work to everyone’s satisfaction.  Luckily, my grandfather stopped by around that time to offer his condolences on their loss.  When presented with their quandary, he gave them his horse as a bereavement give.

With eighteen horses now, the oldest got nine, the second child got six, and the third child got two.  Taking the one that was left over as payment for services rendered, Grandfather left later that evening on the same horse he rode in on...

Who says farmers don’t know math?  ;D
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Yuck String Math or What's wrong with FOO?
« Reply #44 on: April 11, 2019, 04:19:57 pm »
Well it looks like I drug this thread off topic. I'm denying all responsibility.

Rounding tho. Anyone else think its inaccurate? I think if you divide 1 by 3 and get 0.333333 report all your digits and don't hide or round anything. Calculators are now reporting in fractional mode and preserve value when its not a repeating integer.
We use numbers in base 10 (usually) to represent an idea. They are not the idea, they are the representation.

QB64 is the best!