Page 1 of 1

Bug in an addition!

Posted: Fri Jan 02, 2026 4:52 pm
by charvista
Happy Year 2026 to you all! :D
This year begins with the detection of a bug in an addition. :shock:
No, it is not a joke.
I was calculating the Decimal value of a string, and the result was wrong.
Here is the code:

Code: Select all

Procedure.i zDec(S.s)
    Protected.i Dec,i
    For i=1 To Len(S)
        Dec+Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
    Next
    ProcedureReturn Dec
EndProcedure


Procedure.q zDecDebug(S.s)
    Protected.q X,DecOkay,DecProb,i
    For i=1 To Len(S)
        Debug "<Loop "+i+">"
        Debug "    "+Str(Abs(Asc(Mid(S,i,1))))
        Debug "    "+Str(Pow(256,Abs(i-Len(S))))
        X=Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
        Debug "   ="+X
        Debug "   ="+Str(Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S))))
        DecOkay+X
        DecProb+Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
        Debug "DecOkay="+DecOkay
        Debug "DecProb="+DecProb
    Next
    ProcedureReturn DecOkay
EndProcedure


Debug zDecDebug("ONEDRIV")
Debug zDec("ONEDRIV")
The zDec() is my original procedure.
The zDecDebug() is the same procedure with debugging.
As you can see, when I calculate to X before adding it to DecOkay, it looks fine.
But the variable X is not necessary because I can add it directly to the variable Dec, but the result is different at the 7th iteration.
I am working on Windows 11 64-bit, so using .i (integers) or .q (quad) makes no difference.

The final result 22322582566095190 has 17 digits, and is far below the integer range 9223372036854775808 to +9223372036854775807 (19 digits), so it is normally safe.
So, why do I get a difference of 2 :?:

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:01 pm
by infratec
I can not run your code.
I get an error message that a quad variable is not allowed in a for loop.

PB 6.30b6 x86 on win10 x64

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:03 pm
by infratec
If you make both procedure identical with .q
they return the same value

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:10 pm
by infratec
Wrong from me :oops:

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:19 pm
by infratec
Btw.:

Code: Select all

For i=1 To Len(S)
  Dec = Dec << 8 | Asc(Mid(S,i,1))
Next i
is much faster and don't convert types.

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:25 pm
by infratec
My version:

Code: Select all

Procedure.q zDecInfratec(S.s)
    
  Protected Dec.q, i.i, *Ptr.Unicode
  
  
  *Ptr = @S
  While *Ptr\u
    Dec = Dec << 8 | *Ptr\u
    Debug Hex(Dec)
    *Ptr + 2
  Wend
  
  ProcedureReturn Dec
  
EndProcedure

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:29 pm
by skywalk
Works without For..Next as quads not allowed.
Windows 11 x64 latest, x64 CBE.

Code: Select all

EnableExplicit
Procedure.q zDec(S.s)
  Protected.q Dec,i
  i = 1
  Repeat
    Dec+Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
    i + 1
    If i = Len(S)
      Break
    EndIf
  ForEver
  ProcedureReturn Dec
EndProcedure
Procedure.q zDecDebug(S.s)
  Protected.q X,DecOkay,DecProb,i
  i = 1
  Repeat
    Debug "<Loop "+i+">"
    Debug "    "+Str(Abs(Asc(Mid(S,i,1))))
    Debug "    "+Str(Pow(256,Abs(i-Len(S))))
    X=Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
    Debug "   ="+X
    Debug "   ="+Str(Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S))))
    DecOkay+X
    DecProb+Abs(Asc(Mid(S,i,1)))*Pow(256,Abs(i-Len(S)))
    Debug "DecOkay="+DecOkay
    Debug "DecProb="+DecProb
    i + 1
    If i = Len(S)
      Break
    EndIf
  ForEver
  ProcedureReturn DecOkay
EndProcedure
Debug zDecDebug("ONEDRIV")
Debug zDec("ONEDRIV")

Code: Select all

<Loop 1>
    79
    281474976710656
   =22236523160141824
   =22236523160141824
DecOkay=22236523160141824
DecProb=22236523160141824
<Loop 2>
    78
    1099511627776
   =85761906966528
   =85761906966528
DecOkay=22322285067108352
DecProb=22322285067108352
<Loop 3>
    69
    4294967296
   =296352743424
   =296352743424
DecOkay=22322581419851776
DecProb=22322581419851776
<Loop 4>
    68
    16777216
   =1140850688
   =1140850688
DecOkay=22322582560702464
DecProb=22322582560702464
<Loop 5>
    82
    65536
   =5373952
   =5373952
DecOkay=22322582566076416
DecProb=22322582566076416
<Loop 6>
    73
    256
   =18688
   =18688
DecOkay=22322582566095104
DecProb=22322582566095104
22322582566095104
22322582566095104

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 5:41 pm
by infratec
Back to the main problem

Code: Select all

t.q = 22322582566095104
Debug t
Debug t + 86.0
Debug t + Int(86.0)
The problem is that in the second debug line the value is converted to a double.
And then you come the 'normal' floating point problem.
Large values can not precise represented by float or double.

The same happens in your code.
-> Not a bug.

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 6:00 pm
by skywalk
You are correct, big math requires scaling + integers.
I only report the 2 functions return same answer.
They did not using for..next loop.

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 6:38 pm
by NicTheQuick
infratec wrote: Fri Jan 02, 2026 5:01 pm I can not run your code.
I get an error message that a quad variable is not allowed in a for loop.

PB 6.30b6 x86 on win10 x64
lol. Why do you use x86 in the first place on a x64 Windows? Just use x64 and profit from the speed up.

Re: Bug in an addition!

Posted: Fri Jan 02, 2026 6:48 pm
by infratec
NicTheQuick wrote: Fri Jan 02, 2026 6:38 pm lol. Why do you use x86 in the first place on a x64 Windows? Just use x64 and profit from the speed up.
Because customers still have some x86 PCs in use.
Also for my hobby project many peoble buy cheap laptops (<=50EUR) with Win7 to use it as OBD Diagnostic laptop. (GuzziDiag)
So ... there is still a reason to use the x86 compiler.

Re: Bug in an addition!

Posted: Sat Jan 03, 2026 12:41 am
by charvista
You are right, it is not a bug.
It is due to the limitation of Pow() to 2^53 (= 9'007'199'254'740'992) from IEEE-754 restrictions.
Infratec's elegant Dec() function solved the problem:

Code: Select all

Procedure.q DecInfratec(S.s) ; (8 bits) Ascii plane 0-255
    Protected *Ptr.Unicode
    Protected.q Dec
    *Ptr = @S
    While *Ptr\u
        Dec << 8 | *Ptr\u
        Debug Hex(Dec)
        *Ptr + 2
    Wend
    ProcedureReturn Dec
EndProcedure
Thanks!