Repository navigation
fix(number): make equality and ordering exact - #846
Conversation
892863a to
aebd6a8
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Regression coverage still needs genuinely out-of-f64-range integers and compiled RVM execution.
2 open issues
What changed in this PR
Makes numeric equality and ordering exact and consistent, preventing distinct numbers from merging in sets and object keys.
Changes:
- Replaces lossy mixed-number comparisons with exact integer scaling.
- Preserves signed-zero equality and defines deterministic non-finite ordering.
- Adds regression tests and updates the Verus comparison model.
| File | Description |
|---|---|
| tests/interpreter/cases/builtins/units/parse.yaml | Preserves exact large-integer expectations. |
| tests/interpreter/cases/builtins/units/parse_bytes.yaml | Preserves exact large-integer expectations. |
| tests/gate_cmp_exactness.rs | Adds public-boundary comparison regressions. |
| src/verify/number_specs.rs | Models exact numeric ordering. |
| src/number.rs | Implements exact comparisons and internal tests. |
Review effort: Balanced
aebd6a8 to
abd58ec
Compare
abd58ec to
ee5d60f
Compare
12877a2 to
6d1d3fe
Compare
Compare mixed float and integer values without lossy f64 conversion, and use a coherent total order for defensive non-finite values. Add public-boundary and in-crate regression coverage plus an exact Verus comparison model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 83d6af09-e009-4535-acfd-fc9aa756fc3a
6d1d3fe to
888bf87
Compare
Jay Lorch (jaylorch)
left a comment
There was a problem hiding this comment.
I stopped reviewing around line #489, after finding many problems and bugs. I think it would be useful to fix those and apply similar fixes to the rest of the PR before I continue reviewing.
Jay Lorch (jaylorch)
left a comment
There was a problem hiding this comment.
I stopped reviewing around line #489, after finding many problems and bugs. I think it would be useful to fix those and apply similar fixes to the rest of the PR before I continue reviewing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 83d6af09-e009-4535-acfd-fc9aa756fc3a
|
Addressed all current review threads in Highlights: exponent 2047 and sign-bit handling are explicit; scaled comparison now uses a common exponent; the Jay Lorch (@jaylorch), please re-review these changes and continue beyond the original line 489 when convenient. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 83d6af09-e009-4535-acfd-fc9aa756fc3a
|
Addressed the latest review round in The internal order is now Local verification: Number 73/0, comparison proofs 16/0, full Verus 105/0; Number 10/10, comparison 6/6, arithmetic 3/3, RVM fixture passed; Rust 1.95 strict Clippy, formatting, and diff checks passed. Jay Lorch (@jaylorch), please re-review when convenient. |
Jay Lorch (jaylorch)
left a comment
There was a problem hiding this comment.
Getting close! There are now a few extraneous spec functions that don't need to be there.
There are still a few external_body functions, which is unfortunate, but we can just plan to fix those in a later PR. It seems like the agent isn't quite up to the task, and it will require some human assistance.
Remove redundant comparison models and use the scaled-value specification for every representation pair. Update the integer proof and add exact-cast explanations and comparison regressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 12523f37-af5f-4614-a3a4-eb754e1b9989
Jay Lorch (jaylorch)
left a comment
There was a problem hiding this comment.
We should try to get rid of the external_body instances in a later PR, but for now this looks good. Thanks!
|
Thanks for the thorough review Jay Lorch (@jaylorch). Much appreciated. |

Summary
Make
Numberequality and ordering exact and coherent.f64BigInts and use at most one binary64-bounded temporary for integral float/BigIntcomparisonEqandOrd, including deterministic defensive handling if a non-finiteNumberreaches the internal type-0.0 == 0)Ord,PartialEq, NaN dispatch, and the integer/BigIntcomparison dispatch, leaving only unsupported native float comparison helpers as narrow trusted boundariesSecurity impact
The previous lossy comparison could make a float at
2^63compare equal to both exact integers2^63and2^63 + 1. It could also make out-of-rangeBigIntvalues compare equal to infinity. That violated equality transitivity and allowed distinct set elements or object keys to be silently merged.This PR fixes comparison semantics only. It is rebased onto
mainafter #845 and preserves its finite-arithmetic error paths and strengthened Verus contracts; the diff does not change numeric ingress, arithmetic overflow/promotion, formatting, or compiled-blob validation.Ordering contract
This is an internal
Eq/Ordcontract:finite integers and floats follow exact mathematical ordering
-0.0,0.0, and integer zero remain equalthe complete internal order is:
-∞ < negative finite numbers < (-0.0 = +0.0 = integer 0) < positive finite numbers < +∞ < NaNEvery NaN sign and payload compares equal to every other NaN, matching CEL equality. NaN remains distinct from infinities and finite values.
Language frontends that require different NaN operator semantics should implement those operators separately rather than expose this internal storage order.
Verification model
The Verus model specifies exact finite scaled-integer comparison and a terminal NaN equality class.
Ord,PartialEq, NaN dispatch, integer comparisons, andBigInt/primitive comparisons are body-verified. Four narrowexternal_bodyhelpers retain exact postconditions for operations this Verus toolchain cannot connect to the binary64 bit model: guarded float-to-integer casts,FloatCore::integer_decodewith BigInt shifts, and native non-NaN float comparisons. No global axiom assumes the final comparison correspondence.Verification
cargo test- 344 passed, 2 ignored, plus all integration suites passedcargo test --test gate_cmp_exactnesscargo test --test gate_promotionunits.parseandunits.parse_bytesfixturescargo test --no-default-features --tests --no-runnumberverification: 73 verified, 0 errorscargo clippy --all-targets --all-features -- -Dwarnings