【问题标题】:Prevent floating point overflows right before they happen防止浮点溢出发生之前
【发布时间】:2015-04-13 20:25:54
【问题描述】:

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

(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

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

【问题讨论】:

  • 可以测试x是否大于(sqrt most-positive-double-float)
  • 为什么不在溢出发生时使用条件处理程序来检测?
  • 处理FLOATING-POINT-OVERFLOW 条件。
  • 当错误发生时,您可能使用HANDLER-CASE 来返回NIL
  • 限制取决于实现。这就是为什么您需要使用MOST-POSITIVE-DOUBLE-FLOAT 来确定它的原因。

标签: common-lisp


【解决方案1】:

Barmar suggested 在溢出发生后处理 floating-point-overflow 条件。这比检测它何时将要发生有点小,但这可能是最容易做的事情。比如这里有一个add函数,和+一样添加,只是如果出现问题,你可以使用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)))

然后,您可以建立 use-value 重启,以便在调用 add 失败时提供值:

;; 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

【讨论】:

  • 这太棒了!谢谢。
猜你喜欢
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2018-06-19
  • 2014-06-28
  • 1970-01-01
  • 1970-01-01
  • 2018-02-17
  • 1970-01-01
相关资源
最近更新 更多