Report when exact arithmetic is used inside float expressions, which may make the extra precision useless.
original commit: cd027109c9aa71d788764d934992d290bd586a39
This commit is contained in:
parent
9d1bfedc5e
commit
4c08c496f6
|
@ -0,0 +1,16 @@
|
|||
#;
|
||||
(
|
||||
precision-loss.rkt 13:3 (#%app * (quote 3/4) (quote 2/3)) -- exact arithmetic subexpression inside a float expression, extra precision discarded -- caused by: 13:0 (#%app + (#%app * (quote 3/4) (quote 2/3)) (quote 2.0))
|
||||
2.5
|
||||
2.75
|
||||
)
|
||||
|
||||
#lang typed/racket
|
||||
|
||||
;; warn when the extra precision gained by doing exact computations would
|
||||
;; be lost when the results are mixed with floats, resulting in extra
|
||||
;; computation cost for (usually) no gain
|
||||
(+ (* 3/4 2/3) ; exact computation
|
||||
2.0) ; extra precision lost
|
||||
(+ 3/4 2.0) ; here, since the exact subexpression is atomic, it will get
|
||||
;; coerced anyway, so there's not much need for a warning
|
|
@ -86,18 +86,42 @@
|
|||
f2:float-arg-expr
|
||||
fs:float-arg-expr ...)
|
||||
;; if the result is a float, we can coerce integers to floats and optimize
|
||||
#:when (let ([safe-to-opt? (subtypeof? this-syntax -Flonum)])
|
||||
;; if we don't have a return type of float, we missed an optimization
|
||||
;; opportunity, report it
|
||||
;; ignore operations that stay within integers or rationals, since
|
||||
;; these have nothing to do with float optimizations
|
||||
(when (and (not safe-to-opt?)
|
||||
(in-real-layer? this-syntax))
|
||||
#:when (let* ([safe-to-opt? (subtypeof? this-syntax -Flonum)]
|
||||
;; if we don't have a return type of float, we missed an optimization
|
||||
;; opportunity, report it
|
||||
;; ignore operations that stay within integers or rationals, since
|
||||
;; these have nothing to do with float optimizations
|
||||
[close-call? (and (not safe-to-opt?)
|
||||
(in-real-layer? this-syntax))])
|
||||
(when close-call?
|
||||
(log-close-call "binary, args all float-arg-expr, return type not Float"
|
||||
this-syntax
|
||||
(for/first ([x (in-list (syntax->list #'(f1 f2 fs ...)))]
|
||||
#:when (not (subtypeof? x -Flonum)))
|
||||
x)))
|
||||
;; If an optimization was expected (whether it was safe or not doesn't matter),
|
||||
;; report subexpressions doing expensive exact arithmetic (Exact-Rational and
|
||||
;; Real arithmetic), since that extra precision would be "lost" by going to
|
||||
;; floating-point in this expression.
|
||||
;; Since this exact behavior can be desirable, it's invalid to optimize it away,
|
||||
;; but it's more likely to be there by accident. I can't really think of many
|
||||
;; use cases for computing exact intermediate results, then converting them to
|
||||
;; floats at the end.
|
||||
(when (or safe-to-opt? close-call?)
|
||||
(for ([subexpr (in-list (syntax->list #'(f1 f2 fs ...)))]
|
||||
#:when (or (in-real-layer? subexpr)
|
||||
(in-rational-layer? subexpr)))
|
||||
(syntax-parse subexpr
|
||||
;; Only warn about subexpressions that actually perform exact arithmetic.
|
||||
;; There's not much point in warning about literals/variables that will
|
||||
;; be coerced anyway, or about things like:
|
||||
;; (vector-ref vector-of-rationals x)
|
||||
;; which don't perform arithmetic despite returning numbers.
|
||||
[(#%plain-app (~var op (float-op binary-float-ops)) xs ...)
|
||||
(log-close-call
|
||||
"exact arithmetic subexpression inside a float expression, extra precision discarded"
|
||||
subexpr this-syntax)]
|
||||
[_ #f])))
|
||||
safe-to-opt?)
|
||||
#:with opt
|
||||
(begin (log-optimization "binary float" #'op)
|
||||
|
|
Loading…
Reference in New Issue
Block a user