#### 4.8.4 Floating-Point Exceptions

In IEEE 754-2008, floating-point operations such as arithmetic may raise exceptions. This sets a flag in the floating-point environment that is maintained until it is cleared. Many machines can also be configured to trap on exceptions, which in Scheme leads to signalling a condition. (Not all CPUs support trapping exceptions — for example, most ARMv8 CPUs do not.) In the default environment, no exceptions are trapped.

Floating-point exceptions and sets of floating-point exceptions are represented by small integers, whose interpretation is machine-dependent — for example, the invalid-operation exception may be represented differently on PowerPC and AMD x86-64 CPUs. The number for a floating-point exception is the same as the number for a set of exceptions containing only that one; the bitwise-AND of two sets is their intersection, the bitwise-IOR is their union, etc. The procedures `flo:exceptions->names` and `flo:names->exceptions` convert between machine-dependent integer representations and machine-independent lists of human-readable symbols.

The following exceptions are recognized by MIT/GNU Scheme:

inexact-result ¶

  Raised when the result of a floating-point computation is not a floating-point number and therefore must be rounded.

  The inexact-result exception is never trappable in MIT/GNU Scheme.

underflow ¶

  Raised when the result of a floating-point computation is too small in magnitude to be represented by a normal floating-point number, and is therefore rounded to a subnormal or zero.

overflow ¶

  Raised when the result of a floating-point computation is too large in magnitude to be represented by a floating-point number, and is therefore rounded to infinity.

divide-by-zero ¶

  Raised on division of a nonzero finite real number by a zero real number, or logarithm of zero, or other operation that has an unbounded limit at a point like division by a divisor approaching zero.

invalid-operation ¶

  Raised when the input to a floating-point computation is nonsensical, such as division of zero by zero, or real logarithm of a negative number. The result of an invalid-operation is a NaN. Also raised when the input to a floating-point operation is a signalling NaN, but not for a quiet NaN.

subnormal-operand ¶

  Raised when an operand in a floating-point operation is subnormal.

  (This is not a standard IEEE 754-2008 exception. It is supported by Intel CPUs.)

procedure: flo:supported-exceptions ¶

  Returns the set of exceptions that are supported on the current machine.

procedure: flo:trappable-exceptions ¶

  Returns the set of exceptions that can be trapped on the current machine. This is usually the same as the supported exceptions, except for inexact-result, which is never trappable in MIT/GNU Scheme.

procedure: flo:exception:divide-by-zero ¶
procedure: flo:exception:inexact-result ¶
procedure: flo:exception:invalid-operation ¶
procedure: flo:exception:overflow ¶
procedure: flo:exception:subnormal-operand ¶
procedure: flo:exception:underflow ¶

  Returns the specified floating-point exception number. On machines that do not support a particular exception, the corresponding procedure simply returns `0`.

procedure: flo:exceptions->names excepts ¶
procedure: flo:names->exceptions list ¶

  These procedures convert between a machine-dependent small integer representation of a set of exceptions, and a representation of a set of exceptions by a list of human-readable symbols naming them.

      (flo:preserving-environment
       (lambda ()
         (flo:clear-exceptions! (flo:supported-exceptions))
         (flo:/ (identity-procedure 1.) 0.)
         (flo:exceptions->names
          (flo:test-exceptions (flo:supported-exceptions)))))
                                     ⇒  (divide-by-zero)

procedure: flo:test-exceptions excepts ¶

  Returns the set of exceptions in excepts that are currently raised.

  In the default environment, the result is indeterminate, and may be affected by floating-point operations in other threads.

procedure: flo:clear-exceptions! excepts ¶
procedure: flo:raise-exceptions! excepts ¶

  Clears or raises the exceptions in excepts, entering a per-thread environment. Other exceptions are unaffected.

procedure: flo:save-exception-flags ¶
procedure: flo:restore-exception-flags! exceptflags ¶
procedure: flo:test-exception-flags exceptflags excepts ¶

  `Flo:save-exception-flags` returns a machine-dependent representation of the currently trapped and raised exceptions. `Flo:restore-exception-flags!` restores it, entering a per-thread environment. `Flo:test-exception-flags` returns the set of exceptions in excepts that are raised in exceptflags.

  Exceptflags is not the same as a set of exceptions. It is opaque and machine-dependent and should not be used except with `flo:restore-exception-flags!` and `flo:test-exception-flags`.

  Bug: `Flo:test-exception-flags` is unimplemented.

procedure: flo:have-trap-enable/disable? ¶

  Returns true if trapping floating-point exceptions is supported on this machine.

procedure: flo:default-trapped-exceptions ¶

  Returns the set of exceptions that are trapped in the default floating-point environment. Equivalent to `(flo:names->exceptions '())`, or simply `0`, since by default, no exceptions are trapped.

procedure: flo:trapped-exceptions ¶

  Returns the set of exceptions that are currently trapped.

procedure: flo:trap-exceptions! excepts ¶
procedure: flo:untrap-exceptions! excepts ¶
procedure: flo:set-trapped-exceptions! excepts ¶

  `Flo:trap-exceptions!` requests that any exceptions in the set excepts be trapped, in addition to all of the ones that are currently trapped. `Flo:untrap-exceptions!` requests that any exceptions in the set excepts not be trapped. `Flo:set-trapped-exceptions!` replaces the set of trapped exceptions altogether by excepts. All three procedures enter a per-thread environment.

      (define (flo:trap-exceptions! excepts)
        (flo:set-trapped-exceptions!
         (fix:or (flo:trapped-exceptions) excepts)))

      (define (flo:untrap-exceptions! excepts)
        (flo:set-trapped-exceptions!
         (fix:andc (flo:trapped-exceptions) excepts)))

      (define (flo:set-trapped-exceptions! excepts)
        (flo:trap-exceptions! excepts)
        (flo:untrap-exceptions!
         (fix:andc (flo:supported-exceptions) excepts)))

procedure: flo:with-exceptions-trapped excepts thunk ¶
procedure: flo:with-exceptions-untrapped excepts thunk ¶
procedure: flo:with-trapped-exceptions excepts thunk ¶

  Dynamic-extent analogues of `flo:trap-exceptions!`, `flo:untrap-exceptions!`, and `flo:set-trapped-exceptions!`. These call thunk with their respective changes to the set of trapped exceptions in a per-thread environment, and restore the environment on return or non-local exit.

procedure: flo:defer-exception-traps! ¶

  Saves the current floating-point environment, clears all raised exceptions, disables all exception traps, and returns a descriptor for the saved floating-point environment.

  `Flo:defer-exception-traps!` is typically used together with `flo:update-environment!`, to trap any exceptions that the caller had wanted trapped only after a long intermediate computation. This pattern is captured in `flo:deferring-exception-traps`.

procedure: flo:deferring-exception-traps thunk ¶

  Calls thunk, but defers trapping on any exceptions it raises until it returns. Equivalent to:

      (flo:preserving-environment
       (lambda ()
         (let ((environment (flo:defer-exception-traps!)))
           (begin0 (thunk)
             (flo:update-environment! environment)))))

procedure: flo:ignoring-exception-traps thunk ¶

  Calls thunk with all exceptions untrapped and unraised. Equivalent to:

      (flo:preserving-environment
       (lambda ()
         (flo:defer-exception-traps!)
         (thunk)))