在它们发生之前防止浮点溢出

时间:2015-04-13 20:25:54

标签: common-lisp

作为溢出浮点的一种简单方法(我在我的代码中使用双浮点数,所以我在这里也这样做):

(setq *read-default-float-format* 'double-float)
(defun example-float-overflow (x)
  (example-float-overflow (* x x)))
(example-float-overflow 4.4)

很快,x变得越来越大。很快它达到了5.295234290518905e164并且溢出。哪个,甚至是双浮动了?

无论如何,在溢出之前识别点的最佳方法是什么?现在我正在做类似的事情:

(defun example-float-overflow-no-error (x)
  (if (> (* x x) 1.0e20)
      x
      (example-float-overflow-no-error (* x x))))
(example-float-overflow 4.4)

=> 1.973525870240772e10

注意:我对结果并不感兴趣,但我的其余代码依赖于它在溢出之前运行多次。

1 个答案:

答案 0 :(得分:1)

Barmar suggested在溢出发生后立即处理浮点溢出条件。这比检测它即将发生的时间稍微多一点,但它可能是最容易做到的事情。例如,这是一个添加功能,添加就像 + 一样,除非出现问题,您可以使用 use-value 重启提供不同的价值:

(defun add (&rest numbers)
  "Add numbers with +, but with a USE-VALUE restart
available in case of an overflow (or other condition)."
  (restart-case (reduce '+ numbers)
    (use-value (value &optional condition) value)))

然后,如果对添加的调用失败,您可以建立使用价值重新启动,以便提供值:

;; Attempt to some arithmetic, but with a handler bound that
;; will return 42 if an floating point-overflow occurs.
(handler-bind ((floating-point-overflow
                (lambda (condition)
                  (use-value 42 condition))))
  (+ 5 (add most-positive-double-float most-positive-double-float)))
;;     |----------- this ends up evaluating to 42 ---------------|
;;|------------- and 42 + 5 is 47 --------------------------------|
;=> 47
相关问题