Faster addition in string math. Now with multiplication!
#15
@SMcNeill

Glad you found it.

I added (excuse the pun) a chunk multiple routine. It may be buggy, as I haven't tested it all that well. I had to vary a bit from the structure I used for addition/subtraction, but not too much. I might go back and tweak the two a bit latter. Anyway, these changes are proving to be a faster model than my old string routines from a few years ago.

The Holly grail would be a way to do chunk division, but that's one hell of a rabbit hole to go down.

Here's the updated code for +, - , and now *

Code: (Select All)
betatest% = 0
DIM AS _INTEGER64 a, b, c, aa, bb, cc, s, ss
WIDTH 160, 42
_SCREENMOVE 0, 0

DO
    LINE INPUT "Number: "; a$
    IF a$ = "" THEN EXIT DO ' Quit.
    LINE INPUT "+ - * : "; op$
    LINE INPUT "Number: "; b$

    a1$ = a$: b1$ = b$

    SELECT CASE op$
        CASE "*"
            z$ = "": sign$ = "": mult&& = 0: h&& = 0: i&& = 0: j&& = 0: c = 0: decimal% = 0
            zz$ = "": ii&& = 0: jj&& = 0
            s = 8: ss = 18

            IF INSTR(a$, "-") <> 0 OR INSTR(b$, "-") <> 0 THEN
                IF INSTR(a$, "-") <> 0 AND INSTR(b$, "-") <> 0 THEN
                    a$ = MID$(a$, 2): b$ = MID$(b$, 2)
                ELSE
                    IF INSTR(a$, "-") <> 0 THEN a$ = MID$(a$, 2) ELSE b$ = MID$(b$, 2)
                    sign$ = "-"
                END IF
            END IF

            IF INSTR(a$, ".") <> 0 OR INSTR(b$, ".") <> 0 THEN
                decimal% = -1
                IF INSTR(a$, ".") <> 0 THEN
                    dec_a&& = LEN(MID$(a$, INSTR(a$, ".") + 1))
                    a$ = MID$(a$, 1, INSTR(a$, ".") - 1) + MID$(a$, INSTR(a$, ".") + 1)
                END IF
                IF INSTR(b$, ".") <> 0 THEN
                    dec_b&& = LEN(MID$(b$, INSTR(b$, ".") + 1))
                    b$ = MID$(b$, 1, INSTR(b$, ".") - 1) + MID$(b$, INSTR(b$, ".") + 1)
                END IF
            END IF

            IF LEN(a$) < LEN(b$) THEN SWAP a$, b$

            DO
                h&& = h&& + s: i&& = 0
                x2$ = MID$(b$, LEN(b$) - h&& + 1, s)
                WHILE -1
                    i&& = i&& + s
                    x1$ = MID$(a$, LEN(a$) - i&& + 1, s)
                    a = VAL(sign_a$ + x1$) * VAL(sign_b$ + x2$) + c
                    IF betatest% THEN PRINT "x1$ = "; x1$;: LOCATE , 20: PRINT "x2$ = "; x2$;: LOCATE , 35: PRINT VAL(x1$) * VAL(x2$) + c;: LOCATE , 55: PRINT "c = "; c;: LOCATE , 75: PRINT "val = "; a,
                    c = 0
                    tmp$ = LTRIM$(STR$(a))
                    IF LEN(tmp$) > s THEN c = VAL(MID$(tmp$, 1, LEN(tmp$) - s)): tmp$ = MID$(tmp$, LEN(tmp$) - s + 1)
                    z$ = tmp$ + z$
                    IF betatest% THEN LOCATE , 100: PRINT a;: LOCATE , 120: PRINT z$
                    IF i&& >= LEN(a$) AND c = 0 THEN EXIT WHILE
                WEND

                jj&& = jj&& + 1

                IF jj&& > 1 THEN
                    ii&& = 0: cc = 0
                    aa$ = holdaa$
                    bb$ = z$ + STRING$((jj&& - 1) * s, "0")
                    IF betatest% THEN PRINT "aa$ "; aa$; " + bb$ "; z$;: COLOR 14, 0: PRINT STRING$(jj&& - 1, "0"); " = ";: COLOR 7, 0: SLEEP
                    DO
                        ii&& = ii&& + ss
                        xx1$ = MID$(aa$, LEN(aa$) - ii&& + 1, ss)
                        xx2$ = MID$(bb$, LEN(bb$) - ii&& + 1, ss)
                        aa = VAL(xx1$) + VAL(xx2$) + cc
                        IF xx1$ + xx2$ = "" AND cc = 0 THEN EXIT DO ' Prevents leading zeros.
                        cc = 0
                        IF aa > VAL(STRING$(ss, "9")) THEN aa = aa - 10 ^ ss: cc = 1
                        tmp$ = LTRIM$(STR$(aa))
                        zz$ = STRING$(ss - LEN(tmp$), "0") + tmp$ + zz$
                        REM PRINT xx1$;: LOCATE , 15: PRINT xx2$;: LOCATE , 30: PRINT VAL(xx1$) + VAL(xx2$);: LOCATE , 45: PRINT cc;: LOCATE , 60: PRINT aa, "z$ = "; zz$: SLEEP
                    LOOP

                    DO WHILE LEFT$(zz$, 1) = "0"
                        IF LEFT$(zz$, 1) = "0" THEN zz$ = MID$(zz$, 2)
                    LOOP
                    IF zz$ = "" THEN zz$ = "0"

                    holdaa$ = zz$
                    IF betatest% THEN COLOR 2, 0: PRINT holdaa$: COLOR 7, 0
                ELSE
                    holdaa$ = z$ + STRING$(jj&& - 1, "0")
                END IF

                z$ = "": zz$ = ""
            LOOP UNTIL h&& >= LEN(b$)

            z$ = holdaa$

            IF decimal% THEN
                DO UNTIL LEN(z$) >= dec_a&& + dec_b&&
                    z$ = "0" + z$
                LOOP

                z$ = MID$(z$, 0, LEN(z$) - (dec_a&& + dec_b&& - 1)) + "." + MID$(z$, LEN(z$) - (dec_a&& + dec_b&&) + 1)

                DO UNTIL RIGHT$(z$, 1) <> "0" AND RIGHT$(z$, 1) <> "."
                    z$ = MID$(z$, 1, LEN(z$) - 1)
                LOOP
            END IF

            IF z$ = "" OR z$ = "0" THEN z$ = "0": ELSE z$ = sign$ + z$

            PRINT " " + LTRIM$(STR$(VAL(a1$) * VAL(b1$))), "QB64 VAL()."
            PRINT " "; z$, "String Math."
            PRINT

            decimal% = 0: sign$ = ""

        CASE "+", "-"
            s = 18

            IF op$ = "-" THEN
                IF LEFT$(b$, 1) = "-" THEN b$ = MID$(b$, 2) ELSE b$ = "-" + b$
            END IF

            IF INSTR(a$, ".") <> 0 OR INSTR(b$, ".") <> 0 THEN
                decimal% = -1
                IF INSTR(a$, ".") <> 0 THEN
                    dec_a&& = LEN(MID$(a$, INSTR(a$, ".") + 1))
                    a$ = MID$(a$, 1, INSTR(a$, ".") - 1) + MID$(a$, INSTR(a$, ".") + 1)
                END IF
                IF INSTR(b$, ".") <> 0 THEN
                    dec_b&& = LEN(MID$(b$, INSTR(b$, ".") + 1))
                    b$ = MID$(b$, 1, INSTR(b$, ".") - 1) + MID$(b$, INSTR(b$, ".") + 1)
                END IF
                ' Line up decimal places by inserting trailing zeros.
                IF dec_b&& > dec_a&& THEN
                    j&& = dec_b&&
                    a$ = a$ + STRING$(dec_b&& - dec_a&&, "0")
                ELSE
                    j&& = dec_a&&
                    b$ = b$ + STRING$(dec_a&& - dec_b&&, "0")
                END IF
            END IF

            IF LEFT$(a$, 1) = "-" OR LEFT$(b$, 1) = "-" THEN
                IF LEFT$(a$, 1) = "-" AND LEFT$(b$, 1) = "-" THEN
                    sign$ = "--": a$ = MID$(a$, 2): b$ = MID$(b$, 2)
                ELSE
                    IF LEFT$(a$, 1) = "-" THEN a$ = MID$(a$, 2): sign_a$ = "-"
                    IF LEFT$(b$, 1) = "-" THEN b$ = MID$(b$, 2): sign_b$ = "-"

                    string_compare LTRIM$(STR$(ABS(VAL(a1$)))), LTRIM$(STR$(ABS(VAL(b1$)))), gl%

                    IF gl% < 0 THEN
                        IF LEN(sign_b$) THEN sign$ = "-": SWAP a$, b$
                    ELSE
                        IF LEN(sign_a$) THEN sign$ = "-": SWAP sign_a$, sign_b$
                    END IF
                END IF
            END IF

            z$ = ""
            DO
                i&& = i&& + s
                x1$ = MID$(a$, LEN(a$) - i&& + 1, s)
                x2$ = MID$(b$, LEN(b$) - i&& + 1, s)
                a = VAL(sign_a$ + x1$) + VAL(sign_b$ + x2$) + c
                IF x1$ + x2$ = "" AND c = 0 THEN EXIT DO ' Prevents leading zeros.
                c = 0
                IF a > VAL(STRING$(s, "9")) THEN a = a - 10 ^ s: c = 1
                IF a < 0 THEN a = a + 10 ^ s: c = -1
                z$ = LTRIM$(STR$(a)) + z$
                REM PRINT x1$;: LOCATE , 15: PRINT x2$;: LOCATE , 30: PRINT VAL(x1$) - VAL(x2$);: LOCATE , 45: PRINT c;: LOCATE , 60: PRINT a, z$: SLEEP
            LOOP

            IF decimal% THEN
                z$ = MID$(z$, 1, LEN(z$) - j&&) + "." + MID$(z$, LEN(z$) - j&& + 1)
            END IF

            ' Remove any leading zeros.
            DO
                IF LEFT$(z$, 1) = "0" THEN z$ = MID$(z$, 2) ELSE EXIT DO
            LOOP

            IF z$ = "" OR z$ = "0" THEN z$ = "0" ELSE z$ = LEFT$(sign$, 1) + z$

            IF op$ = "+" THEN PRINT " " + LTRIM$(STR$(VAL(a1$) + VAL(b1$))), "QB64 VAL()." ELSE PRINT " " + LTRIM$(STR$(VAL(a1$) - VAL(b1$))), "QB64 VAL()."
            PRINT " "; z$, "String Math."
            PRINT
            sign$ = "": sign_a$ = "": sign_b$ = "": i&& = 0: j&& = 0: decimal% = 0: c = 0
    END SELECT
LOOP
SYSTEM

SUB string_compare (compa$, compb$, gl%)
    DO
        REM Remove trailing zeros after a decimal point.
        IF INSTR(compa$, ".") THEN
            DO UNTIL RIGHT$(compa$, 1) <> "0" AND RIGHT$(compa$, 1) <> "." AND RIGHT$(compa$, 1) <> "-"
                compa$ = MID$(compa$, 1, LEN(compa$) - 1)
            LOOP
        END IF
        IF INSTR(compb$, ".") THEN
            DO UNTIL RIGHT$(compb$, 1) <> "0" AND RIGHT$(compb$, 1) <> "." AND RIGHT$(compb$, 1) <> "-"
                compb$ = MID$(compb$, 1, LEN(compb$) - 1)
            LOOP
        END IF

        IF MID$(compa$, 1, 2) = "-0" OR compa$ = "" OR compa$ = "-" THEN compa$ = "0"
        IF MID$(compb$, 1, 2) = "-0" OR compb$ = "" OR compb$ = "-" THEN compb$ = "0"

        ' A - and +
        IF LEFT$(compa$, 1) = "-" THEN j% = -1
        IF LEFT$(compb$, 1) = "-" THEN k% = -1
        IF k% = 0 AND j% THEN gl% = -1: EXIT DO
        IF j% = 0 AND k% THEN gl% = 1: EXIT DO

        ' A decimal and non-decimal.
        j% = INSTR(compa$, ".")
        k% = INSTR(compb$, ".")
        IF j% = 0 AND k% THEN
            IF compa$ = "0" THEN gl% = -1 ELSE gl% = 1
            EXIT DO
        END IF
        IF k% = 0 AND j% THEN
            IF compb$ = "0" THEN gl% = 1 ELSE gl% = -1
            EXIT DO
        END IF

        ' Both decimals.
        IF j% THEN
            IF compa$ > compb$ THEN
                gl% = 1
            ELSEIF compa$ = compb$ THEN gl% = 0
            ELSEIF compa$ < compb$ THEN gl% = -1
            END IF
            EXIT DO
        END IF

        ' Both positive or both negative whole numbers.
        SELECT CASE LEN(compa$)
            CASE IS < LEN(compb$)
                gl% = -1
            CASE IS = LEN(compb$)
                IF compa$ = compb$ THEN
                    gl% = 0
                ELSEIF compa$ > compb$ THEN gl% = 1
                ELSEIF compa$ < compb$ THEN gl% = -1
                END IF
            CASE IS > LEN(compb$)
                gl% = 1
        END SELECT
        EXIT DO
    LOOP
END SUB

Edit fixed one bug by adding the statement: IF LEN(a$) < LEN(b$) THEN SWAP a$, b$

Pete
Reply


Messages In This Thread
RE: Faster addition in string math. - by SMcNeill - 08-18-2022, 08:16 PM
RE: Faster addition in string math. - by Pete - 08-18-2022, 09:15 PM
RE: Faster addition in string math. - by SMcNeill - 08-18-2022, 09:59 PM
RE: Faster addition in string math. - by SMcNeill - 08-18-2022, 10:08 PM
RE: Faster addition in string math. - by SMcNeill - 08-18-2022, 11:46 PM
RE: Faster addition in string math. - by Pete - 08-19-2022, 10:07 AM
RE: Faster addition in string math. - by SMcNeill - 08-19-2022, 11:26 AM
RE: Faster addition in string math. - by Pete - 08-19-2022, 04:44 PM
RE: Faster addition in string math. - by SMcNeill - 08-19-2022, 04:58 PM
RE: Faster addition in string math. - by SMcNeill - 08-19-2022, 05:57 PM
RE: Faster addition in string math. - by Jack - 08-19-2022, 09:54 PM
RE: Faster addition in string math. - by SMcNeill - 08-19-2022, 11:48 PM
RE: Faster addition in string math. - by SMcNeill - 08-20-2022, 03:49 AM
RE: Faster addition in string math. - by Pete - 08-20-2022, 06:16 AM
RE: Faster addition in string math. - by SMcNeill - 08-20-2022, 06:41 AM



Users browsing this thread: 3 Guest(s)