Posts: 660
Threads: 142
Joined: Apr 2022
Reputation:
58
Why does this happen?
when this is the code?
Code: (Select All) Dim x
For x = 1 To .05 Step -.05
Print x
_Delay x
Next x
Is there a complier setting to keep this from happening?
Posts: 128
Threads: 17
Joined: Apr 2022
Reputation:
10
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
Posts: 3,927
Threads: 175
Joined: Apr 2022
Reputation:
214
When you get desperate enough there is Steve's N2S$ and a rounding thing that uses it in my vs GUI.BM that I absolutely needed to get numbers right for Slider Boxes.
b = b + ...
Posts: 422
Threads: 27
Joined: Apr 2022
Reputation:
26
11-30-2022, 11:48 PM
(This post was last modified: 11-30-2022, 11:51 PM by Jack.)
hello @ James D Jarvis
if you feel like having a bit of fun try the following
in the file internal\c\libqb.cpp search for qbs *qbs_str(float value) {
and change l = sprintf((char *)&qbs_str_buffer, "% .6E", value);
to l = sprintf((char *)&qbs_str_buffer, "% .5G", value);
save and recompile your basic program
I only tested this with your code in first post, don't know how this would behave for other values, one thing for sure is that this will print 1 digit less
Posts: 2,152
Threads: 222
Joined: Apr 2022
Reputation:
102
Use Jack's decfloat or my string math routine. Computer binary math is troublesome when the results we want are to be in base 10. Before I made a string math routine, I made a rounding routine that worked fine for my accounting apps, although we are talking about maximum transactions in the thousands. With Bideflation, I'd have to test it out to a few more zeros.
Pete
Shoot first and shoot people who ask questions, later.
Posts: 3,927
Threads: 175
Joined: Apr 2022
Reputation:
214
Code: (Select All) Dim x
For x = 1 To -0.001 Step -.05
Print Round2$(x, -2)
_Limit 4
Next x
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
A few LOC less than string math and still QB64
b = b + ...
Posts: 2,152
Threads: 222
Joined: Apr 2022
Reputation:
102
12-01-2022, 10:43 AM
(This post was last modified: 12-01-2022, 02:04 PM by Pete.)
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!
Pete
Posts: 3,927
Threads: 175
Joined: Apr 2022
Reputation:
214
12-01-2022, 04:29 PM
(This post was last modified: 12-01-2022, 04:33 PM by bplus.)
SOB code has me swearing, every time I think I have some accuracy in display settled, someone comes up with something to shake my faith.
@Pete
Took me a long time to figure out what was going on, not pleasantly!
Here it is!
Code: (Select All) For x = 100 To -.001 Step -.01
You (we) are (were) expecting x of a single type in the FOR loop to be better behaved than any other single type!
I have no idea why it decides not to round up at the 2 places in 10,000 numbers but look at those freak'n x values wandering as much as .005 off the expected value!
I did an equivalent test like yours dropping integers down: For cnt = 10000 to 1 step -1
only setting x = cnt/100 and x doesn't wander nearly as much as .005 and so roundDP$ returns expected results.
BTW Round2$ was old code that failed with negative numbers.
Code: (Select All) $Console:Only
''test DP$ 2022-10-14 another Round Helper
'For n = 1 To 10000
' If n = 7658 Then Beep: Flag = -1
' a = n / 100
' r$ = roundDP$(a, 2)
' Print n, a, r$
' If n Mod 20 = 0 Then
' If Flag Then Sleep
' Cls
' End If
'Next
'Dim x ' ref Pete's test https://qb64phoenix.com/forum/showthread.php?tid=1209&pid=10895#pid10895
'cnt = 10000
'For x = 100 To -.001 Step -.01
' a$ = roundDP$(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
' If Len(olda$) And Abs(Val(a$) - Val(olda$)) <> .01 Then Beep: Sleep ' <<< b= mod this is less confusing than above
' cnt = cnt - 1
' olda$ = a$
' 'If cnt Mod 10 = 0 Then ' check screens
' ' Sleep
' ' Cls
' 'End If
'Next
Dim cnt As Long, x As Single
For cnt = 10000 To 5000 Step -1
x = cnt / 100
a$ = roundDP$(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
If Len(olda$) And Abs(Val(a$) - Val(olda$)) <> .01 Then Beep: Sleep ' <<< b= mod this is less confusing than above
olda$ = a$
'If cnt Mod 20 = 0 Then ' check screens
' Sleep
' Cls
'End If
Next
Function roundDP$ (num, digits) 'flaw if expontential notation involved.
Print "roundDP recd this num"; num
s$ = N2S$(Str$(num + Sgn(num) * (.5 * (10 ^ -digits))))
dot = InStr(s$, ".")
If dot Then r$ = Mid$(s$, 1, dot + digits) Else r$ = s$
roundDP$ = r$
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
I am glad I did do this because I am updating GUI for new dialogs in v3.4.1 and I was using the buggy Round2$ code that failed with neg numbers.
BTW I get something short of 5000 lines in Console, good to know.
b = b + ...
Posts: 3,927
Threads: 175
Joined: Apr 2022
Reputation:
214
(11-30-2022, 07:49 PM)James D Jarvis Wrote: Why does this happen?
when this is the code?
Code: (Select All) Dim x
For x = 1 To .05 Step -.05
Print x
_Delay x
Next x
Is there a complier setting to keep this from happening?
The lesson is don't trust a single index in a FOR loop with < 1 steps. It gets off track by as much as half the step value.
Here is equivalent that works better:
Code: (Select All) Dim x
For x = 100 To 5 Step -5
i = i + 1: Print i, x / 100
_Delay x / 100 ' <<< why ?? accuracy .001
Next x
b = b + ...
Posts: 2,152
Threads: 222
Joined: Apr 2022
Reputation:
102
12-01-2022, 04:52 PM
(This post was last modified: 12-01-2022, 04:52 PM by Pete.)
Well don't tear your hair out over it, but if you do, save some for me. There isn't much going on under that big ol' hat of mine. Shut up Steve, I meant hair-wise!
Pete
|