August 25, 2022

On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:

>

On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:

>

On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:

>

A better option would be to throw an exception if NaN is used in an operation.

-Steve

IMHO this is the better solution and not even an exception, but Error.

As soon as you have any NaN values that are being used your program is effectively useless and broken.

I think as soon as any variable becomes NaN it should throw, not just when an operation happens.

Basically I think it should throw when either of these conditions holds true:

  • A value was initialized as NaN and used in an operation
  • A value was set to NaN outside of initialization
  • NaN is returned from a function (Even if not set to a variable or anything.)

I'm shocked by this idea. What if I want high performance nothrow FP code ?

It could be optimized away in release code and/or be optional to disable (should be enabled by default.)

August 25, 2022

On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:

>

On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:

>

On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:

>

A better option would be to throw an exception if NaN is used in an operation.

-Steve

IMHO this is the better solution and not even an exception, but Error.

As soon as you have any NaN values that are being used your program is effectively useless and broken.

I think as soon as any variable becomes NaN it should throw, not just when an operation happens.

Basically I think it should throw when either of these conditions holds true:

  • A value was initialized as NaN and used in an operation
  • A value was set to NaN outside of initialization
  • NaN is returned from a function (Even if not set to a variable or anything.)

I'm shocked by this idea. What if I want high performance nothrow FP code ?

Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.

August 25, 2022

On Thursday, 25 August 2022 at 11:38:22 UTC, max haughton wrote:

>

On Thursday, 25 August 2022 at 09:07:54 UTC, user1234 wrote:

>

On Thursday, 25 August 2022 at 07:15:58 UTC, bauss wrote:

>

On Thursday, 25 August 2022 at 03:08:54 UTC, Steven Schveighoffer wrote:

>

A better option would be to throw an exception if NaN is used in an operation.

-Steve

IMHO this is the better solution and not even an exception, but Error.

As soon as you have any NaN values that are being used your program is effectively useless and broken.

I think as soon as any variable becomes NaN it should throw, not just when an operation happens.

Basically I think it should throw when either of these conditions holds true:

  • A value was initialized as NaN and used in an operation
  • A value was set to NaN outside of initialization
  • NaN is returned from a function (Even if not set to a variable or anything.)

I'm shocked by this idea. What if I want high performance nothrow FP code ?

Turn the check off. The hardware basically already supports doing this (NaNs don't have to be quiet) but almost no one uses it - it's quite hard to trigger at all on a modern system.

Looks like D allows you to enable floating-point exceptions using the std.math.hardware.FloatingPointControl interface.

Of course, these are hardware exceptions, so you will get SIGFPE rather than a thrown Error with a backtrace. To turn them into D Errors you'd need to set up a signal handler, like how etc.linux.memoryerror does it (or whatever the equivalent is on Windows).

August 25, 2022

On Thursday, 25 August 2022 at 14:34:52 UTC, Paul Backus wrote:

>

Looks like D allows you to enable floating-point exceptions using the std.math.hardware.FloatingPointControl interface.

Of course, these are hardware exceptions, so you will get SIGFPE rather than a thrown Error with a backtrace. To turn them into D Errors you'd need to set up a signal handler, like how etc.linux.memoryerror does it (or whatever the equivalent is on Windows).

Unfortunately, it looks like this will not work in practice, because the "invalid" floating-point exception is raised only when a NaN is created, not when it's propagated. Since the initial NaN values of default-initialized float/double variables are created at compile time, not runtime, no exception is ever raised for them.

Example program:

import std.math.hardware;

float div(float x, float y)
{
    return x / y;
}

void main()
{
    FloatingPointControl fpctrl;
    fpctrl.enableExceptions(FloatingPointControl.severeExceptions);

    float f = float.nan; // ok - no exception
    float g = div(0.0f, 0.0f); // crashes with SIGFPE
}
August 25, 2022

On Thursday, 25 August 2022 at 16:06:43 UTC, Paul Backus wrote:

>

Unfortunately, it looks like this will not work in practice, because the "invalid" floating-point exception is raised only when a NaN is created, not when it's propagated. Since the initial NaN values of default-initialized float/double variables are created at compile time, not runtime, no exception is ever raised for them.

Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way.

This kind of makes another motivation to let floats default to zero, if this is correct.

August 25, 2022
On 8/22/2022 6:16 PM, Steven Schveighoffer wrote:
>> The point is, since 0.0 is a common value for a floating point value to be, just when does it become obvious that it is wrong? Are you really going to notice if your computation is 5% off? Isn't it a *lot* more obvious that it is wrong if it is NaN?
> 
> This is a highly dependent situation. It could be 0, which is 100% off. It could be 5%. It could be 0.0001% off, which might actually not be a problem that is noticed.

Of course. And NaN is always wrong.


> If instead it printed NaN I would have ignored that price, and just put 0 in *at a later calculation* to prevent errors showing up in the final proposal. Then I would have missed the fudge factor someone sneaked in.

If you ignore the NaN value, you can hardly then blame it for missing the fudge factor.


> But I think in terms of *frequency*, a default value of 0 for a float that isn't explicitly initialized is 99% of the time correct, which means you will have *less of these problems to find*.

See my other post about having code work by happenstance 99% of the time being not what D is about.


>> 0.0 is hardly a rare value, even in correct calculations. NaN is always wrong.
> 
> It's not rare because it's a very very common initial value.

0.0 a commonplace value everywhere.


>> NaN propagates. 0.0 does not.
> Someone has to look at it, to "obviously" see that it's wrong.

If you never look at the output, no bugs will be noticed in it anyway.


> Something with semantic capabilities has to be used to prove it's not set before being used. Is there anything besides the compiler front end that can do this?

You need data flow analysis for that. I didn't put DFA in the front end because that makes it slow for little benefit.

August 25, 2022
On 8/24/2022 6:30 PM, Adam D Ruppe wrote:
> On Thursday, 25 August 2022 at 01:19:55 UTC, Walter Bright wrote:
>> If the hydraulic lines are hooked to the wrong ports, the airplane will be uncontrollable and will crash.
> 
> oh ye of little faith!
> 
> I read about a story where this happened. The pilots quickly found the plane uncontrollable to the point where they asked for vectors to ditch into the ocean so the crash wouldn't hurt anybody on the ground at least... but they couldn't even control it well enough to successfully navigate out there. They kept flying in random directions and ended up over ground again, but had enough altitude to keep trying again.
> 
> After quite some time though, they actually recognized the "random, uncontrollable" aircraft actually was responding to their inputs in a predictable pattern, it was just all messed up. As they figured it out and learned how to fly with these bizarro controls, their initial panic subsided and they were able to successfully return to the airport for a safe landing!
> 
> (of course there are other similar stories without the happy ending so your point is good, but i like this story)

The cases I've heard all resulted in a smoking hole in the ground just past the end of the runway. When the airplane does the wrong thing as the result of a control input, the natural pilot reflex is to push it harder, not try the other way. When you're a few feet off the ground, that means smacking it hard into the ground.

Your anecdote was surely not the elevators or ailerons. It might have been the rudder, where the pilots would have more of a chance.
August 25, 2022
On 8/24/2022 8:08 PM, Steven Schveighoffer wrote:
> NaN fails at that. It's silently swallowed by just about everything. Only when a human looks at some printout does it become obvious.

Seriously, *when* is 0 better than that?

If you aren't looking at your output, then why are you calculating the value?
August 25, 2022
On 8/25/2022 9:16 AM, IGotD- wrote:
> Which is strange because HW wise it is trivial to check if the result is NaN. To check that NaN is not based on input is of course more complicated. Then again an x86 complicated in an unhealthy way.
> 
> This kind of makes another motivation to let floats default to zero, if this is correct.


There's nothing to be afraid of in getting a NaN in the output. One should be glad, because then one *knows* there's a bug.

This thread reminds me of the threads about assert, and the contention that the program should continue after a failed assert.

1. It is not better to pretend a program is working when it is not.

2. It is not better for a language to guess at what the programmer must have meant, even if the guess is correct 99% of the time.

3. It is not better to never check the output of the program for correctness.

D is a tool for helping the programmer create correct, robust, and bug-free programs.
August 25, 2022
On 8/21/2022 2:00 AM, Dom Disc wrote:
> It's no problem to implement saveint so, that int.min stays at that value for all operations (except direct assignment). Ok, as library this may cost a little performance, but I think it's worth it.

This may be what you're looking for:

https://dlang.org/phobos/std_checkedint.html