Compiler setting for accurate math?
#7
As best as my memory serves me these days, I think this is or is close to the ledger formula I made 30 years ago...

I put is Steve's side by side to compare result.

Edit: I found some unacceptable results in both my function and Steve's on an expanded level. I'll post an example in a bit...

Code: (Select All)
$CONSOLE:ONLY
DIM x
FOR x = 1 TO -0.001 STEP -.01
    PRINT x;: LOCATE , 25: PRINT "Pete = "; pete$(x);: LOCATE , 45: PRINT "Steve = "; Round2$(x, -2)
NEXT x
'-----------------------------------------------------------------------
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

Here's the glitch I found in Steve's function results Mark posted, using an extended testing range. Run it and it will beep and pause at the first error. Click the left mouse button to continue. It will beep and pause one more time. Note in the first case a sequence is skipped and in the second case a number is duplicated. I experienced similar errors at slightly different places in my function results.

Code: (Select All)
DIM x
cnt = 10000
FOR x = 100 TO -0.001 STEP -.01
    a$ = Round2$(x, -2)
    PRINT cnt, x;: LOCATE , 30: PRINT "Steve = "; a$
    REM IF cnt <> VAL(MID$(a$, 1, INSTR(a$, ".") - 1) + MID$(a$, INSTR(a$, ".") + 1)) THEN DO: WHILE _MOUSEINPUT: WEND: LOOP UNTIL _MOUSEBUTTON(1): _DELAY .1
    IF LEN(olda$) AND ABS(VAL(a$) - VAL(olda$)) <> .01 THEN BEEP: DO: WHILE _MOUSEINPUT: WEND: LOOP UNTIL _MOUSEBUTTON(1): _DELAY .1
    cnt = cnt - 1
    olda$ = a$
NEXT

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

Now this could easily be a case of apples and oranges. If Steve's function is for rounding a single number instead of for use in adjusting the output sequence generated in a decimal loop, it isn't the right tool for this particular task.

I'll wait until some more eyes get into this. I've pulled an all-nighter (no, not 'highlighter' you dumb ass spell check...) working on some code and none code related stuff, and for all I know I'm imagining being on the forum typing this post. That's right, sleep coding again! Big Grin

Pete
Reply


Messages In This Thread
RE: Compiler setting for accurate math? - by Jack - 11-30-2022, 11:48 PM
RE: Compiler setting for accurate math? - by Pete - 12-01-2022, 04:26 AM
RE: Compiler setting for accurate math? - by Pete - 12-01-2022, 10:43 AM
RE: Compiler setting for accurate math? - by Pete - 12-01-2022, 04:52 PM
RE: Compiler setting for accurate math? - by Pete - 12-01-2022, 10:16 PM



Users browsing this thread: 2 Guest(s)