I want to do some numerical calculations (probably using f64
, but maybe I’ll be generic later). Some of my calculation may be subject to numerical instability, and I might run into
- division by zero
- square root of negative number
- sine of infinity
- logarithm of zero
- logarithm of negative number
- …
Now reading the Zig documentation on Illegal Behavior, I read that
is illegal behavior. I also read that:
Some Illegal Behavior is safety-checked: […] All other Illegal Behavior is unchecked, […]
Some questions:
- So is division by zero safety-checked or not? And how can I know?
- Is division by zero also illegal behavior for floating point numbers, or just for integers?
- If yes, does floating point division-by-zero differ from integer division-by-zero with regard to safety checking?
- Are there differences between
comptime
and runtime?
Experiments with zig version 0.15.0-dev.936+fc2c1883b
on FreeBSD, all in Debug
mode:
std.debug.print("{}\n", .{1.0 / 0.0});
⇒ error: division by zero here causes illegal behavior
But:
for (0..3) |i| {
const f: f64 = 1 - @as(f64, @floatFromInt(i));
std.debug.print("{}\n", .{1.0 / f});
}
Results in:
1e0
inf
-1e0
Note that the documentation of @setFloatMode
says:
@setFloatMode(comptime mode: FloatMode) void
Changes the current scope’s rules about how floating point operations are defined.
Strict
(default) - Floating point operations follow strict IEEE compliance.- […]
Now IEEE says that 1.0/0.0
is inf
by default, right? (But maybe IEEE allows optional exceptions?)
Also I wonder: Disregarding what Zig does now, would it be good to treat floating point division-by-zero as Illegal Behavior?
If yes, then what about:
sqrt(-0.00001)
ln(0)
ln(-1)
- …
And side question: Is there a reason why there is no natural logarithm (of a number x
, not of 1+x
or gamma(x)
) in std.math
?