Jump to page: 1 2
Thread overview
Bug?
Oct 23, 2014
deed
Oct 23, 2014
deed
Oct 23, 2014
deed
Oct 23, 2014
deed
Oct 24, 2014
deed
Oct 23, 2014
H. S. Teoh
Oct 23, 2014
deed
Oct 23, 2014
deed
Oct 23, 2014
anonymous
Oct 23, 2014
anonymous
Oct 24, 2014
deed
Oct 23, 2014
deed
October 23, 2014
// DMD v2.066.0
// All asserts pass (!)

import std.math : sin, cos, tan, asin, acos, atan,
                  sinh, cosh, tanh, asinh, acosh, atanh;

alias F = double;

immutable F a = 3, b = 5;

F fmul (F a) pure { return a * b;  }
F fsin (F a) pure { return sin(a); }

struct Smul { F value; this (F a) { value = a * b;  } alias value this; }
struct Ssin { F value; this (F a) { value = sin(a); } alias value this; }

F ans_mul = fmul(a);
F ans_sin = fsin(a);

Smul smul = Smul(a);
Ssin ssin = Ssin(a);


// All combinations of a*b, fmul(a), Smul(a), ans_mul and smul pass
// the equality test. E.g.:
assert (a*b == a*b);
assert (a*b == fmul(a));
assert (a*b == Smul(a));
assert (a*b == ans_mul);
assert (a*b == smul);

assert (fmul(a) == fmul(a));
assert (fmul(a) == Smul(a));
assert (fmul(a) == ans_mul);
assert (fmul(a) == smul);


// However, for std.math.sin it's different:
assert (sin(a) == fsin(a));        // But not in 2.065
assert (sin(a) != Ssin(a));        // ?
assert (sin(a) != ans_sin);        // ?
assert (sin(a) != ssin);           // ?

assert (fsin(a) != fsin(a));       // ?
assert (fsin(a) != Ssin(a));       // ?
assert (fsin(a) != ans_sin);       // ?
assert (fsin(a) != ssin);          // ?

// Same goes for cos, tan, asin, acos, atan:
F fcos  (F a) { return cos(a);  }
F ftan  (F a) { return tan(a);  }
F fasin (F a) { return asin(a); }
F facos (F a) { return acos(a); }
F fatan (F a) { return atan(a); }

assert (fcos(a)  != fcos(a));      // ?
assert (ftan(a)  != ftan(a));      // ?
assert (fasin(a) != fasin(a));     // ?
assert (facos(a) != facos(a));     // ?
assert (fatan(a) != fatan(a));     // ?


// And then it goes only downhill for
// sinh, cosh, tanh, asinh, acosh and atanh:
assert (sinh(a)    != sinh(a));    // ?
assert (cosh(a)    != cosh(a));    // ?
assert (tanh(a)    != tanh(a));    // ?
assert (asinh(a)   != asinh(a));   // ?
assert (acosh(a)   != acosh(a));   // ?
assert (atanh(0.5) != atanh(0.5)); // ?

--

Why bother?

import std.algorithm : max;

F fun (F a, F b) { return max(a,b) + 1.; }
unittest { assert (gun(1, 2) == gun(2, 1)); } // Passes

F pun (F a, F b) { return sin(max(a,b)); }
unittest { assert (fun(1, 2) == fun(2, 1)); } // Fails
October 23, 2014
> --
>
> Why bother?
>
> import std.algorithm : max;
>
> F fun (F a, F b) { return max(a,b) + 1.; }
> unittest { assert (gun(1, 2) == gun(2, 1)); } // Passes
>
> F pun (F a, F b) { return sin(max(a,b)); }
> unittest { assert (fun(1, 2) == fun(2, 1)); } // Fails

// Fun, gun, pun...
unittest { assert (fun(1, 2) == fun(2, 1)); } // Passes
unittest { assert (pun(1, 2) == pun(2, 1)); } // Fails
October 23, 2014
On 10/23/14 1:08 PM, deed wrote:
> // DMD v2.066.0
> // All asserts pass (!)

Using equality is not a good idea with floating point.

The compiler will on a whim, or depending on whether it can inline or not, use higher precision floats, changing the outcome slightly.

I cannot say for certain whether this explains all the issues you have, the very last one seems troubling to me at least.

-Steve
October 23, 2014
> assert (fasin(a) != fasin(a));     // ?
> assert (facos(a) != facos(a));     // ?

Too quick there.. But:

assert (fasin(0.5) != fasin(0.5));   // ?
assert (facos(0.5) != facos(0.5));   // ?
October 23, 2014
> Using equality is not a good idea with floating point.
>
> The compiler will on a whim, or depending on whether it can inline or not, use higher precision floats, changing the outcome slightly.
>
> I cannot say for certain whether this explains all the issues you have, the very last one seems troubling to me at least.
>
> -Steve

Sure, in many cases it's a bad idea. While I understand that sin(PI) != 0.0, but approxEqual(sin(PI), 0.0) == true, I would expect the following to pass:

assert (0.0 == 0.0);
assert (1.2345 == 1.2345);

F a = 1.2345, b = 9.8765;

assert (a+b == b+a);
assert (a*b == b*a);

F fun (F a) pure;

assert (fun(a) + fun(b) == fun(b) + fun(a));
assert (fun(a) * fun(b) == fun(b) * fun(a));

auto a = fun(100);
auto b = fun(100);

assert (a == b);
assert (fun(100) == fun(100));


Now, if fun's body is { return sin(a); }, the behaviour changes to:

auto c = fun(100);
auto d = fun(100);

assert (c == d);              // Ok
assert (fun(100) != fun(100)) // I have a hard time understanding
                              // this is correct behaviour
October 23, 2014
On 10/23/14 2:18 PM, deed wrote:
>> Using equality is not a good idea with floating point.
>>
>> The compiler will on a whim, or depending on whether it can inline or
>> not, use higher precision floats, changing the outcome slightly.
>>
>> I cannot say for certain whether this explains all the issues you
>> have, the very last one seems troubling to me at least.
>>
>
> Sure, in many cases it's a bad idea. While I understand that sin(PI) !=
> 0.0, but approxEqual(sin(PI), 0.0) == true, I would expect the following
> to pass:
>
> assert (0.0 == 0.0);
> assert (1.2345 == 1.2345);
> F a = 1.2345, b = 9.8765;
>
> assert (a+b == b+a);
> assert (a*b == b*a);

None of these fail on my system

> F fun (F a) pure;
>
> assert (fun(a) + fun(b) == fun(b) + fun(a));
> assert (fun(a) * fun(b) == fun(b) * fun(a));
>
> auto a = fun(100);
> auto b = fun(100);
>
> assert (a == b);
> assert (fun(100) == fun(100));
>

Not sure what body of fun is, so I cannot test this.

>
> Now, if fun's body is { return sin(a); }, the behaviour changes to:
>
> auto c = fun(100);
> auto d = fun(100);
>
> assert (c == d);              // Ok
> assert (fun(100) != fun(100)) // I have a hard time understanding
>                                // this is correct behaviour

Tried that out, it does not fail on my machine. Can you be more specific on your testing? What compiler/platform? Stock compiler, or did you build it yourself?

-Steve
October 23, 2014
On Thursday, 23 October 2014 at 18:26:53 UTC, Steven Schveighoffer wrote:
> On 10/23/14 2:18 PM, deed wrote:
>>> Using equality is not a good idea with floating point.
>>>
>>> The compiler will on a whim, or depending on whether it can inline or
>>> not, use higher precision floats, changing the outcome slightly.
>>>
>>> I cannot say for certain whether this explains all the issues you
>>> have, the very last one seems troubling to me at least.
>>>
>>
>> Sure, in many cases it's a bad idea. While I understand that sin(PI) !=
>> 0.0, but approxEqual(sin(PI), 0.0) == true, I would expect the following
>> to pass:
>>
>> assert (0.0 == 0.0);
>> assert (1.2345 == 1.2345);
>> F a = 1.2345, b = 9.8765;
>>
>> assert (a+b == b+a);
>> assert (a*b == b*a);
>
> None of these fail on my system

Same for me, that's the point; it's perfectly valid to compare floating points.

>
>> F fun (F a) pure;
>>
>> assert (fun(a) + fun(b) == fun(b) + fun(a));
>> assert (fun(a) * fun(b) == fun(b) * fun(a));
>>
>> auto a = fun(100);
>> auto b = fun(100);
>>
>> assert (a == b);
>> assert (fun(100) == fun(100));
>>
>
> Not sure what body of fun is, so I cannot test this.

Could be anything taking a floating point and returning a floating point.
You would expect to get the same back for the same input, especially when
it's pure. If so, the asserts above are expected to hold.


>> Now, if fun's body is { return sin(a); }, the behaviour changes to:
>>
>> auto c = fun(100);
>> auto d = fun(100);
>>
>> assert (c == d);              // Ok
>> assert (fun(100) != fun(100)) // I have a hard time understanding
>>                               // this is correct behaviour
>
> Tried that out, it does not fail on my machine. Can you be more specific on your testing? What compiler/platform? Stock compiler, or did you build it yourself?

Right. It doesn't fail, and that's the problem.

assert (fun(100) == fun(100));  // Should pass, and does with
                                // body { return a + 1; }
                                // but not with
                                // body { return sin(a); }
assert (fun(100) != fun(100));  // Shouldn't pass, but passes with
                                // body { return sin(a);}

Compiler: DMD32 D Compiler v2.066.0

Also tried dpaste.dzfl.pl with 2.065.0 and DMD 2.x Git (cfb5842b49),
which had slightly different behaviour; more of the sin tests which should
pass in my opinion did with those two. Hence, it appears to be regressions.

>
> -Steve

October 23, 2014
On Thu, Oct 23, 2014 at 02:26:52PM -0400, Steven Schveighoffer via Digitalmars-d-learn wrote:
> On 10/23/14 2:18 PM, deed wrote:
[...]
> >Now, if fun's body is { return sin(a); }, the behaviour changes to:
> >
> >auto c = fun(100);
> >auto d = fun(100);
> >
> >assert (c == d);              // Ok
> >assert (fun(100) != fun(100)) // I have a hard time understanding
> >                               // this is correct behaviour
> 
> Tried that out, it does not fail on my machine. Can you be more specific on your testing? What compiler/platform? Stock compiler, or did you build it yourself?
[...]

A similar problem was recently (about 2-3 weeks ago IIRC) seen in one of the Phobos PR's. It appears to be related to the autoextension of float to double (or double to real, I forget which) in certain contexts on Windows.  @deed Could you please try to reduce the failing test to a minimal code example, and post a disassembly of the concerned function(s)? This could either be a subtle codegen bug, or something more fundamentally broken with 80-bit real support.


T

-- 
Making non-nullable pointers is just plugging one hole in a cheese grater. -- Walter Bright
October 23, 2014
> A similar problem was recently (about 2-3 weeks ago IIRC) seen in one of
> the Phobos PR's. It appears to be related to the autoextension of float
> to double (or double to real, I forget which) in certain contexts on
> Windows.  @deed Could you please try to reduce the failing test to a
> minimal code example, and post a disassembly of the concerned
> function(s)? This could either be a subtle codegen bug, or something
> more fundamentally broken with 80-bit real support.
>
>
> T

Some testing can be found on http://dpaste.dzfl.pl/5f55f4152aa8
for both Windows and Linux. This just illustrates the sin function.
October 23, 2014
> Some testing can be found on http://dpaste.dzfl.pl/5f55f4152aa8
> for both Windows and Linux. This just illustrates the sin function.

Replacing double with real makes everything pass on Linux Mint 16 with -m32 and -m64. Replacing double with float seems to give the same problems as before, but hasn't been extensively tested. It seems very likely to be a conversion issue, as H. S. Teoh mentioned.
« First   ‹ Prev
1 2