跳到主要内容
未列出页
此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。

数值函数形式化验证:中间语言与验证平台选型

基于 [[数值函数形式化验证-想法与约束.md]] 中 PureLibm-rs 五级验证体系,探索 Rust 之外的验证平台选择,评估中间语言作为"一次证明、多语言分发"中枢的可行性。

整理日期:2026年6月


〇、核心问题

在 PureLibm-rs 的五级验证体系中,L3(Gappa 多项式误差证明)和 L4(Coq/Flocq 完整正确舍入证明)是语言无关的——证明的是算法而非特定实现。这引出一个架构问题:

是否存在一个中间语言,可以在其中完成算法验证,然后提取到多语言(C/Rust/Julia),通过差分测试对齐?

即"一次证明、多语言分发"的模式:

验证平台 (单一语言) ──→ 机器可检查的证明

AI 翻译 / 提取 ↓
┌──────┼──────┐
C Rust Julia
│ │ │
└──┬───┴───┬──┘

差分测试对齐 (穷举/随机 + oracle)

本文档系统评估了五个中间验证语言/平台(Why3、Boogie、Viper、Dafny、CakeML)和四个验证平台(SPARK/Ada、C+Frama-C、Coq/Flocq、VST+CompCert),给出针对此场景的选型建议。


一、评估维度

维度含义
IEEE 754 形式化完备性语言/工具是否内置 IEEE 754 浮点的形式化语义模型
浮点精度证明能力能否自动或半自动证明舍入误差 bound(如多项式逼近误差 ≤ N ULP)
代码提取目标能否从验证语言生成可执行代码,支持哪些目标语言
多语言前端能否从 Rust/C/Ada 等语言的代码翻译到该平台做验证
Coq 后端能否生成 Coq 验证条件,以进行 L4 级完全形式化证明
TCB 大小信任基(Trusted Computing Base)的大小——需要信任多少未经验证的代码
AI 辅助友好度语言/工具的训练数据丰富程度,AI 生成代码和标注的质量预期
浮点验证成熟度是否有已完成的 libm 级浮点函数验证案例

二、中间验证语言对比

2.1 Why3/WhyML(Inria)

目前唯一满足"IEEE 754 形式化 + C 提取 + 多语言前端 + Coq 后端"完整链条的 IVL。

架构:
Rust ──→ Creusot ──→ WhyML ←── SPARK/GNATprove ←── Ada

C ──────→ Frama-C WP ─┤

Why3 调度
├── SMT (Z3, CVC4, Alt-Ergo)
├── Gappa (浮点舍入误差)
└── Coq (手动证明)

提取到 C / OCaml

IEEE 754 标准库(ieee_float.why):

type float32 = <float 8 24> (* binary32 *)
type float64 = <float 11 53> (* binary64 *)

type mode = RNE | RNA | RTP | RTN | RTZ

val add: mode -> float32 -> float32 -> float32
val sub: mode -> float32 -> float32 -> float32
val mul: mode -> float32 -> float32 -> float32
val div: mode -> float32 -> float32 -> float32
val fma: mode -> float32 -> float32 -> float32 -> float32
val sqrt: mode -> float32 -> float32

val to_real: float32 -> real (* 浮点→实数 *)
val of_real: mode -> real -> float32 (* 实数→浮点,带舍入 *)

val is_finite: float32 -> bool
val is_nan: float32 -> bool
val is_infinite: float32 -> bool
val is_normal: float32 -> bool
val is_subnormal: float32 -> bool
val is_positive: float32 -> bool
val is_negative: float32 -> bool

"unbounded float"方法论:

Inria 团队在验证 log-sum-exp(LSE)和 SLSE 时引入的核心技巧 —— 将精度证明和溢出证明分离:

(* 步骤 1: 在 unbounded float 中证明精度——不考虑溢出 *)
lemma accuracy_bound:
∀ x: ub_float32,
abs (to_real (compute x) - exact_value x) ≤ ε * abs (exact_value x)

(* 步骤 2: 单独证明原始程序不溢出 *)
lemma no_overflow:
∀ x: float32, is_finite x → is_finite (compute x)

已验证案例: LSE(log-sum-exp)和 SLSE(mutual information)——误差 bound 参数化于底层 exp/log 实现的精度假设。

维度评价说明
IEEE 754 形式化⭐⭐⭐⭐⭐ieee_float.why 是除 Flocq 外最完整的形式化
浮点精度证明⭐⭐⭐⭐Gappa 集成,天然适合多项式误差 bound
代码提取⭐⭐⭐½C ✅ OCaml ✅ Rust ❌(Creusot 只有反向)
多语言前端⭐⭐⭐⭐⭐C, Ada, Rust, Java, Solidity
Coq 后端⭐⭐⭐⭐生成 VCs 供 Coq/Flocq 证明
TCB 大小⭐⭐⭐½Why3 框架本身 + SMT solvers(Gappa 已验证)
AI 友好度⭐⭐½WhyML 训练数据少
浮点验证成熟度⭐⭐⭐⭐LSE/SLSE 案例,Frama-C 工业案例

2.2 Boogie(Microsoft Research)

最简洁的 IVL。不提取代码,不做浮点精度验证。

Dafny / VCC / SDV ──→ Boogie ──→ Z3 (SMT)
维度评价说明
IEEE 754 形式化⭐⭐无原生浮点类型,通过 SMT 浮点理论模拟
浮点精度证明没有 Gappa 集成,舍入误差 bound 的证明极不自然
代码提取不提取代码
多语言前端⭐⭐⭐Dafny, C# (Spec#), C (VCC/SMACK)
Coq 后端
TCB 大小⭐⭐⭐½Boogie + Z3

结论:不适合此场景。 Boogie 的哲学是"把验证问题翻译成 SMT 公式"——它没有 IEEE 754 的形式化模型,没有 Gappa 用于误差 bound,不提取代码。


2.3 Viper(ETH Zurich)

分离逻辑最强。面向内存安全和并发,不为数值精度设计。

Prusti (Rust) / Nagini (Python) / Gobra (Go) ──→ Viper ──→ Z3
维度评价说明
IEEE 754 形式化无原生支持
浮点精度证明不在设计目标中
代码提取不提取
多语言前端⭐⭐⭐⭐Rust, Python, Go, Java (VerCors)
Coq 后端
浮点验证成熟度无 libm 级案例

结论:不适合此场景。 Viper 的核心优势在权限推理——如果你未来需要验证"多线程数值计算"中的内存安全,它是首选。但对于数学函数的精度验证,它没有任何专用能力。


2.4 Dafny

SMT 自动验证语言。Rust 提取是最大亮点,但 IEEE 754 形式化深度不足。

架构:
Dafny 源码 (.dfy)
├──→ Boogie → Z3 (验证)
└──→ 直接编译到 C#/JS/Java/Go/Python/Rust
维度评价说明
IEEE 754 形式化⭐⭐½fp32/fp64 类型在集成中,无不依赖 SMT 的显式形式化
浮点精度证明⭐⭐½无 Gappa,依赖 SMT 浮点理论(功能弱于专用工具)
代码提取⭐⭐⭐⭐C# ✅ JS ✅ Java ✅ Go ✅ Python ✅ Rust ✅ (AWS, POPL 2025)
多语言前端只有 Dafny 自身
Coq 后端
AI 友好度⭐⭐⭐⭐语法接近主流语言,LLM 支持好
浮点验证成熟度⭐⭐统计库(Mean, Variance),无 sin/cos/exp

Dafny-to-Rust 编译器(AWS + UC Berkeley, POPL 2025):

  • 9/10 benchmark 性能≤手写 Rust 的 1.22×
  • 2/10 达到性能平价
  • 解决了类型系统差异、内存管理、跨语言互操作

CakeML 后端(Dafny 2025):

  • Dafny IR → CakeML → 验证的编译链
  • 减少 Dafny 的 TCB(不再信任 C#/Rust 编译器)

结论:Dafny 有潜力但浮点验证不成熟。 适合"快速得到一个可用的验证+Rust代码"。对于"不可质疑的正确性规格",Why3 > Dafny。


2.5 Gillian(Imperial College)

符号执行 + 分离逻辑。研究阶段,不适用。

维度评价说明
代码提取不提取
浮点支持不在设计目标中
C 前端Gillian-C 基于 CompCert 语义(比 Why3 的 C 前端 TCB 更小)

优势在 Gillian-C 使用 CompCert 语义——长期看,如果 Gillian 将来支持浮点,这条路径的 TCB 比 Frama-C 更小。但目前不适用。


三、验证语言/平台对比

3.1 C + Frama-C/ACSL + Gappa

当前工业级浮点验证最成熟的 C 路径。

工作流:
CORE-MATH C 代码 + ACSL 标注
→ Frama-C WP 插件 → WhyML VCs
→ Gappa (舍入误差) + SMT (程序逻辑) + Coq (超越函数)
维度评价说明
IEEE 754 形式化⭐⭐⭐⭐½ACSL 支持 Full IEEE 754 模型(含 NaN/Inf/signed zero)
Gappa 集成天然适合多项式逼近误差证明
C 语言形式化语义⭐⭐不基于 CompCert,C 语义在 Frama-C 中非形式化定义
UB 风险⚠️验证假设"无 UB",需 value analysis 辅助排除
工业验证案例Safran 惯性导航(四元数浮点运算)
CORE-MATH 对接直接在 CORE-MATH C 代码上加标注,零翻译
AI 标注能力⚠️ACSL 训练数据少,AI 写 ACSL 标注质量存疑

关键优势: CORE-MATH 本身是 C,验证对象无需翻译。Gappa 是其多项式误差证明的设计场景。

关键劣势: C 的 UB 是结构性问题——验证的是"假设没有 UB"下的正确性。


3.2 SPARK/Ada

工业级最高内置保证。浮点数学库验证正在发展中。

维度评价说明
IEEE 754 支持⭐⭐⭐⭐语言内置 Float'Pred/Float'Succ、range types
浮点精度证明⭐⭐⭐⭐PropaFP 已验证 Taylor sin + Heron sqrt
形式化验证级别Gold完全功能证明(spark_math 部分函数)
libm 级验证⚠️spark_math 以定点为主,超越函数在 roadmap
AI 友好度⭐⭐Ada 训练数据极低,AI 翻译到其他语言质量差
生态大小⭐⭐社区小,库少

核心矛盾: 证明能力强,但作为"AI 翻译源语言"不适合——AI 从 Ada 翻译到 Rust/C/Julia 的质量,会因训练数据极度匮乏而远低于从 C 翻译。


3.3 Coq/Flocq

最高级别的形式化保证。IEEE 754 本身在 Coq 中形式化并证明了性质。

为什么 Coq/Flocq 是"最高级"的证明:

层级证明对象TCB 包含
SMT/Kani具体输入上的程序行为SMT solver(Z3 ~50万行C++)
Gappa多项式在区间上的误差界Gappa 本身(已验证)
SPARK GoldAda 代码满足标注GNAT 语义 + SMT solver
Frama-C + GappaC 代码 + 浮点误差 boundFrama-C 前端 + Gappa + SMT
VST + CompCertC 程序的 CompCert 语义Coq 内核(~2万行OCaml)
Coq/Flocq浮点运算的形式化模型本身Coq 内核

Flocq 证明的不是"这个程序对"——Flocq 证明的是"什么是 IEEE 754 舍入"以及"这个舍入模型具有什么数学性质"。

Flocq 的内容层次:

Core/RoundPred.v — 舍入谓词的形式化定义(什么是合法的舍入方向)
Core/RoundNE.v — round-to-nearest-even 的性质证明
Core/Ulp.v — ULP 的形式化定义和性质
Core/FLT.v — 浮点格式(任意尾数精度和指数范围)
IEEE754/Binary.v — binary32/binary64 的完整 IEEE 754 语义
Calc/ — 运算的具体实现和误差界证明
Prop/ — 舍入误差的通用性质(如相对误差≤0.5ulp)

Flocq 实际能够处理的:

  • Hard-to-round cases 的完备性证明(不能靠穷举,因为 f64 有 2^64 个输入)
  • Range reduction(Payne-Hanek)的形式化——含条件分支和取模,超出 Gappa 区间分析范围
  • 不同舍入模式的参数化证明
  • 调用链的组合保证(已验证函数的规约可直接作为调用者的前提)

3.4 VST + VCFloat2(C + Coq)

C 程序的完整机器检查证明链,CompCert 语义 + Flocq 浮点模型。

VST (验证 C 程序满足功能规范)
+ VCFloat2 (浮点舍入误差分析)
+ CompCert (形式化验证的 C 语义)
+ Flocq (IEEE 754 形式化模型)
→ 全部归约到 Coq 内核

CPP 2024 已验证的应用: ODE Leapfrog 积分、Jacobi 迭代、稀疏矩阵转换。

与 Frama-C 的本质区别: Frama-C 的 C 语义是工具内部定义的非形式化语义。VST 的 C 语义是 CompCert 的——在 Coq 中形式化并证明了正确性的编译器。TCB 从"Frama-C + SMT solver"缩小到"Coq 内核"。


四、Why3 直接使用 vs Frama-C + Why3

4.1 两条路径的本质差异

维度Why3 直接使用Frama-C + Why3
出发语言WhyML(手写)C(CORE-MATH)
验证对象算法本身已有的 C 实现
核心产出WhyML 规格 + 证明 + C 代码被验证的 C 代码 + ACSL 标注
核心价值"这个算法是正确的""这个 C 实现是正确的"
TCBWhy3 框架 + SMT+ C 语言语义(非 CompCert)
CORE-MATH 对接需手动翻译算法逻辑直接在原始代码加标注
AI 翻译友好度WhyML→C 由 Why3 保证C→Rust/Julia AI 翻译

4.2 两条路径可以共存

WhyML (真理源)
/ \
Frama-C + ACSL Why3→C 提取
CORE-MATH C 代码 可信任的 C 参考实现
│ │
└────────┬───────────────┘

交叉验证 (ACSL 标注 ↔ WhyML 规格)

AI 翻译到 Rust

差分测试对齐

交叉验证本身是最高强度的保证——同一算法的两个独立形式化互相验证。


五、CakeML:一个特殊的选项

5.1 CakeML 是什么

CakeML 不是 IVL——它是在 HOL4 定理证明器中形式化验证的编译器(Standard ML 子集 → 机器码)。

5.2 CakeML 的浮点能力

CakeML 有三个独立的浮点相关项目,形成完整链:

项目功能
HOL4 IEEE 754 形式化HOL4 中的 IEEE 754 浮点语义形式化
FloVer舍入误差 bound 证书检查器——证明 `max
RealCake扩展 CakeML 编译器支持 fast-math 优化(FMA 收缩等),同时证明优化后机器码与原始实数语义之间的误差 bound

FloVer 恰好覆盖 L3(多项式求值的误差证明)。 但只限直线代码——不处理 range reduction 等复杂控制流。

RealCake(ECOOP 2022)的三层语义:

  1. 标准 IEEE 754 语义(严格模式)
  2. 放松的浮点语义(允许 FMA 收缩等优化)
  3. 实数语义(ground truth)

编译器自动证明 I/O 行为在这三层之间的误差 refinement。JetEngine 内核在 Raspberry Pi 上加速 95%,误差 bound 被形式化证明。

5.3 CakeML 作为 Why3 的提取后端

当前: Why3 → C 提取 → gcc/clang → 机器码 (信任 C 编译器)
改进: Why3 → CakeML 提取 → CakeML 编译器 → 机器码 (编译器已验证)

注意:CakeML 替代的是 C 编译器(gcc/clang),不是 Coq。 它作为 Why3 的"第二个提取后端",让编译阶段也有 Coq 级别的形式化保证,与 Coq 证明后端并列——一个保证证明正确,一个保证编译正确。

现状: WhyML→CakeML 在架构上可行,Dafny 2025 已有 Dafny→CakeML 先例。但没有人做过 WhyML→CakeML,需要自己实现翻译层。


六、对各语言的建议

6.1 Rust

地位: L0-L2 最佳实现语言,验证需借助 Why3/Creusot。

  • L0(类型系统+lint):✅ 最佳
  • L1(穷举测试+oracle):✅ proptest + MPFR FFI
  • L2(Kani 模型检查):✅ 有限但够用
  • L3+(Gappa/Coq):❌ 需要走出 Rust。LLVM 没有形式化浮点语义

6.2 TypeScript

不适合。 TS 的 number 是 IEEE 754 binary64,但:

  • 无法控制舍入模式、检测浮点异常、做位编码操作
  • TS 验证工具(TheoremTS、Plumbproof)面向业务逻辑(金额守恒),不是数值分析(ULP 误差界)
  • 脚本语言的浮点语义是"whatever the runtime does"——与形式化验证的"exactly what the spec says"结构性矛盾

6.3 Julia

适合作为算法原型 + oracle,不适合作为形式化验证平台。

  • IntervalArithmetic.jl(IEEE 1788-2015):保证计算结果包含真值
  • ValidatedNumerics.jl:捆绑区间求根、全局优化、Taylor 模型
  • llvmcall + constrained intrinsics:比 Rust 更底层控制 LLVM 浮点语义

鸿沟: 区间算术给出 bound,但不是机器可检查的证明。Julia 社区在讨论生成 Lean/Coq certificate,但未实现。

6.4 Python

不适合。 Nagini 的浮点验证非常有限,重点在内存安全和引用计数,不在精度。

6.5 总结矩阵

浮点语义确定性

│ C + fenv SPARK/Ada

│ Dafny

│ Rust Julia

│ Python TypeScript
└──────────────────────────────→ 验证工具成熟度

七、推荐方案

7.1 核心架构

手写 WhyML
(ieee_float + 算法 + 误差 bound 证明)

┌────────────┼────────────┐
↓ ↓ ↓
Why3 验证通过 Why3→Coq VCs (未来) Why3→CakeML
│ ↓ ↓
│ Coq/Flocq 证明 验证的机器码
│ (L4: 完整正确舍入)

Why3 提取到 C
(可信任的参考实现)

┌────────┼────────┐
↓ ↓ ↓
AI→Rust AI→Julia 保留 C
│ │ │
└───┬────┘────────┘

差分测试对齐
(穷举 f32 + 随机 f64 + hard-to-round cases + CORE-MATH oracle)

7.2 Why3 直接使用 vs Frama-C + Why3 的选择

推荐分两步验证,而非二选一:

阶段任务时间
PilotWhy3 直接使用——选 cr_sqrtf 在 WhyML 中完成全链路:IEEE 754 标注 → Gappa 误差 bound → SMT 程序逻辑 → 提取到 C → 和 CORE-MATH 交叉验证2-4 周
决策点基于 Pilot 结果决定后续路线

Pilot 结果决策矩阵:

Pilot 结果建议
WhyML 流程顺畅继续深化 Why3 路径,WhyML 成为真理源
WhyML 写起来太痛苦转 Frama-C + ACSL,直接在 CORE-MATH C 代码上加标注
Gappa 对 range reduction 处理不了已知局限,需 Coq 介入(不影响 Why3/C 的选择)
AI 翻译 C→Rust 质量好Why3→C + AI 翻译路径可行,不需要 Dafny 的 Rust 提取

7.3 各验证层的归属

层级保证内容归属
L0(类型系统+lint)降低 UB/panic 风险每种目标语言自己做
L1(穷举测试+oracle)f32 穷举 + f64 采样 + hard-to-round cases语言相关,但 oracle 和测试集跨语言共享
L2(模型检查)无 panic/越界/溢出每种语言自己做(Kani/Creusot/Frama-C)
L3(Gappa 多项式误差)逼近误差 bound语言无关,一次证明,所有语言复用系数和误差 bound
L4(Coq/Flocq 完整证明)正确舍入语言无关,对关键函数做,作为 L3 最终保险

"银弹"的核心是 L3。L4 是"如果某个函数需要最高保证"的选项。

7.4 可移植的资产清单

无论选择哪个验证平台,以下资产是独立于语言和工具的:

  1. Gappa 证明脚本(语言无关)——证明多项式误差
  2. 系数生成脚本(Sollya,语言无关)——魔术参数出处
  3. 测试向量集(f32 全部 + f64 采样)——差分测试基础
  4. Hard-to-round cases 列表——边界保证
  5. Oracle 参考输出(MPFR 高精度)——正确的标准
  6. Coq/Flocq 证明(语言无关)——终极保证

AI 翻译到目标语言后,用 3-5 做差分测试。1-2 保证系数正确性跨语言复用。6 是终极保险。


八、风险与局限

风险说明缓解
WhyML 学习曲线WhyML 不是主流语言,没有 Rust/C 的社区体量Pilot 阶段快速验证可行性
超越函数需要公理化sin/cos/exp 在 Why3 的 real 理论中是未解释符号手写公理,或依靠 Coq/Flocq
Gappa 只擅长直线代码Range reduction 含条件分支和取模,超出区间分析范围需 Coq 手动介入
没有 Rust 提取WhyML→Rust 不存在AI 翻译 C→Rust + 差分测试弥补
CORE-MATH 只有部分函数有 Coq 证明L4 的现实上限你的 L4 作为文档和演进目标,不急
形式化验证 + 数学库两个深坑需设边界防无限考古Pilot 阶段设明确完成定义

九、相关资源