!IMPORTANT! - Real Comparision BUG

Status
Not open for further replies.
Hello everyone,

I just notice a bug (I hope it's not my warcraft 3) I have 1.33.0.19252 version of Warcraft 3 classic

when there is a comparison (superiod or equal) between 2 reals (one of them is a counter) it can't detect the 2 amounts are equals
if the amount added is lower than 0.1

here are 2 snippets of the code map joined

JASS:
globals
  constant real INTERVAL = 0.05

  constant real TIMER_MAX = 0.25

  real COUNT = 0

endglobals

function Trig_Timer_Actions takes nothing returns nothing
  set COUNT = COUNT + INTERVAL

  call BJDebugMsg(R2S(COUNT))

  if COUNT == TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " == " + R2S(TIMER_MAX))
  endif

  if COUNT >= TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " >= " + R2S(TIMER_MAX))
    set COUNT = 0
  endif

endfunction

//===========================================================================
function InitTrig_Timer takes nothing returns nothing
    set gg_trg_Timer = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_Timer, INTERVAL )
    call TriggerAddAction( gg_trg_Timer, function Trig_Timer_Actions )
endfunction

This will display
0.05
0.10
0.15
0.20
0.25 (the condition should be true there)
0.30 (and then the condition is true)

it does not detects that 0.25 (COUNT) is SUPERIOR OR EQUAL to 0.25 (TIMER_MAX)
it waits the next iteration to say that 0.3 (COUNT) is SUPERIOR OR EQUAL to 0.25 (TIMER_MAX)

JASS:
globals
  constant real INTERVAL = 0.1

  constant real TIMER_MAX = 0.3

  real COUNT = 0

endglobals

function Trig_Timer_Actions takes nothing returns nothing
  set COUNT = COUNT + INTERVAL

  call BJDebugMsg(R2S(COUNT))

  if COUNT == TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " == " + R2S(TIMER_MAX))
  endif

  if COUNT >= TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " >= " + R2S(TIMER_MAX))
    set COUNT = 0
  endif

endfunction

//===========================================================================
function InitTrig_Timer takes nothing returns nothing
    set gg_trg_Timer = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_Timer, INTERVAL )
    call TriggerAddAction( gg_trg_Timer, function Trig_Timer_Actions )
endfunction

This will display
0.10
0.20
0.30 (and then the condition is true) that is correct

I think that the equal part of the comparision ">=" does not work with decimals added if the number is lower than 0.1...
(Integer comparision works) I've noticed that bug when I launch a test from the world editor and when I launch a game normally
"<=" comparision seems to work properly

What do you think?
Does someone have the same problem?
I join a map for you to test
 

Attachments

  • Real Comparison Bug.w3m
    16.8 KB · Views: 10
Last edited:
What do you think?
Does someone have the same problem?
Basically every programming language in world (that uses IEEE754 or similar) have this issue.
The TLDR of it is that all reals (or floating point numbers) are inexact by definition and should be treated as such.

0.1 + 0.2 will never be 0.3. It will be something like 0.30000000000000004.
In this case, it was slightly bigger than 0.3, but all numbers can be slightly bigger or smaller than what you'd expect, and you'll have to deal with it by NEVER expect exact equals between reals, always add/remove a tiny number to account for inexact numbers if you care about exact values.

If you want to know all the details (imo it's very interesting, but then again, I'm a nerd... xD), read the linked wikipedia article.

Integers are fundamentally different and will always be exact. (between -2 billion to 2 billion, but that's another topic)
 
thanks for yourt answer @ThompZon but for whatr reason when we log the number we have 0.2500 no more decimals (maybe because it is truncated).
And for what reason when we add numbers like bigger or equal that 0.1 I don't have the problem.
And last thing in my test I check the exact match of the value with "==" and it returns true... so I don't think there is a decimal problem. I trust you, because you are the nerd xD
 
Test 1: FOR 0 to 0.25 interval 0.05
1662904020071.png


Test 2: FOR 0 to 0.3 interval 0.1
1662904081823.png
 
thanks for yourt answer @ThompZon but for whatr reason when we log the number we have 0.2500 no more decimals (maybe because it is truncated).
And for what reason when we add numbers like bigger or equal that 0.1 I don't have the problem.
Yes, it is truncated.
That's probably because 0.1 is actually 0.100000000000002 and 0.05 is actually 0.049999999998 or something like that. If you use "less than or equals" I'd guess you'll have the opposite problem.

Each time you add/subtract, a tiny bit or "error" is introduced and it can be either bigger or smaller than expected value.

I guess that you can use R2SW with 10 digit precision to see more exact values. I'm pretty damn sure reals are 32-bit floats (meaning that 7-8 decimal places), but I haven't bothered making sure that's the case...
 
Typically when you check for equals between values A, B (as I said, something you should "never" do), should check Abs(A - B) <= epsilon, where epsilon is your "equality threshold". Something like a difference smaller than 0.000001 is considered "equal enough" in many cases.

I'd guess that WC3 does that automatically under the hood when checking equals... But they don't do for >= or <= I guess.
 
1662905020861.png

the lower or equals has the same problem.
Thanks man for your very detailled answers

here is the code:
JASS:
globals
  constant real INTERVAL = 0.05

  constant real TIMER_MAX = 0.25

  real COUNT = 0

endglobals

function Trig_Timer_Actions takes nothing returns nothing
  set COUNT = COUNT + INTERVAL

  call BJDebugMsg(R2S(COUNT))

  if COUNT == TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " == " + R2S(TIMER_MAX))
  endif

  if TIMER_MAX <= COUNT then
    call BJDebugMsg(R2S(TIMER_MAX) + " <= " + R2S(COUNT))
  endif

  if COUNT >= TIMER_MAX then
    call BJDebugMsg(R2S(COUNT) + " >= " + R2S(TIMER_MAX))
    set COUNT = 0
  endif

endfunction

//===========================================================================
function InitTrig_Timer takes nothing returns nothing
    set gg_trg_Timer = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_Timer, INTERVAL )
    call TriggerAddAction( gg_trg_Timer, function Trig_Timer_Actions )
endfunction
 
Level 45
Joined
Feb 27, 2007
Messages
5,578
In an instance like this the easiest thing to do to be 'precise' is to use an integer instead. Instead of checking that Count == 0.25, you leave count as an integer and check that Count == 5. If you need to know the 'full long value' of count then you'd compute Duration = Count*Interval.
 
Typically when you check for equals between values A, B (as I said, something you should "never" do), should check Abs(A - B) <= epsilon, where epsilon is your "equality threshold". Something like a difference smaller than 0.000001 is considered "equal enough" in many cases.

I'd guess that WC3 does that automatically under the hood when checking equals... But they don't do for >= or <= I guess.
It is safe though to do a real comparison to check whether the value of a real variable has changed. Also, I was under the impression that JASS uses single-precision floats and not double-precision, and that's why real numbers diverge much faster from their "intended" values than in some other programming languages. So, if I'm correct, 0.3 won't be 0.30000000000000004, but even 0.30000004.
 
If it helps, I recall someone years ago saying something to the effect that "!=" in jass doesn't do an epsilon check like ThompZon mentioned, but "==" does do the check. As such, if you check not COUNT != TIMER_MAX then if what I remember from the old days is correct, that check would probably fail when COUNT == TIMER_MAX would still pass. And if you think about that, that is a very weird result that we would not normally expect in most programming languages. Usually we would think "not A == B" and "A != B" were exactly the same check. But what I heard back then was that in JASS2 on Wc3, these two checks are not equivalent.
 
Status
Not open for further replies.
Top