Z3 C++ API浮点运算(FPA)使用咨询:代码报错与示例需求
Z3 C++ API 使用FPA求解非线性问题的解决方案
你的代码存在的问题
你遇到的断言错误,核心原因是错误使用了Z3_mk_fpa_fp函数:这个函数的作用是基于给定的符号位、指数位、尾数位的具体BV值,构造一个确定的浮点数实例,而不是用来声明浮点类型的变量。你的代码直接用未约束的BV变量调用它,完全不符合函数的使用场景,自然会触发断言失败。
另外你漏掉了关键步骤:没有先定义浮点类型(sort),就试图创建浮点变量,这也是导致错误的原因之一。
Z3 C++ API 使用FPA的完整示例
下面是适配你需求的完整代码,用32位单精度浮点数(对应C++的float)替代实数,实现x*y > 10的求解逻辑,还支持生成多个解:
#include <z3++.h> #include <iostream> using namespace z3; int main() { // 初始化配置与上下文 config cfg; cfg.set("auto_config", true); context con(cfg); // 创建32位单精度浮点类型:1位符号位 + 8位指数位 + 23位尾数位 sort fp_sort = to_sort(con, Z3_mk_fpa_sort(con, 1, 8, 23)); // 声明浮点类型的变量x和y expr x = con.constant("x", fp_sort); expr y = con.constant("y", fp_sort); solver sol(con); // 将整数10转换为对应浮点类型的常量,确保约束类型一致 expr ten = to_expr(con, Z3_mk_fpa_from_real(con, con.real_val(10), 1, 8, 23)); // 添加约束:x*y > 10 sol.add(mul(x, y) > ten); // 求解并获取第一个解 check_result res = sol.check(); if (res == sat) { model m = sol.get_model(); std::cout << "第一个解:" << std::endl; std::cout << "x = " << m.eval(x) << std::endl; std::cout << "y = " << m.eval(y) << std::endl; // 添加约束排除当前解,生成第二个解 sol.add(x != m.eval(x) || y != m.eval(y)); res = sol.check(); if (res == sat) { model m2 = sol.get_model(); std::cout << "\n第二个解:" << std::endl; std::cout << "x = " << m2.eval(x) << std::endl; std::cout << "y = " << m2.eval(y) << std::endl; } else { std::cout << "\n没有更多解了" << std::endl; } } else { std::cout << "无解" << std::endl; } return 0; }
代码关键说明
- 浮点类型定义:用
Z3_mk_fpa_sort创建自定义浮点类型,参数依次是符号位长度、指数位长度、尾数位长度。如果你的精度需求更低(仅1-2位小数),可以用更精简的格式,比如1位符号+5位指数+10位尾数(总16位),既能满足精度要求,又能进一步缩小搜索空间提升速度。 - 变量声明:通过
con.constant基于浮点类型声明变量,这才是创建浮点变量的正确方式。 - 常量类型匹配:必须把实数/整数常量转换为对应浮点类型,用
Z3_mk_fpa_from_real完成,避免类型不匹配的错误。 - 生成多解:每次求解后,添加排除当前解的约束(
x != 当前x值 || y != 当前y值),再次调用solver.check()即可得到新解。
额外优化建议
如果不需要处理NaN、无穷大等特殊浮点值,可以添加约束排除这些情况,让求解更贴合业务场景:
// 确保x和y是正常的浮点数(非NaN、非无穷大) sol.add(is_normal(x)); sol.add(is_normal(y));
内容的提问来源于stack exchange,提问作者Rehab11
相关产品推荐
相关产品推荐

