May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | On Monday, 16 May 2016 at 07:16:41 UTC, Iain Buclaw wrote: > Feel free to give me any bug report or example. None that you've done so far in this thread relate to CTFE. Of course it is the same issue. Constant folding is "compile-time-function-evaluation", e.g. an expression is a function. Compiler internals does not change that. |
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | On 5/15/2016 11:48 PM, Iain Buclaw via Digitalmars-d wrote: > I can't think of a case of the top of my head where too much precision > caused a surprise. It's always when there is too little: > > https://issues.dlang.org/show_bug.cgi?id=16026 > > And I think the it's about that time of the year when I remind people > of gcc bug 323, and this lovely blog post. > > http://blog.jwhitham.org/2015/04/gcc-bug-323-journey-to-heart-of.html Manu, read those! More: https://randomascii.wordpress.com/2012/03/21/intermediate-floating-point-precision/ Ironically, this Microsoft article argues for greater precision for intermediate calculations, although Microsoft ditched 80 bits: https://msdn.microsoft.com/en-us/library/aa289157(VS.71).aspx |
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, 16 May 2016 at 06:46:59 UTC, Walter Bright wrote: > On 5/15/2016 10:37 PM, Manu via Digitalmars-d wrote: >> [...] > > Because, as I explained, that results in a 2x or more speed degradation (along with the loss of accuracy). > > >> [...] > > I used to do numerics work professionally. Most of the troubles I had were catastrophic loss of precision. Accumulated roundoff errors when doing numerical integration or matrix inversion are major problems. 80 bits helps dramatically with that. > A classic example... :-) http://www.stsci.edu/~lbradley/seminar/butterfly.html |
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 5/15/2016 11:14 PM, Ola Fosheim Grøstad wrote: > On Sunday, 15 May 2016 at 22:34:24 UTC, Walter Bright wrote: >> So far, nobody has posted a legitimate one (i.e. not contrived). > Oh, so comparing the exact same calculation, using the exact same binary > executable function, is not a legitimate algorithm. What algorithm relies on such? And as numerous links posted here show, it doesn't work reliably on just about any C/C++ compiler, either. If you're writing C++ code that relies on such, you're in for some tragic late night debugging sessions as Manu relates. > It is the most trivial > thing to do and rather common. It should be _very_ convincing. Post a link to some algorithm that does that. > But hey, here is another one: > > const real x = f(); > assert(0<=x && x<1); > x += 1; > > const float f32 = cast(float)(x); > const real residue = x - cast(real)f32; // ZERO!!!! > > output(dither(f32, residue)); // DITHERING IS FUBAR!!! Why would anyone dither based on the difference in precision of floats and doubles? Dithering is usually done based on different pixel densities. I'm sure you can (and did) write code contrived to show a difference. I asked for something different, though. |
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 16 May 2016 at 09:22, Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Monday, 16 May 2016 at 06:34:04 UTC, Iain Buclaw wrote:
>>
>> This says more about promoting float operations to double than anything else, and has nothing to do with CTFE.
>
>
> No, promoting to double is ok.
Your own example:
const float value = 1.30;
float copy = value;
assert(value*0.5 == copy*0.5);
Versus how you'd expect it to work.
const float value = 1.30;
float copy = value;
assert(cast(float)(value*0.5) == cast(float)(copy*0.5)); // Compare
as float, not double.
|
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 5/15/2016 11:00 PM, Ola Fosheim Grøstad wrote:
> On Sunday, 15 May 2016 at 22:49:27 UTC, Walter Bright wrote:
>> On 5/15/2016 2:06 PM, Ola Fosheim Grøstad wrote:
>>> The net result is that adding const/immutable to a type can change the semantics
>>> of the program entirely at the whim of the compiler implementor.
>>
>> C++ Standard allows the same increased precision, at the whim of the compiler
>> implementor, as quoted to you earlier.
>>
>> What your particular C++ compiler does is not relevant, as its behavior is not
>> required by the Standard.
>
> This is a crazy attitude to take. C++ provides means to detect that IEEE floats
> are being used in the standard library.
IEEE floats do not specify precision of intermediate results. A C/C++ compiler can be fully IEEE compliant and yet legitimately have increased precision for intermediate results.
I posted several links here pointing out this behavior in VC++ and g++. If your C++ numerics code didn't have a problem with it, it's likely you wrote the code in such a way that more accurate answers were not wrong.
FP behavior has complex trade-offs with speed, accuracy, compatibility, and size. There are no easy, obvious answers.
|
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Iain Buclaw | On Monday, 16 May 2016 at 07:54:32 UTC, Iain Buclaw wrote:
> On 16 May 2016 at 09:22, Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>> On Monday, 16 May 2016 at 06:34:04 UTC, Iain Buclaw wrote:
>>
>> No, promoting to double is ok.
>
> Your own example:
>
> const float value = 1.30;
> float copy = value;
> assert(value*0.5 == copy*0.5);
>
> Versus how you'd expect it to work.
>
> const float value = 1.30;
> float copy = value;
> assert(cast(float)(value*0.5) == cast(float)(copy*0.5)); // Compare
> as float, not double.
Promoting to double is sound. That is not the issue. Just replace the assert with a function like "check(real x, real y)". The programmer shouldn't have to look it up. Using "check(real x, real y)" should _not_ give a different result than using "check(float x, float y)". If you have implemented the former, you shouldn't have to implement the latter to get reasonable results.
Binding to "const float" or "float" should not change the outcome.
The problem is not the promotion, the problem is that you don't get the coercion to 32 bit floats where you requested it. This violates the principle of "least surprise".
|
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On 16.05.2016 00:34, Walter Bright wrote:
>
>> Yes. Algorithms can break because of it.
>
> So far, nobody has posted a legitimate one (i.e. not contrived).
My examples were not contrived. Manu's even less so.
What you call "illegitimate" are really just legitimate examples that you dismiss because they do not match your own specific experience. I think that's a little disrespectful.
|
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | On Monday, 16 May 2016 at 08:10:02 UTC, Walter Bright wrote: > IEEE floats do not specify precision of intermediate results. A C/C++ compiler can be fully IEEE compliant and yet legitimately have increased precision for intermediate results. IEEE 754-2008 provide language designers with features that enables predictable bit-accurate computations using floats for ordinary floating point operations. Only a subset of functions are implementation defined. This also has the advantage that you can do bit-level optimizations... including proving asserts to hold at compile time and "assume assert" optimizations that you are fond of ;-). But all the C/C++ compilers I have used support reliable coercion to 32 bit floats. > I posted several links here pointing out this behavior in VC++ and g++. If your C++ numerics code didn't have a problem with it, it's likely you wrote the code in such a way that more accurate answers were not wrong. I use clang++ only for production, and I don't really care how I wrote my code. What I do know is that in performance optimized code for 32 bit floats and simd I do rely upon unit-testing with guaranteed 32 bit floats. I absolutely do not want unit tests to execute with higher precision. I want it to break if 32 bit floats fails. If I cannot be sure of this I risk having libraries that enter infinite loops in production code. Keep in mind that even "simple" algorithms can get complex when you write for high performance. E.g. sound processing. So having predictable outcome is very much desirable. Such code also don't gain much from compiler optimizations... > FP behavior has complex trade-offs with speed, accuracy, compatibility, and size. There are no easy, obvious answers. Well, but randomly increasing precision is always a bad idea when you deal with related computations, like time series. It is better to have consistent noise/bias than random noise/bias. Also, in the case of audio processing it is not unheard of to exploit the 24 bit mantissa and the specifics of the IEEE 32 bit floating point format. Now, I don't object to having a "real" type that works the way you want. What I object to is having float and double act that way. Or rather, not having strict ieee32 and ieee64 types. |
May 16, 2016 Re: Always false float comparisons | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ola Fosheim Grøstad | On 16 May 2016 at 10:25, Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Monday, 16 May 2016 at 07:54:32 UTC, Iain Buclaw wrote:
>>
>> On 16 May 2016 at 09:22, Ola Fosheim Grøstad via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>>
>>> On Monday, 16 May 2016 at 06:34:04 UTC, Iain Buclaw wrote:
>>>
>>> No, promoting to double is ok.
>>
>>
>> Your own example:
>>
>> const float value = 1.30;
>> float copy = value;
>> assert(value*0.5 == copy*0.5);
>>
>> Versus how you'd expect it to work.
>>
>> const float value = 1.30;
>> float copy = value;
>> assert(cast(float)(value*0.5) == cast(float)(copy*0.5)); // Compare
>> as float, not double.
>
>
> Promoting to double is sound. That is not the issue. Just replace the assert with a function like "check(real x, real y)". The programmer shouldn't have to look it up. Using "check(real x, real y)" should _not_ give a different result than using "check(float x, float y)". If you have implemented the former, you shouldn't have to implement the latter to get reasonable results.
>
> Binding to "const float" or "float" should not change the outcome.
>
> The problem is not the promotion, the problem is that you don't get the coercion to 32 bit floats where you requested it. This violates the principle of "least surprise".
>
But you *didn't* request coercion to 32 bit floats. Otherwise you would have used 1.30f.
|
Copyright © 1999-2021 by the D Language Foundation