Remix.run Logo
thwarted 3 days ago

You still can't divide by zero, it just doesn't result in an error state that stops execution. The inf and NaN values are sentinel values that you still have to check for after the calculation to know if it went awry.

sixo 3 days ago | parent | next [-]

In the space of floats, you are dividing by zero. To map back to the space of numbers you have to check. It's nice, though; inf and NaN sentinels give you the behavior of a monadic `Result | Error` pipeline without having to wrap your numbers in another abstraction.

epcoa 3 days ago | parent | prev | next [-]

If dividing by zero has a well defined result that doesn’t abort execution what exactly does “can’t” even mean?

Operations on those sentinel values are also defined. This can affect when checking needs to be done in optimized code.

bee_rider 2 days ago | parent [-]

I believe divide-by-zero produces an exception. The machine can either be configured to mask that exception, or not.

Personally, I am lazy, so I don’t check the mxcsr register before I start running my programs. Maybe gcc does something by default, I don’t know. IMO legitimate division by zero is rare but not impossible, so if you do it, the onus is on you to make sure the flags are set up right.

epcoa 2 days ago | parent [-]

Correct, divide by zero is one of the original five defined IEEE754-1985 exception. But the default behavior then and now is to produce that defined result mentioned and continue execution with a flag set ("default non-stop"). Further conforming implementations also allow "raiseNoFlag".

It's well-defined is all that really matters AFAIC.

exDM69 2 days ago | parent | prev | next [-]

It's not always necessary to check for inf/NaN explicitly using isinf/isnan. Both inf and NaN are floating point values with well defined semantics.

I'll give two examples from a recent project where I very intentionally divided by zero. First one was about solving a zero in a derivative and check if it falls on 0..1 range. This exploits the fact that (x < NaN) is always false and comparisons with +/- inf behave as expected.

    float t = a / b; // might divide by zero. NaN if a and b == 0.0, +/- inf if b == 0.0
    if (t > 0.0 && t < 1.0) {
        // we don't get here if t is +/- inf or nan
        split_at(t); // do the thing
    }
The second one was similar, but clamping to 0..1 range using branchless simd min/max.

    f32x8 x = a / b; // might divide by zero
    return simd_min(simd_max(0.0, x), 1.0); // returns 0 for -inf or nan, 1 for +inf
In both of these cases, explicitly checking for division by zero or isinf/isnan would've been (worse than) useless because just using the inf/NaN values gave the correct answer for what comes next.
mike_ivanov 3 days ago | parent | prev | next [-]

This is the Result monad in practice. It allows you to postpone error handling until the computation is done.

wpollock 2 days ago | parent | prev | next [-]

It has always amused me that Integer division by 0 results in "floating point exception", but floating point division by 0.0 doesn't!

TehShrike 3 days ago | parent | prev [-]

You can divide by zero, but you mayn't.