www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - floating point conversion

reply Martin Krejcirik <mk-junk i-line.cz> writes:
import std.conv;

void main()
{
    float a = 1.23f;
    double b = to!float("1.23");
    assert (a == b); // ???
}

Should the assert fail or not ? (Please reply without trying first).


If your reply is yes, should
assert (a == to!float("1.23"))
fail or not ?

I'm bringing this up, because dmd and gdc (x86) don't agree on this.

-- 
mk
Jun 01 2014
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Martin Krejcirik:

     float a = 1.23f;
     double b = to!float("1.23");
     assert (a == b); // ???
 }

 Should the assert fail or not ? (Please reply without trying 
 first).
It's a bad question. Generally to compare floating point values for equality use std.math.feqrel. Bye, bearophile
Jun 01 2014
next sibling parent reply Martin Krejcirik <mk-junk i-line.cz> writes:
On 1.6.2014 14:45, bearophile wrote:
 It's a bad question. Generally to compare floating point values for
 equality use std.math.feqrel.
So it's just a coincidence, that GDC, LDC x86 and also DMD x86_64 doesn't fail ? And this bug https://issues.dlang.org/show_bug.cgi?id=12831 should be marked invalid ? -- mk
Jun 01 2014
parent reply "Qox" <robertw89 googlemail.com> writes:
 So it's just a coincidence, that GDC, LDC x86 and also DMD 
 x86_64
 doesn't fail ?
(Equality) Compareision of float/float or float/double are machine dependent (depends even on x86 on the generated code (SSE/SSE2/AVX/AVX2), rounding settings, maybe event the cpu vendor etc.). On other platforms (ARM, etc) it could be even more weird. The General rule is not to compare floats for equality, (is 0.0==-0.0, etc.). Use a epsilon based comparision scheme instead or a wrapper around it.
Jun 01 2014
parent "Wanderer" <no-reply no-reply.org> writes:
 The General rule is not to compare floats for equality, (is 
 0.0==-0.0, etc.). Use a epsilon based comparision scheme 
 instead or a wrapper around it.
That's not exactly true. You cannot (and should not) compare floating points for equality, and use epsilon-based comparison instead, only in one certain case: when one of the arguments if the result of computation, during which a computational error might accumulate. If you have two exact or constant values, comparing them directly is perfectly fine. :-) Nowadays floating-point hardware support is not that "buggy".
Jun 01 2014
prev sibling parent reply "Famous" <famous review_queue.org> writes:
On Sunday, 1 June 2014 at 12:45:26 UTC, bearophile wrote:
 It's a bad question.
Actually, Martin's question is a good one. Initializing a variable of type float via a literal or as conversion from string should be the same, exacly, always. Casting a float to double should be deterministic as well. Famous
Jun 01 2014
next sibling parent reply Martin Krejcirik <mk-junk i-line.cz> writes:
On 1.6.2014 16:42, Famous wrote:
 from string should be the same, exacly, always. Casting a float to
 double should be deterministic as well.
void main() { float a = 1.234f; double b = 1.234; assert (a == cast(float) b); // fails in DMD x86, works in GDC, LDC } Maybe enhancement request ? -- mk
Jun 01 2014
parent reply "Famous" <famous review_queue.org> writes:
On Sunday, 1 June 2014 at 15:31:53 UTC, Martin Krejcirik wrote:
 On 1.6.2014 16:42, Famous wrote:
 from string should be the same, exacly, always. Casting a 
 float to
 double should be deterministic as well.
void main() { float a = 1.234f; double b = 1.234; assert (a == cast(float) b); // fails in DMD x86, works in GDC, LDC } Maybe enhancement request ?
This is different. The decimal 1.234 cannot be exacly represented as radix-2 floating-point number. In your example above, a and b are not equal. They are both approximations to 1.234 but the value of b is closer. Then casting b to float might or might not result in the same value as that of a. This is what bearophile and Qox referred to. Since every float can be exacly converted to double the following situation is different: float a = 1.234f; double b = a; assert(a == b); // always succeeds in a sane environment When taking into account constant folding, well, decide on your own, whether the following behaviour is sane: void main() { const float a = 1.234f; float b = 1.234f; assert(a == 1.234); // ok assert(b == 1.234); // fails }
Jun 01 2014
next sibling parent "Famous" <famous review_queue.org> writes:
I have compiled some cases at

  http://dpaste.dzfl.pl/5611b8bce8e3

This implies that floating-point constants do not have fixed but 
minimum precision. Particularly, the literal 1.23 describes a 
floating-point value with either double or real precision 
depending on what it is compared to.

This seems to comply with

  http://dlang.org/float.html
Jun 01 2014
prev sibling parent Martin Krejcirik <mk-junk i-line.cz> writes:
On 1.6.2014 18:02, Famous wrote:
 This is different. The decimal 1.234 cannot be exacly represented as
 radix-2 floating-point number. In your example above, a and b are not
 equal. They are both approximations to 1.234 but the value of b is
Still feels iffy to me. If you add: printf("%.70f\n%.70f\n", a, cast(float) b); you can see that gcc in C and gdc in D both convert value of b to float resulting in equality. Dmd doesn't, it just ignore the cast. -- mk
Jun 01 2014
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Sun, 01 Jun 2014 14:42:34 +0000
Famous via Digitalmars-d-learn <digitalmars-d-learn puremagic.com>
wrote:

 On Sunday, 1 June 2014 at 12:45:26 UTC, bearophile wrote:
 It's a bad question.
Actually, Martin's question is a good one. Initializing a variable of type float via a literal or as conversion from string should be the same, exacly, always. Casting a float to double should be deterministic as well.
Not necessarily, particularly because any floating point operations done at compile time are generally done at much higher precision than those done at runtime. So, it's pretty trivial for very similar floating point operations to end up with slightly different results. In general, expecting any kind of exactness from floating point values is asking for trouble. Sure, they follow the rules that they have consistently, but there are so many numbers that aren't actually representable by a floating point value, the precisions vary just enough, and slightly different code paths can result in slightly different results that depending on floating point operations resulting in any kind of specific values except under very controlled circumstances just isn't going to work. - Jonathan M Davis
Jun 01 2014
prev sibling next sibling parent "Famous" <famous review_queue.org> writes:
float a = 1.234f;
float b = to!float("1.234");
assert (a == b);
assert (a == to!float("1.234")); // is allowed to fail due to 
constant folding
Jun 01 2014
prev sibling parent "Gary Willoughby" <dev nomad.so> writes:
I have a couple of functions that you may find useful for 
comparing floats.

https://github.com/nomad-software/dunit/blob/master/source/dunit/toolkit.d#L42
https://github.com/nomad-software/dunit/blob/master/source/dunit/toolkit.d#L134
Jun 02 2014