Inconsistent application of banker's rounding

Post bugreports for the Windows version here
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6076
Joined: Sat May 17, 2003 11:31 am
Contact:

Inconsistent application of banker's rounding

Post by blueznl »

Code: Select all

zero.f = 0
onehalf.f = 1.5
three.f = 3
four.f = 4

i.l = 3.0 + 1.5
Debug i

j.l = 4.0 + 1.5
Debug j

k.l = onehalf + three
Debug k

l.l = onehalf + four
Debug l
Triggered by this thread:

http://www.purebasic.fr/english/viewtop ... 43#p339143
( PB5.xx Win10 x64 Asrock AB350 Pro4 Ryzen 1600X 32GB RAM Evo 840 GTX1060 )
( The path to enlightenment and the PureBasic Survival Guide right here... )
User avatar
luis
Addict
Addict
Posts: 3706
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy
Contact:

Re: Inconsistent application of banker's rounding

Post by luis »

wow, nice find !

Code: Select all

; 
; i.l = 3.0 + 1.5
  MOV    dword [v_i],5
; Debug i
; 
; j.l = 4.0 + 1.5
  MOV    dword [v_j],6
; Debug j
; 
; k.l = onehalf + three
  FLD    dword [v_onehalf]
  FADD   dword [v_three]
  FADD   dword [F1]
  FISTP  dword [v_k]
; Debug k
; 
; l.l = onehalf + four
  FLD    dword [v_onehalf]
  FADD   dword [v_four]
  FADD   dword [F1]
  FISTP  dword [v_l]
; Debug l
In the first two expressions the compiler pre-calculate the resulting constants (3.0+1.5 and 4.0+1.5) rounding them to the highest int and assign them directly to the long vars (not applying the "banker's rounding")

In the last two expressions involving float vars, the compiler generate the floating point instructions for the cpu resulting in the correct "banker's rounding".


EDIT: oh, I saw you already guessed it ! :)
blueznl wrote: ... my suspicion is that the compiler tries to optimize 3.0 + 1.5 and uses a regular 'normal rounding' rule, whilst the other calculation is done inside the FPU and is then converted back to integer following some IEEE standard.
Little John
Addict
Addict
Posts: 4000
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: Inconsistent application of banker's rounding

Post by Little John »

I think this is one more good example of the risks of implicit typecasting. In cases like this, it's safer to use Int() or Round(), e.g.

Code: Select all

zero.f = 0
onehalf.f = 1.5
three.f = 3
four.f = 4

i.l = Round(3.0 + 1.5, #PB_Round_Nearest)
Debug i

j.l = Round(4.0 + 1.5, #PB_Round_Nearest)
Debug j

k.l = Round(onehalf + three, #PB_Round_Nearest)
Debug k

l.l = Round(onehalf + four, #PB_Round_Nearest)
Debug l
Regards, Little John
Please excuse my flawed English. My native language is PureBasic.
Search
RSBasic's backups
User avatar
Michael Vogel
Addict
Addict
Posts: 2571
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Inconsistent application of banker's rounding

Post by Michael Vogel »

Little John wrote:I think this is one more good example of the risks of implicit typecasting. [...]
Wouldn't it be fine to get the full power (for confusion):

Code: Select all

; just some ideas how type casting could be seen in PB5.02 
i.l = {long} (3.0 + {byte} 1.5);
j.l = {long} 4.0 + {long} ( {float} 3/2 )
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Inconsistent application of banker's rounding

Post by PB »

@blueznl:
But is it a bug to store the results of a float in a long?
Fred once told me never to do that, so I always use
floats to hold the results. If you change all your ".l"
to ".f" in your first post, then all results are correct.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6076
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: Inconsistent application of banker's rounding

Post by blueznl »

I agree it may not make much sense to store the result in an int, but that isn't the point. I just wanted to point out the behaviour is inconsistent, which is something nobody wants I guess :-)
( PB5.xx Win10 x64 Asrock AB350 Pro4 Ryzen 1600X 32GB RAM Evo 840 GTX1060 )
( The path to enlightenment and the PureBasic Survival Guide right here... )
PeterH
User
User
Posts: 25
Joined: Sun Apr 11, 2010 11:01 am

Re: Inconsistent application of banker's rounding

Post by PeterH »

Not having owned PB for that many years, this surprised me a bit.

Two weeks of late nights with debugging and tinkering, just to find that I stumbled upon a 7 year old (still not fixed) bug. Pure chance that I even found this thread. I am going to get so hammered now.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Inconsistent application of banker's rounding

Post by Dude »

If you want to use floats, then make your data types floats, as mentioned above. Not a bug.
User avatar
luis
Addict
Addict
Posts: 3706
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy
Contact:

Re: Inconsistent application of banker's rounding

Post by luis »

Dude wrote:Not a bug.
It's a bug.

Assigning floats to integers it's a normal, legal, mundane operation.
As LJ says, you can use explicit rounding functions if you think the compiler will behave incoherently or in a way which doesn't fit your requirements, to make sure you will get what you intended to.
But it may not be required if the compiler behave in a consistent way which does align with your requirements.
All it's fine if the assignment of a float to an int is treated by the compiler in a coherent way, preferably like most languages do to not make your life harder when porting code.

The destination variables used in this example are of the same type, the float values used in the expressions are exactly the same, the expressions are exactly the same.
Yet the result changes depending on the floats being expressed as immediate values or float variables containing the same values.
The compiler is incoherently giving different results for the same operations applied on the same data.

BTW: since in the first post the results are not mentioned here it is what happens currently.

Code: Select all

zero.f = 0.0
onehalf.f = 1.5
three.f = 3.0
four.f = 4.0

i.l = 3.0 + 1.5
Debug i ; = 5 (round to next integer)

j.l = 4.0 + 1.5
Debug j ; = 6 (round to next integer)

k.l = three + onehalf
Debug k ; = 4 (banker's rounding to the nearest even integer)

l.l = four + onehalf 
Debug l ; = 6 (banker's rounding to the nearest even integer)
Mistrel
Addict
Addict
Posts: 3379
Joined: Sat Jun 30, 2007 8:04 pm

Re: Inconsistent application of banker's rounding

Post by Mistrel »

Dude wrote:If you want to use floats, then make your data types floats, as mentioned above. Not a bug.
I would argue that the issue is the inconsistency of the implementation. If this is the correct behavior then it should be well defined in the documentation.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Inconsistent application of banker's rounding

Post by Dude »

luis wrote:It's a bug.
I agree now, because of this comment by Fred three years ago:
Fred wrote:It looks like a bug, the whole expression should be considered as float when a float is encountered.
Source: http://www.purebasic.fr/english/viewtop ... 63#p445463
Post Reply