Page 1 of 1

Passigs Double/Float test passed

Posted: Fri Feb 27, 2015 9:48 am
by langinagel
In her german book "Weniger schlecht Programmieren" Kathrin Passig says that the following code will fail in almost all programming languages:

Code: Select all

        double a = 0.7;
	double b = 0.9;
	double x = a + 0.1;
	double y = b - 0.1;
	if (x == y) {
		printf(" all fine");
	}
	else {
		printf( " it failed ");
	}
She is right on C (current GCC compiler).

Curiously I tried it with Purebasic:

Code: Select all

OpenConsole()
ad.d = 0.7
bd.d = 0.9
xd = ad + 0.1
yd = bd - 0.1

If xd = yd
  PrintN("Purebasic can do with double")
Else
  Print("PB is all the same on double")
EndIf

af.f = 0.7
bf.f = 0.9
xf = af + 0.1
yf = bf - 0.1

If xf = yf
  PrintN("Purebasic can do with float")
Else
  Print("PB is all the same with float")
EndIf

Input()
and I got a surprising good result (on PB 5.30 Linux-x86).

Is this coincidence? Or is there anything better with PB?

Re: Passigs Double/Float test passed

Posted: Fri Feb 27, 2015 10:01 am
by Danilo
xd and yd should be defined as double. They are Integer now (Default type, .i).
xf and yf should be defined as float. They are Integer now (Default type, .i).

Added code:

Code: Select all

PrintN(""+xd+"="+yd)
PrintN(""+xf+"="+yf)
Output:

Code: Select all

1=1
1=1
:D

After the correction:

Code: Select all

OpenConsole()
ad.d = 0.7
bd.d = 0.9
xd.d = ad + 0.1
yd.d = bd - 0.1

If xd = yd
  PrintN("all fine with double")
Else
  PrintN("it failed with double")
EndIf
PrintN("")
PrintN("xd: "+StrD(xd,20))
PrintN("yd: "+StrD(yd,20))

PrintN("")
PrintN("------------------------------")

af.f = 0.7
bf.f = 0.9
xf.f = af + 0.1
yf.f = bf - 0.1

If xf = yf
  PrintN("all fine with float")
Else
  PrintN("it failed with float")
EndIf
PrintN("")
PrintN("xf: "+StrF(xf,20))
PrintN("yf: "+StrF(yf,20))

Input()

Re: Passigs Double/Float test passed

Posted: Fri Feb 27, 2015 1:08 pm
by langinagel
:shock:

Thanks Danilo.

:oops:
Lesson learned:
I have to check my code better before posting "surprising" results.
Mea culpa.

Re: Passigs Double/Float test passed

Posted: Mon Mar 02, 2015 9:53 am
by blueznl
I never understood how ol' GFAbasic did this, but IIRC there it would pass this test. I should reinstall it one of these days and see if I remember correctly.

Re: Passigs Double/Float test passed

Posted: Mon Mar 02, 2015 3:49 pm
by Thorium
blueznl wrote:I never understood how ol' GFAbasic did this, but IIRC there it would pass this test. I should reinstall it one of these days and see if I remember correctly.
It's commonly done by doing rounded comparisions.

Re: Passigs Double/Float test passed

Posted: Mon Mar 02, 2015 4:06 pm
by Thorium
Here is a rounded compare. It rounds to 3 digits and compares.

Code: Select all

OpenConsole()
ad.d = 0.7
bd.d = 0.9
xd.d = ad + 0.1
yd.d = bd - 0.1

If Round(xd*1000, #PB_Round_Nearest)/1000 = Round(yd*1000, #PB_Round_Nearest)/1000
  PrintN("all fine with double")
Else
  PrintN("it failed with double")
EndIf
PrintN("")
PrintN("xd: "+StrD(xd,20))
PrintN("yd: "+StrD(yd,20))
PrintN("xd rounded: "+StrF(Round(xd*1000, #PB_Round_Nearest)/1000,20))
PrintN("xd rounded: "+StrF(Round(yd*1000, #PB_Round_Nearest)/1000,20))

PrintN("")
PrintN("------------------------------")

af.f = 0.7
bf.f = 0.9
xf.f = af + 0.1
yf.f = bf - 0.1

If Round(xf*1000, #PB_Round_Nearest)/1000 = Round(yf*1000, #PB_Round_Nearest)/1000
  PrintN("all fine with float")
Else
  PrintN("it failed with float")
EndIf
PrintN("")
PrintN("xf: "+StrF(xf,20))
PrintN("yf: "+StrF(yf,20))
PrintN("xf rounded: "+StrF(Round(xf*1000, #PB_Round_Nearest)/1000,20))
PrintN("xf rounded: "+StrF(Round(yf*1000, #PB_Round_Nearest)/1000,20))

Input()

Re: Passigs Double/Float test passed

Posted: Mon Mar 02, 2015 7:52 pm
by blueznl
Thorium wrote:
blueznl wrote:I never understood how ol' GFAbasic did this, but IIRC there it would pass this test. I should reinstall it one of these days and see if I remember correctly.
It's commonly done by doing rounded comparisions.
Hmmm. I'm not totally convinced :-) I always suspected them of doing some 'behind the scenes' manipulation using shifted decimals. I know I've used that approach myself sometimes in some financial application where I had to deal with very large and very small numbers. I was using three elements, float flag, base, exponent, like this:

2.5 = 2.5 x 10^0 and would be stored as 0 25 0
25 = 2.5 x 10^1 and would be stored as 0 25 1
250000000 = 2.5 x 10^8 and would be stored as 0 25 8
2/3 wouldn't fit in that scheme and would be stored as a 1 followed by a float

I must have some of that code somewhere, figuring out when to pick what format was a bit tricky. IIRC the root trigger was that the floats weren't accurate enough for certain things. Even worse, the biggest Int was 64k so I wrote my own little math lib in 6502 assembly to handle larger numbers. (It was some software that calculated the pricing of electronic components in large numbers, ie. very low component prices, and pretty big total numbers. Ah... long ago, when I was still young...)

Re: Passigs Double/Float test passed

Posted: Mon Mar 02, 2015 10:07 pm
by Thorium
VB6 did it like that.
And Siemens Sinumerik high language extension for CNC does it also this way. On Sinumerik you can actually specify the compare precision.