Jump to page: 1 2
Thread overview
D float types operations vs C++ ones
Dec 17, 2015
drug
Dec 17, 2015
Andrea Fontana
Dec 17, 2015
drug
Dec 17, 2015
Nicholas Wilson
Dec 17, 2015
drug
Dec 18, 2015
Nicholas Wilson
Dec 18, 2015
drug
Dec 18, 2015
Ola Fosheim Gr
Dec 18, 2015
Ali Çehreli
Dec 17, 2015
anonymous
Dec 17, 2015
Ali Çehreli
Dec 17, 2015
Guillaume Piolat
December 17, 2015
I have two implementation of the same algorithm - D and C++ (that is port of D version). I assume that running these implementations on the same data should give the same results from both. But with some data the results differ (5th decimal digit after point). For my purpose it isn't important and I can ignore this difference. But I'd like to have the same results totally (I mean bit to bit) to easy maintanence of the implementations. Question is - can I rely that D and C++ float types operations should give the same result because D and C are similar or no and I should use more portable way and compare floats with some epsilon?
December 17, 2015
On Thursday, 17 December 2015 at 11:50:02 UTC, drug wrote:
> I have two implementation of the same algorithm - D and C++ (that is port of D version). I assume that running these implementations on the same data should give the same results from both. But with some data the results differ (5th decimal digit after point). For my purpose it isn't important and I can ignore this difference. But I'd like to have the same results totally (I mean bit to bit) to easy maintanence of the implementations. Question is - can I rely that D and C++ float types operations should give the same result because D and C are similar or no and I should use more portable way and compare floats with some epsilon?

You should publish some code to check...
December 17, 2015
On 17.12.2015 14:52, Andrea Fontana wrote:
>
> You should publish some code to check...
Too much code to public - operations are simple, but there are many branches and reducing may take much time . In fact I asked to understand _in general_ if it worth diving into code to find the source of the difference or take it easy and go on...
If D and C++ use the same things to process float types then it worth to dive, but if there is some issues, then it doesn't.
December 17, 2015
On Thursday, 17 December 2015 at 11:58:35 UTC, drug wrote:
> On 17.12.2015 14:52, Andrea Fontana wrote:
>>
>> You should publish some code to check...
> Too much code to public - operations are simple, but there are many branches and reducing may take much time . In fact I asked to understand _in general_ if it worth diving into code to find the source of the difference or take it easy and go on...
> If D and C++ use the same things to process float types then it worth to dive, but if there is some issues, then it doesn't.

Yes the float types are the same. floats doubles are identical long double == real ( at least for x86)

The only difference is that float are default initialised to NaN in D.
The sources of difference are likely to occur from
- const folding (varying by compiler e.g. gcc uses libgmp for high precision floating point for constant folding where as other compliers may not)
- type promotions and truncations
I.e.
double a = ... ,b = ... ;
float c = a+b;
float d = cast(float)a + cast(float)b;

c is unlikely to be bit for bit equal to d.

floating point operations are NOT commutative nor are they distributive. Order of operations does matter.
i.e. a+(b+c) !=(a+b) +c and a*(b+c) != a*b + a*c (!= means not necessarily equal)

you should always compare floats for equality with an epsilon (unless 0.0 +-inf )

December 17, 2015
On 17.12.2015 16:09, Nicholas Wilson wrote:
>
> Yes the float types are the same. floats doubles are identical long
> double == real ( at least for x86)
>
> The only difference is that float are default initialised to NaN in D.
> The sources of difference are likely to occur from
> - const folding (varying by compiler e.g. gcc uses libgmp for high
> precision floating point for constant folding where as other compliers
> may not)
> - type promotions and truncations
> I.e.
> double a = ... ,b = ... ;
> float c = a+b;
> float d = cast(float)a + cast(float)b;
>
> c is unlikely to be bit for bit equal to d.
>
> floating point operations are NOT commutative nor are they distributive.
> Order of operations does matter.
> i.e. a+(b+c) !=(a+b) +c and a*(b+c) != a*b + a*c (!= means not
> necessarily equal)
>
> you should always compare floats for equality with an epsilon (unless
> 0.0 +-inf )
>
Thanks for answer. My C++ version is tracing D version so commutativity and distributivity aren't requred because order of operations is the same (I guess so at least), so I hoped for bit to bit equality (it simplifies comparing serialized data). But I found that error between D and C++ versions grows if more data processed so I should investigate it anyway.
December 17, 2015
On 17.12.2015 12:50, drug wrote:
> I have two implementation of the same algorithm - D and C++ (that is
> port of D version). I assume that running these implementations on the
> same data should give the same results from both. But with some data the
> results differ (5th decimal digit after point). For my purpose it isn't
> important and I can ignore this difference. But I'd like to have the
> same results totally (I mean bit to bit) to easy maintanence of the
> implementations. Question is - can I rely that D and C++ float types
> operations should give the same result because D and C are similar or no
> and I should use more portable way and compare floats with some epsilon?

D explicitly allows compilers to use greater precision in calculations than the involved types have [1]. For example, an expression involving `float`s may be evaluated at double or real precision.

That means, you cannot rely on getting the same results even when looking only at D. Compiler A may produce higher precision code than compiler B; or machine X offers a larger maximum precision than machine Y (and the compiler makes use of it).


[1] http://dlang.org/spec/float.html
December 17, 2015
On 12/17/2015 03:50 AM, drug wrote:

> D and C++ [...] But with some data the results differ

You may have similar results between two C and two C++ compilers, even between two different versions of the same compiler.

In addition to possible reasons that has already been mentioned, note that function arguments can be evaluated in any order by compilers of C and C++ (D uses left-to-right). For example, for the following expression, gcc evaluates bar() first but dmd (and other D compilers) evaluate foo() first:

    h(foo(), bar())

If foo() and bar() have side effects on floating values, those values can be observed differently.

Ali

December 17, 2015
On Thursday, 17 December 2015 at 11:50:02 UTC, drug wrote:
> I have two implementation of the same algorithm - D and C++ (that is port of D version). I assume that running these implementations on the same data should give the same results from both. But with some data the results differ (5th decimal digit after point). For my purpose it isn't important and I can ignore this difference. But I'd like to have the same results totally (I mean bit to bit) to easy maintanence of the implementations. Question is - can I rely that D and C++ float types operations should give the same result because D and C are similar or no and I should use more portable way and compare floats with some epsilon?

If you aim for float reproducibility, you will get trouble in 32-bit vs 64-bit mode, depending on whether the FPU is used or not. The FPU promotes to 80-bits code that uses float or double, and may get you more precision thus changing the results.
December 18, 2015
On Thursday, 17 December 2015 at 13:30:11 UTC, drug wrote:
> On 17.12.2015 16:09, Nicholas Wilson wrote:
>>[...]
> Thanks for answer. My C++ version is tracing D version so commutativity and distributivity aren't requred because order of operations is the same (I guess so at least), so I hoped for bit to bit equality (it simplifies comparing serialized data). But I found that error between D and C++ versions grows if more data processed so I should investigate it anyway.

What I mean about order of operations is that if you go
 a = b*a+c*c + e;
the compiler is free to rewrite that as
float __tmp0 = a*b;
float __tmp1 = c*c;
and then do either of
float __tmp2 = __tmp0+__tmp1;
a = __tmp2 + e;
OR
float __tmp2 = __tmp0+e;
a = __tmp2+__tmp1;
December 18, 2015
On 18.12.2015 05:58, Nicholas Wilson wrote:
> On Thursday, 17 December 2015 at 13:30:11 UTC, drug wrote:
>> On 17.12.2015 16:09, Nicholas Wilson wrote:
>>> [...]
>> Thanks for answer. My C++ version is tracing D version so
>> commutativity and distributivity aren't requred because order of
>> operations is the same (I guess so at least), so I hoped for bit to
>> bit equality (it simplifies comparing serialized data). But I found
>> that error between D and C++ versions grows if more data processed so
>> I should investigate it anyway.
>
> What I mean about order of operations is that if you go
>   a = b*a+c*c + e;
> the compiler is free to rewrite that as
> float __tmp0 = a*b;
> float __tmp1 = c*c;
> and then do either of
> float __tmp2 = __tmp0+__tmp1;
> a = __tmp2 + e;
> OR
> float __tmp2 = __tmp0+e;
> a = __tmp2+__tmp1;

I see, thanks to all!
« First   ‹ Prev
1 2