QB64 Phoenix Edition
Compiler setting for accurate math? - Printable Version

+- QB64 Phoenix Edition (https://staging.qb64phoenix.com)
+-- Forum: QB64 Rising (https://staging.qb64phoenix.com/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://staging.qb64phoenix.com/forumdisplay.php?fid=3)
+---- Forum: Help Me! (https://staging.qb64phoenix.com/forumdisplay.php?fid=10)
+---- Thread: Compiler setting for accurate math? (/showthread.php?tid=1209)

Pages: 1 2


RE: Compiler setting for accurate math? - James D Jarvis - 12-01-2022

Easy enough to work around, just really annoying. I had half hoped there was an accurate math setting I wasn't aware of... Sad


RE: Compiler setting for accurate math? - bplus - 12-01-2022

(11-30-2022, 08:42 PM)justsomeguy Wrote: You could try for the same effect.
Code: (Select All)
DIM x AS INTEGER
FOR x = 100 TO 5 STEP -5
  PRINT x / 100
  _DELAY x / 100
NEXT x

@justsomeguy had the workaround in first reply. I had to work my way up to it this morning to see why!

And I saw in another thread a version of this thread subject, Steve offering the same.

FOR loop structure may be the most Basic but not the most efficient.


RE: Compiler setting for accurate math? - Pete - 12-01-2022

@bplus

I figured the problem was the way the numbers were being generated in the loop, I see you came to the same conclusion, but that's what these routines are supposed to try to alleviate. So it finally dawned on me to place some conditions on the loop and run the counting variables DOUBLE. It worked, as tested, to 10,000. Glitches beyond that for my function or Steve's, who knows. This kept me in business back in the early 1990's.

These two rounding functions will now match and complete.
Code: (Select All)
cnt = 100000
DIM AS DOUBLE a, x
a = -.01
FOR x = 1000 TO -0.001 STEP a
    a$ = pete(x): b$ = Round2$(x, -2)
    PRINT cnt, x;: LOCATE , 40: PRINT "Pete = "; a$;: LOCATE , 55: PRINT "Steve = "; b$
    IF LEN(olda$) <> 0 AND ABS(VAL(a$) - VAL(olda$)) <> .01 OR LEN(oldb$) <> 0 AND ABS(VAL(b$) - VAL(oldb$)) <> .01 THEN
        BEEP: DO: WHILE _MOUSEINPUT: WEND: LOOP UNTIL _MOUSEBUTTON(1): _DELAY .1
    END IF
    cnt = cnt - 1
    olda$ = a$
    oldb$ = b$
NEXT

FUNCTION pete$ (x)
    tmp1$ = ".00"
    tmp2$ = LTRIM$(STR$(INT(x * 100 + .5) / 100))
    IF INSTR(tmp2$, ".") THEN
        MID$(tmp1$, 2, LEN(tmp2$)) = MID$(tmp2$, INSTR(tmp2$, ".") + 1)
        tmpint$ = MID$(tmp2$, 1, INSTR(tmp2$, ".") - 1)
    ELSE
        tmpint$ = tmp2$
    END IF
    pete$ = tmpint$ + tmp1$
END FUNCTION

FUNCTION N2S$ (EXP$) 'remove scientific Notation to String (~40 LOC)
    'SMcNeill Jan 7, 2020 ref: https://www.qb64.org/forum/index.php?topic=1555.msg112989#msg112989
    'Last Function in code marked Best Answer (removed debug comments and blank lines added these 2 lines.)
    REDIM t$, sign$, l$, r$, r&&
    REDIM dp AS LONG, dm AS LONG, ep AS LONG, em AS LONG, check1 AS LONG, l AS LONG, i AS LONG
    t$ = LTRIM$(RTRIM$(EXP$))
    IF LEFT$(t$, 1) = "-" OR LEFT$(t$, 1) = "N" THEN sign$ = "-": t$ = MID$(t$, 2)
    dp = INSTR(t$, "D+"): dm = INSTR(t$, "D-")
    ep = INSTR(t$, "E+"): em = INSTR(t$, "E-")
    check1 = SGN(dp) + SGN(dm) + SGN(ep) + SGN(em)
    IF check1 < 1 OR check1 > 1 THEN N2S = _TRIM$(EXP$): EXIT FUNCTION 'If no scientic notation is found, or if we find more than 1 type, it's not SN!
    SELECT CASE l 'l now tells us where the SN starts at.
        CASE IS < dp: l = dp
        CASE IS < dm: l = dm
        CASE IS < ep: l = ep
        CASE IS < em: l = em
    END SELECT
    l$ = LEFT$(t$, l - 1) 'The left of the SN
    r$ = MID$(t$, l + 1): r&& = VAL(r$) 'The right of the SN, turned into a workable long
    IF INSTR(l$, ".") THEN 'Location of the decimal, if any
        IF r&& > 0 THEN
            r&& = r&& - LEN(l$) + 2
        ELSE
            r&& = r&& + 1
        END IF
        l$ = LEFT$(l$, 1) + MID$(l$, 3)
    END IF
    SELECT CASE r&&
        CASE 0 'what the heck? We solved it already?
            'l$ = l$
        CASE IS < 0
            FOR i = 1 TO -r&&
                l$ = "0" + l$
            NEXT
            l$ = "." + l$
        CASE ELSE
            FOR i = 1 TO r&&
                l$ = l$ + "0"
            NEXT
            l$ = l$
    END SELECT
    N2S$ = sign$ + l$
END FUNCTION

FUNCTION Round2$ (anyNumber AS _FLOAT, dp AS LONG) ' uses N2S$
    ' 5 and up at decimal place dp+1 > +1 at decimal place  4 and down  > +0 at dp

    '2 1 0.-1 -2 -3 -4 ...  pick dp like this for this Round$ Function
    DIM sn$, dot, predot, postdot, rtn$

    sn$ = N2S$(STR$(anyNumber + .5 * 10 ^ dp)) 'get rid of sci notation, steve trims it so next find dot
    dot = INSTR(sn$, ".")
    IF dot THEN
        predot = dot - 1
        postdot = LEN(sn$) - (dot + 1)
    ELSE
        predot = LEN(sn$)
        postdot = 0
    END IF
    ' xxx.yyyyyy  dp = -2
    '      ^ dp
    IF dp >= 0 THEN
        rtn$ = MID$(sn$, 1, predot - dp) + STRING$(dp, "0")
    ELSE
        rtn$ = MID$(sn$, 1, predot) + "." + MID$(sn$, dot + 1, -dp)
    END IF
    IF rtn$ = "" THEN Round2$ = "0" ELSE Round2$ = rtn$
END FUNCTION

Pete