Walter Bright wrote:
Don wrote:
Walter Bright wrote:
Don wrote:
tango.math doesn't use the C library at all, except when inline asm
is unavailable. Of they differ from the C functions, in that none of
them set errno!
One really annoying issue still remains, though -- the floating
point flags in the CPU. They are entirely deterministic, but are
they considered to be part of the return value of the function? Or
would we allow them to be ignored?
A compiler could check the exception flags before allowing
memoisation. But one could also do the same thing for 'errno'.
Likewise, floating point rounding modes. Essentially, the floating
point status register is a hidden global variable, read from# and
written to during every floating point operation.
# - only the rounding mode and truncation affect the return value.
We could deal with it by regarding that as a whole-program setting.
But (depending on the CPU), the old exception flags generally get
ORed with the new exception flags.
Those are good points. I don't know what the answer is. My
inclination is to say if your program relies on changing the rounding
mode or fiddles with the exception flags, it's undefined behavior.
One form of error analysis is to run the program with different
rounding modes, and compare the results.
You can also use rounding modes to implement interval arithmetic, but
this would normally be restricted to low-level functions. The rounding
mode would not escape from those functions.
I normally use the exception flags for debugging.
Also, you can set the flags to allow any floating point function to
throw a hardware exception. It's difficult for any function using
floating point to claim to be nothrow under ANY circumstances; but
that's a horrible limitation.
I would say that is not supported by D. I've never heard of a use for
them.
What happens if a nothrow function throws an exception? IMHO a
satisfactory response would be to abort the program with an error
message/ drop you into a debugger -- anyway, that's the only thing I
use when running with FP exceptions enabled.
I'd be ok with saying throwing fp exceptions is a non-recoverable error,
like a seg fault or stack overflow, and is acceptable in a nothrow
function.
There are some important uses for catching fp exceptions, including one
which in the revised IEEE standard: the product of an array of doubles.
eg real.max * real.max * real.min * real.min == 1.0, but you get
overflows during the calculation.
What you do is enable floating point overflow and underflow as an
exception, and set up an exception handler inside that function; the
handler is essentially an inner function. Then you have a seperate
counter for how many times it has overflowed.
The thing to note about this is that although FP exceptions are used,
they never leave the function which created them, so there's no stack
unwinding, no destructors are called, etc.
All functionality would be preserved if it is a non-recoverable error to
transmit an fp exception across a function boundary (but possible to
catch the fp exception in the function which generated it).
But possibly such situations are so small in number that they can all be
put in the standard library.
I guess it's reasonable to argue that using the floating-point flags
is sufficiently hard-core that pure and nothrow should pretend that
they don't exist.
Still, some functions (especially correctly-rounded floating-point
i/o) go to a lot of trouble to support them. I have a suspicion that
it's not worth the effort.
So we have two options. One is to say that floating point arithmetic
cannot be made pure. The other is to ignore the problem (saying it's
undefined behavior).
It might not be a difficulty to ignore the problem. The flags are
getting very hard to use these days, since the x87 flags are different
from the SSE flags.
I would recommend stating that when calling a pure function, the state
of the FPU flags is implementation-dependent. Even better would be if we
can state that the built-in math functions will respect the flags,
despite being pure. They are very unlikely to be memoized since they are
so simple.