在浮点溢出发生之前防止它们发生
Prevent floating point overflows right before they happen
作为溢出浮点数的简单方法(我在我的代码中使用双浮点数,所以我也会在这里这样做):
(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
注意:我实际上对结果不感兴趣,但我的其余代码取决于它,在溢出之前尽可能多地 运行 次。
Barmar 在溢出发生后立即处理 浮点溢出 条件。这比检测它何时即将发生要难一些,但这可能是最简单的事情。例如,这里有一个 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
作为溢出浮点数的简单方法(我在我的代码中使用双浮点数,所以我也会在这里这样做):
(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
注意:我实际上对结果不感兴趣,但我的其余代码取决于它,在溢出之前尽可能多地 运行 次。
Barmar
(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