Author Topic: Working on a comma system for string math routine...  (Read 4431 times)

0 Members and 1 Guest are viewing this topic.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Working on a comma system for string math routine...
« on: March 27, 2019, 11:40:11 am »
I think this routine should be able to handle comma entries and if I create a variable, my string math routine should be able to return results with or without commas present, as well as accept and convert entries made with commas.

Please note, only use numbers, one or no decimal point, and commas. I have a completely separate validation routine that handles other types off erroneous entries, which I hope to add this routine to, if it's solid.

Code: QB64: [Select]
  1. LINE INPUT "Number: "; b$
  2.     PRINT
  3.     IF INSTR(b$, ",") THEN PRINT "1) Vaildate commas": x$ = x$ + "1"
  4.     IF INSTR(b$, ",") = 0 THEN PRINT "2) Add commas": x$ = x$ + "2"
  5.     IF INSTR(b$, ",") THEN PRINT "3) Remove commas": x$ = x$ + "3"
  6.     PRINT "4) New number": x$ = x$ + "4"
  7.     PRINT
  8.     DO
  9.         _LIMIT 10
  10.         k$ = INKEY$
  11.         IF k$ = CHR$(27) THEN SYSTEM
  12.         IF LEN(k$) AND INSTR(x$, k$) <> 0 THEN
  13.             SELECT CASE k$
  14.                 CASE "1"
  15.                     GOSUB comma_validation
  16.                     IF b$ = "invalid number" THEN PRINT: RUN
  17.                 CASE "2"
  18.                     GOSUB comma_placement
  19.                 CASE "3"
  20.                     GOSUB comma_removal
  21.                 CASE "4"
  22.                     RUN
  23.             END SELECT
  24.             x$ = ""
  25.             EXIT DO
  26.         END IF
  27.     LOOP
  28.  
  29. ' Add in commas.
  30. comma_placement:
  31. GOSUB comma_prep
  32. FOR i& = LEN(b2$) TO 1 STEP -1
  33.     j% = j% + 1
  34.     IF j% = 4 THEN b$ = "," + b$: j% = 1
  35.     b$ = MID$(b2$, i&, 1) + b$
  36. b$ = b$ + b3$: b3$ = "": b2$ = "": i& = 0
  37.  
  38. ' Validate comma entry.
  39. comma_validation:
  40. GOSUB comma_prep
  41. IF INSTR(b3$, ",") <> 0 OR b2$ = STRING$(LEN(b2$), ",") THEN
  42.     b$ = "invalid number"
  43.     FOR i& = LEN(b2$) TO 1 STEP -1
  44.         j% = j% + 1
  45.         IF j% = 4 THEN
  46.             IF MID$(b2$, i&, 1) <> "," THEN b$ = "invalid number": EXIT FOR
  47.             j% = 0
  48.         END IF
  49.     NEXT
  50.     IF b$ <> "invalid number" THEN
  51.         b$ = b2$ + b3$
  52.     END IF
  53. b3$ = "": b2$ = "": i& = 0
  54.  
  55. comma_removal:
  56. DO UNTIL INSTR(b$, ",") = 0
  57.     b$ = MID$(b$, 1, INSTR(b$, ",") - 1) + MID$(b$, INSTR(b$, ",") + 1)
  58.  
  59. comma_prep:
  60. b2$ = b$: b$ = "": j% = 0
  61. IF INSTR(b2$, ".") THEN
  62.     b3$ = MID$(b2$, INSTR(b2$, "."))
  63.     b2$ = MID$(b2$, 1, INSTR(b2$, ".") - 1)
  64.  

If anyone wants to give it a quick try and see if he can find an inaccurate result, please do so and let me know.

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

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #1 on: March 27, 2019, 01:03:50 pm »
Quote
If anyone wants to give it a quick try and see if he can find an inaccurate result, please do so and let me know.

Pete

I like these dares to try and break code. ;-))

OK tried 000000000000000.0000000 and put commas in right place if first 0 was digit but...
« Last Edit: March 27, 2019, 01:08:37 pm by bplus »

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #2 on: March 27, 2019, 02:37:02 pm »
Worked perfectly for me Pete. And ya, a negative number does throw it off, so I gather a dollar sign etc would as well.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #3 on: March 30, 2019, 01:33:22 pm »
Thanks Mark and Dimster for trying it out. Sorry for the late reply, but I wanted to get to the weekend to spend some more time on adding some other features. If you are up to trying it one more time, this enhanced version should stomp out any invalid entries for numeric or scientific notation input. It also converts between scientific notation, standard numeric notation, and dollars and cents notation.

Please let me know if you can break the code!

Pete

Code: QB64: [Select]
  1. LINE INPUT "Number: "; stringmathb$
  2. GOSUB validate_string_number
  3. PRINT "Validated: "; stringmathb$
  4. IF stringmathb$ = "invalid number" THEN RUN
  5.     PRINT
  6.     IF INSTR(stringmathb$, ",") = 0 THEN PRINT "1) Add Commas": x$ = x$ + "1"
  7.     IF INSTR(stringmathb$, ",") THEN PRINT "2) Remove Commas": x$ = x$ + "2"
  8.     IF INSTR(stringmathb$, "$") = 0 THEN PRINT "3) Convert to Dollars and Cents": x$ = x$ + "3"
  9.     IF INSTR(stringmathb$, "$") THEN PRINT "4) Convert to Numeric": x$ = x$ + "4"
  10.     IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN
  11.         PRINT "5) Convert to Numeric": x$ = x$ + "5"
  12.     ELSE
  13.         PRINT "6) Convert to S.N.": x$ = x$ + "6"
  14.     END IF
  15.     PRINT "7) New number": x$ = x$ + "7"
  16.     PRINT
  17.     DO
  18.         _LIMIT 10
  19.         k$ = INKEY$
  20.         IF k$ = CHR$(27) THEN SYSTEM
  21.         IF LEN(k$) AND INSTR(x$, k$) <> 0 THEN
  22.             SELECT CASE k$
  23.                 CASE "1"
  24.                     GOSUB comma_placement
  25.                 CASE "2"
  26.                     GOSUB comma_removal
  27.                 CASE "3"
  28.                     GOSUB currency_convert
  29.                 CASE "4"
  30.                     GOSUB validate_string_number
  31.                 CASE "5"
  32.                     IF INSTR(stringmathb$, "$") THEN GOSUB validate_string_number
  33.                     GOSUB scientific_to_numeric
  34.                 CASE "6"
  35.                     IF INSTR(stringmathb$, "$") THEN GOSUB validate_string_number
  36.                     GOSUB numeric_to_scientific
  37.                 CASE "7"
  38.                     RUN
  39.             END SELECT
  40.             PRINT stringmathb$
  41.             x$ = ""
  42.             IF stringmathb$ = "invalid number" THEN RUN
  43.             EXIT DO
  44.         END IF
  45.     LOOP
  46.  
  47. validate_string_number:
  48. vsn_negcnt& = 0: vsn_poscnt& = 0: vsn_depresent& = 0: decimalcnt& = 0: vsn_numberpresent& = 0: vsn_zerospresent& = 0
  49. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-" ELSE sm_sign$ = ""
  50. IF LEFT$(stringmathb$, 1) = "+" THEN IF sm_sign$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 2) ELSE stringmathb$ = "invalid number": RETURN
  51. IF INSTR(UCASE$(stringmathb$), "D") OR INSTR(UCASE$(stringmathb$), "E") THEN ' Evaluate for Scientific Notation.
  52.     FOR sm_i& = 1 TO LEN(stringmathb$)
  53.         validatenum$ = MID$(UCASE$(stringmathb$), sm_i&, 1)
  54.         SELECT CASE validatenum$
  55.             CASE "+"
  56.                 IF vsn_depresent& THEN vsn_poscnt& = vsn_poscnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  57.             CASE "-"
  58.                 IF vsn_depresent& THEN vsn_negcnt& = vsn_negcnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  59.             CASE "0" TO "9"
  60.                 vsn_numberpresent& = -1
  61.             CASE "D", "E"
  62.                 vsn_depresent& = vsn_depresent& + 1
  63.                 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
  64.                 vsn_numberpresent& = 0
  65.                 MID$(stringmathb$, sm_i&, 1) = "e" ' Standardize
  66.             CASE "."
  67.                 decimalcnt& = decimalcnt& + 1
  68.                 IF sm_i& <> 2 THEN vsn_numberpresent& = 0: EXIT FOR
  69.             CASE ELSE
  70.                 vsn_numberpresent& = 0: EXIT FOR
  71.         END SELECT
  72.     NEXT
  73.     IF decimalcnt& = 0 THEN stringmathb$ = MID$(stringmathb$, 1, 1) + "." + MID$(stringmathb$, 2) ' Standardize "."
  74.     IF vsn_numberpresent& = 0 OR vsn_negcnt& = 1 AND vsn_poscnt& = 1 OR decimalcnt& > 1 OR INSTR(stringmathb$, ".") <> 2 THEN stringmathb$ = "invalid number": RETURN
  75.     vsn_depresent& = INSTR(stringmathb$, "e")
  76.     sm_x$ = MID$(stringmathb$, vsn_depresent& + 1, 1) ' Standardize exponent "+" these two lines.
  77.     IF sm_x$ <> "+" AND sm_x$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 1, vsn_depresent&) + "+" + MID$(stringmathb$, vsn_depresent& + 1)
  78.     IF MID$(stringmathb$, vsn_depresent& + 2, 1) = "0" THEN
  79.         IF MID$(stringmathb$, vsn_depresent& + 3, 1) <> "" THEN stringmathb$ = "invalid number": RETURN ' No leading zeros allowed in exponent notation.
  80.     END IF
  81.     jjed& = INSTR(stringmathb$, "e") ' Get position of notation.
  82.     valexpside$ = MID$(stringmathb$, jjed&) ' These two lines break up into number and notation
  83.     stringmathb$ = MID$(stringmathb$, 1, jjed& - 1) ' stringmathb$ is +- single digit whole number, decimal point and decimal number. valexpside$ is notation, sign and exponent.
  84.     DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove any trailing zeros for number. Example 1.0d3 or 1.0000d3, etc.
  85.         stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  86.     LOOP
  87.     IF VAL(MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1)) = 0 THEN
  88.         IF RIGHT$(stringmathb$, 1) = "." THEN
  89.             stringmathb$ = "0.e+0" ' Handles all types of zero entries.
  90.         ELSE
  91.             stringmathb$ = "invalid number": RETURN
  92.         END IF
  93.         RETURN
  94.     END IF
  95.     stringmathb$ = sm_sign$ + stringmathb$ + valexpside$
  96.     RETURN
  97.     FOR sm_i& = 1 TO LEN(stringmathb$)
  98.         validatenum$ = MID$(stringmathb$, sm_i&, 1)
  99.         SELECT CASE validatenum$
  100.             CASE "."
  101.                 decimalcnt& = decimalcnt& + 1
  102.             CASE "0"
  103.                 vsn_zerospresent& = -1
  104.             CASE "1" TO "9"
  105.                 vsn_numberpresent& = -1
  106.             CASE "$"
  107.             CASE ELSE
  108.                 stringmathb$ = "invalid number": RETURN
  109.         END SELECT
  110.     NEXT
  111.     IF decimalcnt& > 1 OR vsn_negcnt& > 1 OR vsn_poscnt& > 1 OR vsn_negcnt& >= 1 AND vsn_poscnt& >= 1 THEN
  112.         stringmathb$ = "invalid number": RETURN
  113.     END IF
  114.     IF INSTR(stringmathb$, "$") THEN GOSUB currency_validate
  115.     IF INSTR(stringmathb$, ",") THEN
  116.         GOSUB comma_validation
  117.         IF stringmathb$ = "invalid number" THEN RETURN
  118.         GOSUB comma_removal
  119.     END IF
  120.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  121.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Strip off any leading zeros.
  122.         stringmathb$ = MID$(stringmathb$, 2)
  123.     LOOP
  124.     stringmathb$ = sm_sign$ + stringmathb$
  125.     IF INSTR(stringmathb$, ".") THEN
  126.         DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Strip off any trailing zeros in a decimal.
  127.             stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  128.         LOOP
  129.     END IF
  130.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  131.     IF vsn_numberpresent& = 0 THEN
  132.         IF vsn_zerospresent& THEN
  133.             stringmathb$ = "0"
  134.         ELSE
  135.             stringmathb$ = "invalid number"
  136.         END IF
  137.     END IF
  138.  
  139. ' Add in commas.
  140. comma_placement:
  141. GOSUB comma_prep
  142. FOR sm_i& = LEN(temp_stringmathb1$) TO 1 STEP -1
  143.     sm_j% = sm_j% + 1
  144.     IF sm_j% = 4 THEN stringmathb$ = "," + stringmathb$: sm_j% = 1
  145.     stringmathb$ = MID$(temp_stringmathb1$, sm_i&, 1) + stringmathb$
  146. stringmathb$ = sm_sign$ + stringmathb$ + temp_stringmathb2$
  147. temp_stringmathb1$ = "": temp_stringmathb2$ = "": sm_i& = 0: sm_j% = 0
  148.  
  149. ' Validate comma entry.
  150. comma_validation:
  151. GOSUB comma_prep
  152. IF INSTR(temp_stringmathb2$, ",") <> 0 OR temp_stringmathb1$ = STRING$(LEN(temp_stringmathb1$), ",") THEN
  153.     stringmathb$ = "invalid number" ' Decimal part has comma or entry is all commas.
  154.     FOR sm_i& = LEN(temp_stringmathb1$) TO 1 STEP -1
  155.         sm_j% = sm_j% + 1
  156.         IF sm_j% = 4 THEN
  157.             IF MID$(temp_stringmathb1$, sm_i&, 1) <> "," THEN stringmathb$ = "invalid number": EXIT FOR
  158.             sm_j% = 0
  159.         END IF
  160.     NEXT
  161.     IF stringmathb$ <> "invalid number" THEN
  162.         stringmathb$ = sm_sign$ + temp_stringmathb1$ + temp_stringmathb2$
  163.     END IF
  164. temp_stringmathb1$ = "": temp_stringmathb2$ = "": sm_i& = 0: sm_j% = 0: sm_sign$ = "": sm_dollar$ = ""
  165.  
  166. comma_removal:
  167. DO UNTIL INSTR(stringmathb$, ",") = 0
  168.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ",") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ",") + 1)
  169.  
  170. comma_prep:
  171. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-"
  172. temp_stringmathb1$ = stringmathb$: stringmathb$ = ""
  173. IF INSTR(temp_stringmathb1$, ".") THEN
  174.     temp_stringmathb2$ = MID$(temp_stringmathb1$, INSTR(temp_stringmathb1$, ".")) ' Decimal part
  175.     temp_stringmathb1$ = MID$(temp_stringmathb1$, 1, INSTR(temp_stringmathb1$, ".") - 1) ' Non-decimal part
  176. IF LEFT$(temp_stringmathb1$, 1) = "$" THEN temp_stringmathb1$ = MID$(temp_stringmathb1$, 2): sm_dollar$ = "$"
  177.  
  178. currency_validate:
  179. IF LEFT$(stringmathb$, 2) = "$-" OR LEFT$(stringmathb$, 2) = "$+" THEN stringmathb$ = "invalid number": RETURN
  180. IF LEFT$(stringmathb$, 1) = "$" THEN stringmathb$ = MID$(stringmathb$, 2)
  181. IF INSTR(stringmathb$, "$") THEN stringmathb$ = "invalid number": RETURN
  182. sm_dollar$ = "$"
  183.  
  184. currency_convert:
  185. IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN GOSUB scientific_to_numeric
  186. IF INSTR(stringmathb$, ",") = 0 THEN GOSUB comma_placement
  187. IF INSTR(stringmathb$, ".") = 0 THEN stringmathb$ = stringmathb$ + ".00"
  188. IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = stringmathb$ + "00"
  189. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = stringmathb$ + "0"
  190. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = "invalid number": RETURN
  191. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  192. stringmathb$ = sm_sign$ + "$" + stringmathb$
  193.  
  194. numeric_to_scientific:
  195. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): n2sign$ = "-"
  196. 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.
  197. stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1)
  198. IF LEFT$(stringmathb$, 1) = "0" AND LEN(stringmathb$) > 1 OR exponentvalue&& = -1 THEN
  199.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Remove leading zeros to consider rounding.
  200.         stringmathb$ = MID$(stringmathb$, 2)
  201.         exponentvalue&& = exponentvalue&& - 1
  202.     LOOP
  203.     esign$ = "-"
  204.     esign$ = "+"
  205. DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove trailing zeros.
  206.     stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  207. IF stringmathb$ = "" THEN stringmathb$ = "0": esign$ = "+": exponentvalue&& = 0
  208. stringmathb$ = LEFT$(stringmathb$, 1) + "." + MID$(stringmathb$, 2)
  209. IF stringmathb$ = "0." THEN n2sign$ = "": esign$ = "+"
  210. stringmathb$ = stringmathb$ + "e" + esign$ + LTRIM$(STR$(ABS(exponentvalue&&))) ' S.N formed here.
  211. IF stringmathb$ <> "overflow" THEN
  212.     stringmathb$ = n2sign$ + stringmathb$
  213. n2sign$ = "": esign$ = "": exponentvalue&& = 0
  214.  
  215. scientific_to_numeric:
  216. IF INSTR(UCASE$(stringmathb$), "D") THEN MID$(stringmathb$, INSTR(UCASE$(stringmathb$), "D"), 1) = "e"
  217. IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 2) = "0" THEN ' The numeric value is the number without the zero exponent.
  218.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, "e") - 1)
  219.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  220.     RETURN
  221.     IF LEFT$(stringmathb$, 1) = "-" THEN stn_sign$ = "-": stringmathb$ = MID$(stringmathb$, 2)
  222.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Remove decimal point.
  223.     stn_i& = INSTR(stringmathb$, "e") - 1 ' Length of the numric part.
  224.     IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 1, 1) = "-" THEN
  225.         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.
  226.     ELSE
  227.         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.
  228.         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")
  229.     END IF
  230. IF stringmathb$ = "0" THEN stn_sign$ = ""
  231. stringmathb$ = stn_sign$ + stringmathb$
  232. stn_sign$ = "": stn_point$ = ""
  233.  
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #4 on: March 30, 2019, 05:48:19 pm »
So for sci-num: e (or d) goes right next to digit and only 1 digit must be left of decimal to be valid, correct?

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #5 on: March 30, 2019, 06:14:44 pm »
It tries to convert to a standard, so...

1d5 or 1.d5 or 1.0d5 or 1d+5 or 1.d+5 or 1.0d+5 or even 1.000d5 0r 1.000d+5 would all be automatically converted to: 1.e+5

I use e instead of E, D, or d but you can input any of them, and the routine will (should) adjust it to the standard shown above.

Pete



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

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #6 on: March 31, 2019, 07:13:51 am »
yours choked on a megabyte of digits modified thusly: even on 65536. Mine took .00390625s for a 3-digit separation between commas. Yours takes over 150 times as long.
Code: QB64: [Select]
  1. DEFLNG A-Z
  2. m& = 1048576
  3. stringmathb$ = SPACE$(m&)
  4. FOR i& = 0 TO m& - 1
  5.     MID$(stringmathb$, i& + 1, 1) = CHR$(ASC("0") + RND * (ASC("9") - ASC("0")) AND 255)
  6. GOSUB validate_string_number
  7. PRINT "Validated: "; stringmathb$
  8. IF stringmathb$ = "invalid number" THEN RUN
  9.     PRINT
  10.     IF INSTR(stringmathb$, ",") = 0 THEN PRINT "1) Add Commas": x$ = x$ + "1"
  11.     IF INSTR(stringmathb$, ",") THEN PRINT "2) Remove Commas": x$ = x$ + "2"
  12.     IF INSTR(stringmathb$, "$") = 0 THEN PRINT "3) Convert to Dollars and Cents": x$ = x$ + "3"
  13.     IF INSTR(stringmathb$, "$") THEN PRINT "4) Convert to Numeric": x$ = x$ + "4"
  14.     IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN
  15.         PRINT "5) Convert to Numeric": x$ = x$ + "5"
  16.     ELSE
  17.         PRINT "6) Convert to S.N.": x$ = x$ + "6"
  18.     END IF
  19.     PRINT "7) New number": x$ = x$ + "7"
  20.     PRINT
  21.     DO
  22.         _LIMIT 10
  23.         k$ = INKEY$
  24.         IF k$ = CHR$(27) THEN SYSTEM
  25.         IF LEN(k$) AND INSTR(x$, k$) <> 0 THEN
  26.             SELECT CASE k$
  27.                 CASE "1"
  28.                     s! = TIMER(.001)
  29.                     GOSUB comma_placement
  30.                     CLS
  31.                     f! = TIMER(.001)
  32.                     PRINT f! - s!
  33.                     _DELAY 1
  34.                 CASE "2"
  35.                     GOSUB comma_removal
  36.                 CASE "3"
  37.                     GOSUB currency_convert
  38.                 CASE "4"
  39.                     GOSUB validate_string_number
  40.                 CASE "5"
  41.                     IF INSTR(stringmathb$, "$") THEN GOSUB validate_string_number
  42.                     GOSUB scientific_to_numeric
  43.                 CASE "6"
  44.                     IF INSTR(stringmathb$, "$") THEN GOSUB validate_string_number
  45.                     GOSUB numeric_to_scientific
  46.                 CASE "7"
  47.                     RUN
  48.             END SELECT
  49.             PRINT stringmathb$
  50.             x$ = ""
  51.             IF stringmathb$ = "invalid number" THEN RUN
  52.             EXIT DO
  53.         END IF
  54.     LOOP
  55.  
  56. validate_string_number:
  57. vsn_negcnt& = 0: vsn_poscnt& = 0: vsn_depresent& = 0: decimalcnt& = 0: vsn_numberpresent& = 0: vsn_zerospresent& = 0
  58. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-" ELSE sm_sign$ = ""
  59. IF LEFT$(stringmathb$, 1) = "+" THEN IF sm_sign$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 2) ELSE stringmathb$ = "invalid number": RETURN
  60. IF INSTR(UCASE$(stringmathb$), "D") OR INSTR(UCASE$(stringmathb$), "E") THEN ' Evaluate for Scientific Notation.
  61.     FOR sm_i& = 1 TO LEN(stringmathb$)
  62.         validatenum$ = MID$(UCASE$(stringmathb$), sm_i&, 1)
  63.         SELECT CASE validatenum$
  64.             CASE "+"
  65.                 IF vsn_depresent& THEN vsn_poscnt& = vsn_poscnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  66.             CASE "-"
  67.                 IF vsn_depresent& THEN vsn_negcnt& = vsn_negcnt& + 1 ELSE stringmathb$ = "invalid number": RETURN
  68.             CASE "0" TO "9"
  69.                 vsn_numberpresent& = -1
  70.             CASE "D", "E"
  71.                 vsn_depresent& = vsn_depresent& + 1
  72.                 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
  73.                 vsn_numberpresent& = 0
  74.                 MID$(stringmathb$, sm_i&, 1) = "e" ' Standardize
  75.             CASE "."
  76.                 decimalcnt& = decimalcnt& + 1
  77.                 IF sm_i& <> 2 THEN vsn_numberpresent& = 0: EXIT FOR
  78.             CASE ELSE
  79.                 vsn_numberpresent& = 0: EXIT FOR
  80.         END SELECT
  81.     NEXT
  82.     IF decimalcnt& = 0 THEN stringmathb$ = MID$(stringmathb$, 1, 1) + "." + MID$(stringmathb$, 2) ' Standardize "."
  83.     IF vsn_numberpresent& = 0 OR vsn_negcnt& = 1 AND vsn_poscnt& = 1 OR decimalcnt& > 1 OR INSTR(stringmathb$, ".") <> 2 THEN stringmathb$ = "invalid number": RETURN
  84.     vsn_depresent& = INSTR(stringmathb$, "e")
  85.     sm_x$ = MID$(stringmathb$, vsn_depresent& + 1, 1) ' Standardize exponent "+" these two lines.
  86.     IF sm_x$ <> "+" AND sm_x$ <> "-" THEN stringmathb$ = MID$(stringmathb$, 1, vsn_depresent&) + "+" + MID$(stringmathb$, vsn_depresent& + 1)
  87.     IF MID$(stringmathb$, vsn_depresent& + 2, 1) = "0" THEN
  88.         IF MID$(stringmathb$, vsn_depresent& + 3, 1) <> "" THEN stringmathb$ = "invalid number": RETURN ' No leading zeros allowed in exponent notation.
  89.     END IF
  90.     jjed& = INSTR(stringmathb$, "e") ' Get position of notation.
  91.     valexpside$ = MID$(stringmathb$, jjed&) ' These two lines break up into number and notation
  92.     stringmathb$ = MID$(stringmathb$, 1, jjed& - 1) ' stringmathb$ is +- single digit whole number, decimal point and decimal number. valexpside$ is notation, sign and exponent.
  93.     DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove any trailing zeros for number. Example 1.0d3 or 1.0000d3, etc.
  94.         stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  95.     LOOP
  96.     IF VAL(MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1)) = 0 THEN
  97.         IF RIGHT$(stringmathb$, 1) = "." THEN
  98.             stringmathb$ = "0.e+0" ' Handles all types of zero entries.
  99.         ELSE
  100.             stringmathb$ = "invalid number": RETURN
  101.         END IF
  102.         RETURN
  103.     END IF
  104.     stringmathb$ = sm_sign$ + stringmathb$ + valexpside$
  105.     RETURN
  106.     FOR sm_i& = 1 TO LEN(stringmathb$)
  107.         validatenum$ = MID$(stringmathb$, sm_i&, 1)
  108.         SELECT CASE validatenum$
  109.             CASE "."
  110.                 decimalcnt& = decimalcnt& + 1
  111.             CASE "0"
  112.                 vsn_zerospresent& = -1
  113.             CASE "1" TO "9"
  114.                 vsn_numberpresent& = -1
  115.             CASE "$"
  116.             CASE ELSE
  117.                 stringmathb$ = "invalid number": RETURN
  118.         END SELECT
  119.     NEXT
  120.     IF decimalcnt& > 1 OR vsn_negcnt& > 1 OR vsn_poscnt& > 1 OR vsn_negcnt& >= 1 AND vsn_poscnt& >= 1 THEN
  121.         stringmathb$ = "invalid number": RETURN
  122.     END IF
  123.     IF INSTR(stringmathb$, "$") THEN GOSUB currency_validate
  124.     IF INSTR(stringmathb$, ",") THEN
  125.         GOSUB comma_validation
  126.         IF stringmathb$ = "invalid number" THEN RETURN
  127.         GOSUB comma_removal
  128.     END IF
  129.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  130.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Strip off any leading zeros.
  131.         stringmathb$ = MID$(stringmathb$, 2)
  132.     LOOP
  133.     stringmathb$ = sm_sign$ + stringmathb$
  134.     IF INSTR(stringmathb$, ".") THEN
  135.         DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Strip off any trailing zeros in a decimal.
  136.             stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  137.         LOOP
  138.     END IF
  139.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  140.     IF vsn_numberpresent& = 0 THEN
  141.         IF vsn_zerospresent& THEN
  142.             stringmathb$ = "0"
  143.         ELSE
  144.             stringmathb$ = "invalid number"
  145.         END IF
  146.     END IF
  147.  
  148. ' Add in commas.
  149. comma_placement:
  150. GOSUB comma_prep
  151. FOR sm_i& = LEN(temp_stringmathb1$) TO 1 STEP -1
  152.     sm_j% = sm_j% + 1
  153.     IF sm_j% = 4 THEN stringmathb$ = "," + stringmathb$: sm_j% = 1
  154.     stringmathb$ = MID$(temp_stringmathb1$, sm_i&, 1) + stringmathb$
  155. stringmathb$ = sm_sign$ + stringmathb$ + temp_stringmathb2$
  156. temp_stringmathb1$ = "": temp_stringmathb2$ = "": sm_i& = 0: sm_j% = 0
  157.  
  158. ' Validate comma entry.
  159. comma_validation:
  160. GOSUB comma_prep
  161. IF INSTR(temp_stringmathb2$, ",") <> 0 OR temp_stringmathb1$ = STRING$(LEN(temp_stringmathb1$), ",") THEN
  162.     stringmathb$ = "invalid number" ' Decimal part has comma or entry is all commas.
  163.     FOR sm_i& = LEN(temp_stringmathb1$) TO 1 STEP -1
  164.         sm_j% = sm_j% + 1
  165.         IF sm_j% = 4 THEN
  166.             IF MID$(temp_stringmathb1$, sm_i&, 1) <> "," THEN stringmathb$ = "invalid number": EXIT FOR
  167.             sm_j% = 0
  168.         END IF
  169.     NEXT
  170.     IF stringmathb$ <> "invalid number" THEN
  171.         stringmathb$ = sm_sign$ + temp_stringmathb1$ + temp_stringmathb2$
  172.     END IF
  173. temp_stringmathb1$ = "": temp_stringmathb2$ = "": sm_i& = 0: sm_j% = 0: sm_sign$ = "": sm_dollar$ = ""
  174.  
  175. comma_removal:
  176. DO UNTIL INSTR(stringmathb$, ",") = 0
  177.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ",") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ",") + 1)
  178.  
  179. comma_prep:
  180. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): sm_sign$ = "-"
  181. temp_stringmathb1$ = stringmathb$: stringmathb$ = ""
  182. IF INSTR(temp_stringmathb1$, ".") THEN
  183.     temp_stringmathb2$ = MID$(temp_stringmathb1$, INSTR(temp_stringmathb1$, ".")) ' Decimal part
  184.     temp_stringmathb1$ = MID$(temp_stringmathb1$, 1, INSTR(temp_stringmathb1$, ".") - 1) ' Non-decimal part
  185. IF LEFT$(temp_stringmathb1$, 1) = "$" THEN temp_stringmathb1$ = MID$(temp_stringmathb1$, 2): sm_dollar$ = "$"
  186.  
  187. currency_validate:
  188. IF LEFT$(stringmathb$, 2) = "$-" OR LEFT$(stringmathb$, 2) = "$+" THEN stringmathb$ = "invalid number": RETURN
  189. IF LEFT$(stringmathb$, 1) = "$" THEN stringmathb$ = MID$(stringmathb$, 2)
  190. IF INSTR(stringmathb$, "$") THEN stringmathb$ = "invalid number": RETURN
  191. sm_dollar$ = "$"
  192.  
  193. currency_convert:
  194. IF INSTR(UCASE$(stringmathb$), "D") <> 0 OR INSTR(UCASE$(stringmathb$), "E") <> 0 THEN GOSUB scientific_to_numeric
  195. IF INSTR(stringmathb$, ",") = 0 THEN GOSUB comma_placement
  196. IF INSTR(stringmathb$, ".") = 0 THEN stringmathb$ = stringmathb$ + ".00"
  197. IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = stringmathb$ + "00"
  198. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = stringmathb$ + "0"
  199. IF MID$(stringmathb$, LEN(stringmathb$) - 2, 1) <> "." THEN stringmathb$ = "invalid number": RETURN
  200. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
  201. stringmathb$ = sm_sign$ + "$" + stringmathb$
  202.  
  203. numeric_to_scientific:
  204. IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2): n2sign$ = "-"
  205. 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.
  206. stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1)
  207. IF LEFT$(stringmathb$, 1) = "0" AND LEN(stringmathb$) > 1 OR exponentvalue&& = -1 THEN
  208.     DO UNTIL LEFT$(stringmathb$, 1) <> "0" ' Remove leading zeros to consider rounding.
  209.         stringmathb$ = MID$(stringmathb$, 2)
  210.         exponentvalue&& = exponentvalue&& - 1
  211.     LOOP
  212.     esign$ = "-"
  213.     esign$ = "+"
  214. DO UNTIL RIGHT$(stringmathb$, 1) <> "0" ' Remove trailing zeros.
  215.     stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  216. IF stringmathb$ = "" THEN stringmathb$ = "0": esign$ = "+": exponentvalue&& = 0
  217. stringmathb$ = LEFT$(stringmathb$, 1) + "." + MID$(stringmathb$, 2)
  218. IF stringmathb$ = "0." THEN n2sign$ = "": esign$ = "+"
  219. stringmathb$ = stringmathb$ + "e" + esign$ + LTRIM$(STR$(ABS(exponentvalue&&))) ' S.N formed here.
  220. IF stringmathb$ <> "overflow" THEN
  221.     stringmathb$ = n2sign$ + stringmathb$
  222. n2sign$ = "": esign$ = "": exponentvalue&& = 0
  223.  
  224. scientific_to_numeric:
  225. IF INSTR(UCASE$(stringmathb$), "D") THEN MID$(stringmathb$, INSTR(UCASE$(stringmathb$), "D"), 1) = "e"
  226. IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 2) = "0" THEN ' The numeric value is the number without the zero exponent.
  227.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, "e") - 1)
  228.     IF RIGHT$(stringmathb$, 1) = "." THEN stringmathb$ = MID$(stringmathb$, 1, LEN(stringmathb$) - 1)
  229.     RETURN
  230.     IF LEFT$(stringmathb$, 1) = "-" THEN stn_sign$ = "-": stringmathb$ = MID$(stringmathb$, 2)
  231.     stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Remove decimal point.
  232.     stn_i& = INSTR(stringmathb$, "e") - 1 ' Length of the numric part.
  233.     IF MID$(stringmathb$, INSTR(stringmathb$, "e") + 1, 1) = "-" THEN
  234.         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.
  235.     ELSE
  236.         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.
  237.         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")
  238.     END IF
  239. IF stringmathb$ = "0" THEN stn_sign$ = ""
  240. stringmathb$ = stn_sign$ + stringmathb$
  241. stn_sign$ = "": stn_point$ = ""
  242.  
« Last Edit: March 31, 2019, 08:24:22 am by codeguy »

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #7 on: March 31, 2019, 07:25:22 am »
corrected setting m$ to null.
Please try my code for inserting commas. It is designed to insert commas after variable numbers of characters. it can also be used to save fixed-length strings to CSV (comma-separated values).
Code: QB64: [Select]
  1. g& = 1048576
  2. FOR csep& = 1 TO 3
  3.     FOR I& = g& TO g& + 9
  4.         m$ = SPACE$(g&)
  5.         L& = I&
  6.         s! = TIMER(.001)
  7.         DO UNTIL L& < 1
  8.             MID$(m$, L&, 1) = CHR$((ASC("0") + RND * (ASC("9") - ASC("0"))) AND 255)
  9.             L& = L& - 1
  10.         LOOP
  11.         f! = TIMER(.001)
  12.         start! = TIMER(.001)
  13.         x$ = CommaPad$(m$, csep&)
  14.         finish! = TIMER(.001)
  15.         PRINT x$; " took "; finish! - start!; "seconds LENGTH ="; I&; f! - s!; "to generate."
  16.     NEXT
  17.  
  18. FUNCTION CommaPad$ (f$, every&)
  19.     r& = LEN(f$)
  20.     IF r& > every& THEN
  21.         q& = r& MOD every&
  22.         IF q& > 0 THEN
  23.             n& = (r& - q&) / every& + 1
  24.             b$ = SPACE$(q& + n& * (every& + 1))
  25.             WHILE n& >= 0
  26.                 MID$(b$, q& + n& * ((every& + 1)) + 1) = ","
  27.                 MID$(b$, q& + n& * ((every& + 1)) + 1 + 1, every&) = MID$(f$, q& + n& * every& + 1, every&)
  28.                 n& = n& - 1
  29.             WEND
  30.             MID$(b$, 1, q&) = LEFT$(f$, q&)
  31.             CommaPad$ = LEFT$(b$, LEN(b$) - (every& + 1))
  32.         ELSE
  33.             n& = r& / every&
  34.             b$ = SPACE$(n& * (every& + 1))
  35.             WHILE n& >= 0
  36.                 MID$(b$, n& * ((every& + 1)) + 1) = ","
  37.                 MID$(b$, n& * ((every& + 1)) + 1 + 1, every&) = MID$(f$, n& * every& + 1, every&)
  38.                 n& = n& - 1
  39.             WEND
  40.             CommaPad$ = MID$(b$, 2)
  41.         END IF
  42.         b$ = ""
  43.     ELSE
  44.         CommaPad$ = f$
  45.     END IF
  46.  
« Last Edit: March 31, 2019, 08:50:14 am by codeguy »

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #8 on: March 31, 2019, 12:08:46 pm »
Again Pete, really had a lot of fun with some practical numbers and so far so good. I did have a moment there where I was using some stock prices and had to scratch my head when I got an "invalid number" response. In the stock market you can come up with some prices which are expressed in multiple digits to the right of the decimal. For example, Fidelity US Monthly Income Fund was priced at $18.6037 this past Friday - When I entered this dollar amount as the "number", I did not get the menu but an immediate "Valid Number of 18.6037" - seems it refused to take this as a valid dollar and cents figure. Then, using 18.6037 as a valid number, I did get the menu but again , choosing dollar and cents, it would not accept the number as a valid dollar and cents. This is not a real big deal. The vast majority of commerce and trade only has two digits to the right of the decimal.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #9 on: March 31, 2019, 04:26:04 pm »
Thanks Dimster. I didn't think about including stock prices. A lot of calculators has 2-digit and 4-digit options. That's something I may consider.

@Codeguy: Hey, you're young, you can wait, but I've got to figure out a faster way to add commas. It appears that string replacement is much faster than string concatenation. I'll have to fool with that a bit, but I wanted to get the working components down and tested before I get into optimization and capacity. That LEN() limit is a bummer, but there are ways to save parts in arrays and get around that.

By bombing out, did you mean it wouldn't remove the commas? It took so long, I had to presume it couldn't process that large of a string. Instead of debugging it, as it may be a size limitation and it's bleeping slow, I decided to try a string replacement with INSTR().

Code: QB64: [Select]
  1. m& = 1048576 * 1.25 - 1
  2. stringmathb$ = SPACE$(m&)
  3. FOR i& = 1 TO m&
  4.     j& = j& + 1
  5.     MID$(stringmathb$, i&, 1) = CHR$(ASC("0") + RND * (ASC("9") - ASC("0")) AND 255)
  6.     IF j& MOD 3 = 0 AND i& < m& - 2 THEN i& = i& + 1: MID$(stringmathb$, i&, 1) = ","
  7. PRINT stringmathb$, LEN(stringmathb$), "Press a key to remove commas...": SLEEP
  8.  
  9. b$ = SPACE$(LEN(stringmathb$)): j& = 0
  10.     i& = INSTR(seed& + 1, stringmathb$, ",")
  11.     IF i& = 0 THEN EXIT DO
  12.     MID$(b$, j& + 1, i& - seed& + 1) = MID$(stringmathb$, seed& + 1, i& - seed& - 1)
  13.     j& = j& + i& - seed& - 1
  14.     seed& = i&
  15. stringmathb$ = RTRIM$(b$) + MID$(stringmathb$, seed& + 1): b$ = ""
  16. PRINT stringmathb$, LEN(stringmathb$): END

That's bleeping fast! Thank you for your post, which lead me to surmise QB handles string replacement infinitely faster than string concatenation. That's probably the case for all languages.

OK, I put together a way to add commas, too. This routine will take the 1M+ digits Codeguy provided and add commas, prompt, and remove commas. It's very fast, now!

Code: QB64: [Select]
  1. m& = 1048576
  2. stringmathb$ = SPACE$(m&)
  3. FOR i& = 0 TO m& - 1
  4.     MID$(stringmathb$, i& + 1, 1) = CHR$(ASC("0") + RND * (ASC("9") - ASC("0")) AND 255)
  5.     LINE INPUT "Press Enter to add commas..."; null$
  6.     ' Add commas
  7.     i& = 0: j& = 0: seed& = 0
  8.     seed& = LEN(stringmathb$) MOD 3: IF seed& = 0 THEN seed& = 3
  9.     m1& = LEN(stringmathb$)
  10.     m2& = (LEN(stringmathb$) - 1) \ 3
  11.     c$ = SPACE$(m1& + m2&)
  12.     DO WHILE i& < m1&
  13.         MID$(c$, j& + 1, seed& + 1) = MID$(stringmathb$, i& + 1, seed&) + ","
  14.         i& = i& + seed&: j& = j& + seed& + 1: seed& = 3
  15.     LOOP
  16.     c$ = RTRIM$(c$)
  17.     IF RIGHT$(c$, 1) = "," THEN stringmathb$ = MID$(c$, 1, LEN(c$) - 1) ELSE stringmathb$ = c$
  18.     c$ = ""
  19.     PRINT stringmathb$
  20.     PRINT "Length of string ="; LEN(stringmathb$)
  21.     LINE INPUT "Press Enter to remove commas..."; null$
  22.     ' Remove commas
  23.     i& = 0: j& = 0: seed& = 0
  24.     b$ = SPACE$(LEN(stringmathb$)): j& = 0
  25.     DO
  26.         i& = INSTR(seed& + 1, stringmathb$, ",")
  27.         IF i& = 0 THEN EXIT DO
  28.         MID$(b$, j& + 1, i& - seed& + 1) = MID$(stringmathb$, seed& + 1, i& - seed& - 1)
  29.         j& = j& + i& - seed& - 1
  30.         seed& = i&
  31.     LOOP
  32.     stringmathb$ = RTRIM$(b$) + MID$(stringmathb$, seed& + 1): b$ = ""
  33.     PRINT stringmathb$
  34.     PRINT "Length of string ="; LEN(stringmathb$)
  35.  



Pete
« Last Edit: March 31, 2019, 06:51:28 pm by Pete »
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #10 on: March 31, 2019, 08:19:10 pm »
By bombing out, I mean your comma insertion code ran REALLY slowly as compared to my little comma insertion function. Yes, the string concatenation overhead is terrible, but not unexpected when you discover what goes on under the hood for string concatenation. Mine takes 60s for a 16,777,216 character string (doesn't necessarily have to be numbers) on a mobile core i7. A more modest test of 1 MB takes about 70 milliseconds.
Code: QB64: [Select]
  1. g& = 1048576 * 16
  2. FOR csep& = 1 TO 3
  3.     FOR I& = g& TO g& + 0
  4.         m$ = SPACE$(g&)
  5.         L& = I&
  6.         s! = TIMER(.001)
  7.         DO UNTIL L& < 1
  8.             MID$(m$, L&, 1) = CHR$(ASC("0") + (RND * (ASC("9") - ASC("0"))) AND 255)
  9.             L& = L& - 1
  10.         LOOP
  11.         f! = TIMER(.001)
  12.         start! = TIMER(.001)
  13.         x$ = CommaPad$(m$, csep&)
  14.         finish! = TIMER(.001)
  15.         PRINT x$
  16.         PRINT "took "; finish! - start!; "seconds LENGTH ="; I&; f! - s!; "to generate."
  17.     NEXT
  18.  
  19. FUNCTION CommaPad$ (f$, every&)
  20.     r& = LEN(f$)
  21.     IF r& > every& THEN
  22.         q& = r& MOD every&
  23.         IF q& > 0 THEN
  24.             n& = (r& - q&) / every& + 1
  25.             b$ = SPACE$(q& + n& * (every& + 1))
  26.             WHILE n& >= 0
  27.                 MID$(b$, q& + n& * ((every& + 1)) + 1) = ","
  28.                 MID$(b$, q& + n& * ((every& + 1)) + 1 + 1, every&) = MID$(f$, q& + n& * every& + 1, every&)
  29.                 n& = n& - 1
  30.             WEND
  31.             MID$(b$, 1, q&) = LEFT$(f$, q&)
  32.             CommaPad$ = LEFT$(b$, LEN(b$) - (every& + 1))
  33.         ELSE
  34.             n& = r& / every&
  35.             b$ = SPACE$(n& * (every& + 1))
  36.             WHILE n& >= 0
  37.                 MID$(b$, n& * ((every& + 1)) + 1) = ","
  38.                 MID$(b$, n& * ((every& + 1)) + 1 + 1, every&) = MID$(f$, n& * every& + 1, every&)
  39.                 n& = n& - 1
  40.             WEND
  41.             CommaPad$ = MID$(b$, 2)
  42.         END IF
  43.         b$ = ""
  44.     ELSE
  45.         CommaPad$ = f$
  46.     END IF
  47.  

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Working on a comma system for string math routine...
« Reply #11 on: April 01, 2019, 03:31:40 am »
Here is another version, quite fast too at 16 Megabyte string size, performs in just a shade under 4s on a single thread on a mobile core i7. about 34ms on 1 one megabyte input.
Code: QB64: [Select]
  1. Long_NumberOfCharacters& = 33 '555434
  2. Str_StrInput$ = SPACE$(Long_NumberOfCharacters&): FillNumber Str_StrInput$, 1, Long_NumberOfCharacters&: PRINT Str_StrInput$
  3. Long_DigitsPerComma = 3
  4. Long_StrLenModNOC = Long_NumberOfCharacters& MOD Long_DigitsPerComma
  5. Long_NumberOfCommas& = (Long_NumberOfCharacters& - Long_StrLenModNOC) / Long_DigitsPerComma
  6. Str_StringPosition& = Long_NumberOfCharacters&
  7. Long_OutputStrPos& = Long_NumberOfCharacters& + Long_NumberOfCommas&
  8. Str_StrInput$ = Str_StrInput$ + SPACE$(Long_NumberOfCommas&)
  9. s! = TIMER(.001)
  10.     Long_OutputStrPos& = Long_OutputStrPos& - Long_DigitsPerComma
  11.     Str_StringPosition& = Str_StringPosition& - Long_DigitsPerComma
  12.     MID$(Str_StrInput$, Long_OutputStrPos& + 1, Long_DigitsPerComma) = MID$(Str_StrInput$, Str_StringPosition& + 1, Long_DigitsPerComma)
  13.     MID$(Str_StrInput$, Long_OutputStrPos&, 1) = ","
  14.     Long_OutputStrPos& = Long_OutputStrPos& - 1
  15. LOOP UNTIL Long_OutputStrPos& < 1
  16. f! = TIMER(.001)
  17. IF LEFT$(Str_StrInput$, 1) = "," THEN
  18.     Str_StrInput$ = MID$(Str_StrInput$, 2)
  19. PRINT Str_StrInput$ + "\"; f! - s!
  20.  
  21. SUB FillNumber (Str_StrInput$, start&, finish&)
  22.     asc0% = ASC("0")
  23.     asc9% = ASC("9")
  24.     FOR cpos& = start& TO finish&
  25.         MID$(Str_StrInput$, cpos&, 1) = CHR$(asc0% + INT(RND * (asc9% - asc0%)))
  26.     NEXT
  27.  

and here is a demo I made decidedly shorter and incorporating a SUB to do the work:
Code: QB64: [Select]
  1. '* Converting a stream of input to comma-delimited output
  2. '* This is a common task when displaying information in more convenient human-readable form
  3.  
  4. '* Test variables, not necessary for the function
  5. Long_NumberOfCharacters& = 100
  6. Str_StrInput$ = SPACE$(Long_NumberOfCharacters&)
  7. FillNumber Str_StrInput$, 1, Long_NumberOfCharacters&: PRINT Str_StrInput$
  8.  
  9. '* these are definitely necessary
  10. Long_DigitsPerComma& = 3
  11. s! = TIMER(.001)
  12. AddCommas Str_StrInput$, Long_DigitsPerComma&
  13. f! = TIMER(.001)
  14. PRINT Str_StrInput$ + "\"; f! - s!
  15.  
  16. SUB FillNumber (Str_StrInput$, start&, finish&)
  17.     asc0% = ASC("0")
  18.     asc9% = ASC("9")
  19.     FOR cpos& = start& TO finish&
  20.         MID$(Str_StrInput$, cpos&, 1) = CHR$(asc0% + INT(RND * (asc9% - asc0%)))
  21.     NEXT
  22.  
  23. SUB AddCommas (Str_StrInput$, Long_DigitsPerComma&)
  24.     Long_NumberOfCharacters& = LEN(Str_StrInput$)
  25.     Long_StrLenModNOC& = Long_NumberOfCharacters& MOD Long_DigitsPerComma&
  26.     Long_NumberOfCommas& = (Long_NumberOfCharacters& - Long_StrLenModNOC&) / Long_DigitsPerComma&
  27.     Str_StringPosition& = Long_NumberOfCharacters&
  28.     Long_OutputStrPos& = Long_NumberOfCharacters& + Long_NumberOfCommas&
  29.     Str_StrInput$ = Str_StrInput$ + SPACE$(Long_NumberOfCommas&)
  30.     DO
  31.         Long_OutputStrPos& = Long_OutputStrPos& - Long_DigitsPerComma&
  32.         Str_StringPosition& = Str_StringPosition& - Long_DigitsPerComma&
  33.         MID$(Str_StrInput$, Long_OutputStrPos& + 1, Long_DigitsPerComma&) = MID$(Str_StrInput$, Str_StringPosition& + 1, Long_DigitsPerComma&)
  34.         MID$(Str_StrInput$, Long_OutputStrPos&, 1) = ","
  35.         Long_OutputStrPos& = Long_OutputStrPos& - 1
  36.     LOOP UNTIL Long_OutputStrPos& < 1
  37.     IF LEFT$(Str_StrInput$, 1) = "," THEN
  38.         Str_StrInput$ = MID$(Str_StrInput$, 2)
  39.     END IF
  40.  
« Last Edit: April 01, 2019, 05:34:55 am by codeguy »