为什么 Z3 "rounding" 小实数为 1.0/0.0?
Why is Z3 "rounding" small reals to 1.0/0.0?
我正在使用 Z3 的 python API 进行一些线性实数运算。我遇到过非常接近于零的实数以某种方式转换为 1.0/0.0 的情况。这反过来会导致 Z3 的 C++ 部分出现浮点异常。
例如我有以下 Python 程序:
from z3 import *
s = Solver()
s.add(0.00001 * Real("a") + 0.00001 * Real("b") > 0.0)
print(s.to_smt2())
result = s.check()
print(result)
print(s.model())
产生以下输出:
; benchmark generated from python API
(set-info :status unknown)
(declare-fun b () Real)
(declare-fun a () Real)
(assert
(let ((?x10 (+ (* (/ 1.0 0.0) a) (* (/ 1.0 0.0) b))))
(> ?x10 0.0)))
(check-sat)
Floating point exception (core dumped)
如果我将第 3 行替换为
#s.add(Q(1,100000) * Real("a") + Q(1, 100000) * Real("b") > 0.0)
我得到了预期的输出。
有没有人有解释以及如何使用普通的 Python 浮点数让它工作的方法?
我无法复制这个。当我 运行 你的程序时,我得到:
; benchmark generated from python API
(set-info :status unknown)
(declare-fun b () Real)
(declare-fun a () Real)
(assert
(let ((?x10 (+ (* (/ 1.0 100000.0) a) (* (/ 1.0 100000.0) b))))
(> ?x10 0.0)))
(check-sat)
sat
[b = 50000, a = 0]
其中没有您所说的 (/ 1.0 0)
字词。
您使用的是什么版本的 z3?也许您有一个旧版本,其中有一个已修复的错误?我在 4.8.13(来自 GitHub master),不过你也可以使用最新的官方版本 4.8.12。
NB 话虽如此,我认为您使用 Q(1, 100000)
的“解决方法”实际上是更可取的,因为它会避免各种浮点精度问题。除非你正在解决浮点逻辑问题,否则你真的不应该以这种方式使用浮点数转换,因为在表示问题上会有陷阱。
事实证明,Z3 并没有按原样使用浮点数,而是将其转换为字符串,然后尝试解析该字符串。对于小数字,Python 的 str() 默认为科学记数法,Z3 显然无法正确解析它。使用 "{:.20f}".format(my_small_float)
或类似的显式转换解决了我的问题。
我正在使用 Z3 的 python API 进行一些线性实数运算。我遇到过非常接近于零的实数以某种方式转换为 1.0/0.0 的情况。这反过来会导致 Z3 的 C++ 部分出现浮点异常。
例如我有以下 Python 程序:
from z3 import *
s = Solver()
s.add(0.00001 * Real("a") + 0.00001 * Real("b") > 0.0)
print(s.to_smt2())
result = s.check()
print(result)
print(s.model())
产生以下输出:
; benchmark generated from python API
(set-info :status unknown)
(declare-fun b () Real)
(declare-fun a () Real)
(assert
(let ((?x10 (+ (* (/ 1.0 0.0) a) (* (/ 1.0 0.0) b))))
(> ?x10 0.0)))
(check-sat)
Floating point exception (core dumped)
如果我将第 3 行替换为
#s.add(Q(1,100000) * Real("a") + Q(1, 100000) * Real("b") > 0.0)
我得到了预期的输出。
有没有人有解释以及如何使用普通的 Python 浮点数让它工作的方法?
我无法复制这个。当我 运行 你的程序时,我得到:
; benchmark generated from python API
(set-info :status unknown)
(declare-fun b () Real)
(declare-fun a () Real)
(assert
(let ((?x10 (+ (* (/ 1.0 100000.0) a) (* (/ 1.0 100000.0) b))))
(> ?x10 0.0)))
(check-sat)
sat
[b = 50000, a = 0]
其中没有您所说的 (/ 1.0 0)
字词。
您使用的是什么版本的 z3?也许您有一个旧版本,其中有一个已修复的错误?我在 4.8.13(来自 GitHub master),不过你也可以使用最新的官方版本 4.8.12。
NB 话虽如此,我认为您使用 Q(1, 100000)
的“解决方法”实际上是更可取的,因为它会避免各种浮点精度问题。除非你正在解决浮点逻辑问题,否则你真的不应该以这种方式使用浮点数转换,因为在表示问题上会有陷阱。
事实证明,Z3 并没有按原样使用浮点数,而是将其转换为字符串,然后尝试解析该字符串。对于小数字,Python 的 str() 默认为科学记数法,Z3 显然无法正确解析它。使用 "{:.20f}".format(my_small_float)
或类似的显式转换解决了我的问题。