www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - type comparisons

reply Denton Cockburn <diboss hotmail.com> writes:
Why does this throw these assert errors?
both are thrown.

All 3 - DMD 2.008/2.009/2.010

void main()
{
	real x = 0.6584L;
	double y = 0.6584;
	assert(x == y);
	assert(cast(double)x == y);
}
Jan 26 2008
parent reply BCS <ao pathlink.com> writes:
Reply to Denton,

 Why does this throw these assert errors?
 both are thrown.
 All 3 - DMD 2.008/2.009/2.010
 
 void main()
 {
 real x = 0.6584L;
 double y = 0.6584;
 assert(x == y);
 assert(cast(double)x == y);
 }

rounding error? rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.
Jan 26 2008
parent reply Denton Cockburn <diboss hotmail.com> writes:
On Sat, 26 Jan 2008 18:36:41 +0000, BCS wrote:

 Reply to Denton,
 
 [quoted text muted]

rounding error? rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.

I can't think of a reason that would be acceptable. This means I can't reliably do operations with converted reals/doubles :( This is also weird: double a = 0.65; real b = a + 0.1; b -= 0.1; assert(b == a); // fails real c = a; c += 0.1; c -= 0.1; assert(c == a); // passes
Jan 26 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Denton Cockburn wrote:
 On Sat, 26 Jan 2008 18:36:41 +0000, BCS wrote:
 
 Reply to Denton,

 [quoted text muted]

rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.

I can't think of a reason that would be acceptable. This means I can't reliably do operations with converted reals/doubles :( This is also weird: double a = 0.65; real b = a + 0.1; b -= 0.1; assert(b == a); // fails real c = a; c += 0.1; c -= 0.1; assert(c == a); // passes

You should never compare floating point values using ==. It's not D's fault, it's the lossy nature of floating point calculations themselves. Instead do something like assert(abs(c-a) < rounding_tolerance); --bb
Jan 26 2008
prev sibling parent reply =?ISO-8859-1?Q?=22J=E9r=F4me_M=2E_Berger=22?= <jeberger free.fr> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Denton Cockburn wrote:
 On Sat, 26 Jan 2008 18:36:41 +0000, BCS wrote:
 
 Reply to Denton,

 [quoted text muted]

rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.

I can't think of a reason that would be acceptable. This means I can't reliably do operations with converted reals/doubles :( This is also weird: double a = 0.65; real b = a + 0.1;

to real
 b -= 0.1;
 assert(b == a); // fails
 
 real c = a;
 c += 0.1;

 c -= 0.1;
 assert(c == a); // passes

Which could explain that rounding errors wind up different and make one assertion pass while the other fails. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHm4y1d0kWM4JG3k8RAgfQAKC3LwsQfklEVT+cP2w3HrR/xtK6JACfdPr9 PQIwRTbf2zyhpst9zdeZn9s= =RA4Q -----END PGP SIGNATURE-----
Jan 26 2008
parent reply Denton Cockburn <diboss hotmail.com> writes:
Jérôme M. Berger Wrote:

 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 Denton Cockburn wrote:
 On Sat, 26 Jan 2008 18:36:41 +0000, BCS wrote:
 
 Reply to Denton,

 [quoted text muted]

rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.

I can't think of a reason that would be acceptable. This means I can't reliably do operations with converted reals/doubles :( This is also weird: double a = 0.65; real b = a + 0.1;

to real
 b -= 0.1;
 assert(b == a); // fails
 
 real c = a;
 c += 0.1;

 c -= 0.1;
 assert(c == a); // passes

Which could explain that rounding errors wind up different and make one assertion pass while the other fails. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHm4y1d0kWM4JG3k8RAgfQAKC3LwsQfklEVT+cP2w3HrR/xtK6JACfdPr9 PQIwRTbf2zyhpst9zdeZn9s= =RA4Q -----END PGP SIGNATURE-----

The problem I'm having is that we are comparing the same numerical value for equality, and getting a (logically) false result.
Jan 26 2008
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Denton Cockburn wrote:
 Jérôme M. Berger Wrote:
 
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1

 Denton Cockburn wrote:
 On Sat, 26 Jan 2008 18:36:41 +0000, BCS wrote:

 Reply to Denton,

 [quoted text muted]

rounding 0.6584 (base 10) to real and then converting to double may round different than rounding it directly to double.

This means I can't reliably do operations with converted reals/doubles :( This is also weird: double a = 0.65; real b = a + 0.1;

to real
 b -= 0.1;
 assert(b == a); // fails

 real c = a;
 c += 0.1;

 c -= 0.1;
 assert(c == a); // passes

one assertion pass while the other fails. Jerome - -- +------------------------- Jerome M. BERGER ---------------------+ | mailto:jeberger free.fr | ICQ: 238062172 | | http://jeberger.free.fr/ | Jabber: jeberger jabber.fr | +---------------------------------+------------------------------+ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) iD8DBQFHm4y1d0kWM4JG3k8RAgfQAKC3LwsQfklEVT+cP2w3HrR/xtK6JACfdPr9 PQIwRTbf2zyhpst9zdeZn9s= =RA4Q -----END PGP SIGNATURE-----

The problem I'm having is that we are comparing the same numerical value for equality, and getting a (logically) false result.

One tenth is not exactly representable in floating point. Therefore you get rounding errors the moment you try to store .1 in a float/double/real. real can represent 1/10 a bit more accurately than double. So .1 as a double, then cast to a real is not quite the same as .1 that started as a real. Try .125 or 0.0625 and you'll get a good answer. But .1 is bad news for floating point. --bb
Jan 26 2008
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Denton Cockburn" wrote
 The problem I'm having is that we are comparing the same numerical value 
 for equality, and getting a (logically) false result.

This is inherent in floating point. This happens in other languages as well. The problem is that .1 is like 1/3 in decimal. Decimal cannot accurately represent 1/3 because it is a repeating decimal (0.3333...). Likewise, floating point, which is base-2, cannot represent all decimal values accurately. For an in-depth explanation, see http://en.wikipedia.org/wiki/Floating_point Skip to the section on Accuracy. To work correctly, you should always compare floating point values by adding some small error. So instead of: assert(x > y) you write const myError = 1e-10; assert(x + myError > y) Equality looks something more like: assert(fabs(x - y) < myError) -Steve
Jan 28 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Steven Schveighoffer" wrote
 To work correctly, you should always compare floating point values by 
 adding some small error.  So instead of:

 assert(x > y)
 you write

 const myError = 1e-10;
 assert(x + myError > y)

Er... this should be: assert(x - myError > y) -Steve
Jan 28 2008