mit-scheme-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[MIT-Scheme-devel] floating-point environment


From: Taylor R Campbell
Subject: [MIT-Scheme-devel] floating-point environment
Date: Wed, 6 Oct 2010 07:15:43 +0000
User-agent: IMAIL/1.21; Edwin/3.116; MIT-Scheme/9.0.1

I'd like to make some changes to MIT Scheme to give programs fine-
grained control over the floating-point environment as in IEEE 754.
There are three parts to this: (a) semantics of the floating-point
environment in Scheme, (b) semantics of the floating-point environment
in microcode primitives, and (c) new operations in Scheme.

(a) Currently, the floating-point environment is thread-global, so
that FLO:SET-ROUNDING-MODE! changes the rounding mode in all threads
that have not used FLO:WITH-ROUNDING-MODE.  I don't think this is
right: I think the floating-point environment should be thread-local,
and perhaps part of each continuation.  I have not measured the cost
in performance of changing CWCC to save and restore the floating-point
environment, but if the environment were thread-local, then most uses
of CWCC (for switching threads) would have to save and restore the
environment anyway.

(b) C99 forbids calling any library routine in non-default floating-
point environments unless the routine is documented to allow it.  We
violate this rule -- the microcode runs with Scheme's floating-point
environment.  The only problem I have observed with this is that if
Scheme unmasks the inexact-result exception, it crashes, because the
thread timer uses primitives (REAL-TIME-CLOCK) that perform inexact
floating-point operations.  But there may be other problems.  (E.g.,
maybe changing the rounding mode could make the real-time clock run
backwards briefly.)  We could leave this as is, or I could make the
microcode alternate between the Scheme and default C floating-point
environments when alternating between Scheme and C, and I could change
every floating-point primitive that needs to see Scheme's environment
so that it uses fesetenv explicitly.

(c) Here is a summary of the procedures I'd like to add, some of which
are primitives that I'd like to be able to open-code later.  Thus, the
representation of exception sets and environments is machine-
dependent, and not fit to store in bands.  This is avoidable for
exception sets (just like rounding modes), but not easily avoidable
for environments.  Most of the names should be self-explanatory.

Thoughts?  (Patch is not yet done, but let me know if you'd like to
see it.)

primitive: (FLO:ENVIRONMENT) -> environment
primitive: (FLO:DEFAULT-ENVIRONMENT) -> environment
primitive: (FLO:SET-ENVIRONMENT! <environment>)
primitive: (FLO:DEFER-EXCEPTIONS!) -> environment
primitive: (FLO:UPDATE-ENVIRONMENT! <environment>)

DEFER-EXCEPTIONS! saves the floating-point environment, masks all
exceptions, and returns the saved floating-point environment.
UPDATE-ENVIRONMENT! remembers any raised masked exceptions, has the
effects of SET-ENVIRONMENT!, and then raises all formerly raised
masked exceptions that are now unmasked.

procedure: (FLO:DEFERRING-EXCEPTIONS <procedure>) -> values
procedure: (FLO:IGNORING-EXCEPTIONS <procedure>) -> values

(define (flo:deferring-exceptions procedure)
  (let ((environment (flo:defer-exceptions!)))
    (begin0 (procedure) (flo:update-environment! environment))))

(define (flo:ignoring-exceptions procedure)
  (let ((environment (flo:defer-exceptions!)))
    (begin0 (procedure) (flo:set-environment! environment))))

primitive: (FLO:SUPPORTED-EXCEPTIONS) -> exceptions (small integer)
primitive: (FLO:EXCEPTION:DIVIDE-BY-ZERO) -> exceptions
primitive: (FLO:EXCEPTION:INVALID-OPERATION) -> exceptions
primitive: (FLO:EXCEPTION:UNDERFLOW) -> exceptions
primitive: (FLO:EXCEPTION:OVERFLOW) -> exceptions
primitive: (FLO:EXCEPTION:INEXACT-RESULT) -> exceptions

primitive: (FLO:TEST-EXCEPTIONS <exceptions>) -> exceptions
primitive: (FLO:CLEAR-EXCEPTIONS! <exceptions>)
primitive: (FLO:RAISE-EXCEPTIONS! <exceptions>)

primitive: (FLO:SAVE-ALL-EXCEPTION-FLAGS) -> exception-flags
primitive: (FLO:SAVE-EXCEPTION-FLAGS <exceptions>) -> exception-flags
primitive: (FLO:TEST-EXCEPTION-FLAGS <exception-flags> <exceptions>) -> 
exceptions
primitive: (FLO:RESTORE-EXCEPTION-FLAGS! <exception-flags> <exceptions>)

primitive: (FLO:MASKED-EXCEPTIONS) -> exceptions
primitive: (FLO:SET-MASKED-EXCEPTIONS! <exceptions>) -> exceptions
primitive: (FLO:MASK-EXCEPTIONS! <exceptions>) -> exceptions
primitive: (FLO:UNMASK-EXCEPTIONS! <exceptions>) -> exceptions

These all return the exception mask prior to the call.

procedure: (FLO:WITH-EXCEPTION-MASK <exceptions> <procedure>) -> values

(define (flo:with-exception-mask exceptions procedure)
  (let ((exceptions* (flo:set-masked-exceptions! exceptions)))
    (begin0 (procedure) (flo:set-masked-exceptions! exceptions*))))

It might be useful to have a procedure FLO:WITH-EXCEPTIONS-MASKED, but
it is not clear to me what its semantics should be.  Here are several
possibilities:

(flo:with-exception-mask (fix:and exceptions (flo:exceptions)) procedure)

(flo:mask-exceptions! exceptions)
(begin0 (procedure) (flo:unmask-exceptions! exceptions))

(dynamic-wind (lambda () (flo:mask-exceptions! exceptions))
              procedure
              (lambda () (flo:unmask-exceptions! exceptions)))

(let ((outside-exception-mask))
  (dynamic-wind (lambda ()
                  (set! outside-exception-mask (flo:masked-exceptions))
                  (flo:mask-exceptions! exceptions))
                procedure
                (lambda ()
                  (flo:set-masked-exceptions! outside-exception-mask)
                  (set! outside-exception-mask)
                  unspecific)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]