Infinite precision intermediate arithmetic: how much would break?

logickkk11 pts0 comments

Infinite precision intermediate arithmetic: how much would break? - language design - Rust Internals

= 40rem)" rel="stylesheet" data-target="desktop" />

= 40rem)" rel="stylesheet" data-target="discourse-ai_desktop" /><br>= 40rem)" rel="stylesheet" data-target="poll_desktop" />

> produce the mathematically correct dividend. At each point where the result of an arithmetic evaluation must be ascribed a definite type, that type is chosen based on surrounding context, and it is an error if the compiler cannot prove that all ..." /><br>> produce the mathematically correct dividend. At each point where the result of an arithmetic evaluation must be ascribed a definite type, that type is chosen based on surrounding context, and it is an error if the compiler cannot prove that all ..." />

Infinite precision intermediate arithmetic: how much would break?

language design

zackw

June 8, 2026, 2:52pm

I wonder how much stuff would break if the rules for evaluating arithmetic expressions were changed like so:

All arithmetic expressions are evaluated as-if in ℝ (or ℂ if necessary). In particular, all widening conversions become redundant, and / and >> produce the mathematically correct dividend.

At each point where the result of an arithmetic evaluation must be ascribed a definite type, that type is chosen based on surrounding context, and it is an error if the compiler cannot prove that all possible outputs of the calculation are representable in that type.

You can fix those errors by writing explicit narrowing conversions that tell the compiler what to do when the result is inexact or out of range. Generated machine code is guaranteed to truncate or round results only where one of these explicit conversions appears.

There is a way to write pure functions that take arguments and/or return values in the infinite-precision intermediate representation (this is necessary at least to implement the math library; it can probably be private to std to begin with).

For example, with these rules let sum: u64 = a.saturating_add(b).saturating_add(c) could become let sum:u64 = (a + b + c).saturate().

I'm sure there are a whole bunch of problems with this idea, but the thing is, the last several times I got in a fight with Rust's type system all involved needing to write a zillion explicit conversions among u32, u64 and usize, so right now my gut feeling is the fallout might be worth it.

2 Likes

jdahlstrom

June 8, 2026, 3:59pm

This is, btw, essentially what C does, except the "infinite" precision is just to long int, and narrowing coercions back are implicit.

Realistically, this proposal hinges on the ability of the compiler to prove non-overflow in "typical uses", and that would require importing a lot of machinery to the front end from LLVM, be difficult to write a specification for, and would probably fail often enough that people would get massively frustrated when their i += 1 doesn't work and has to be rewritten as i = (i + 1).unwrap() or something. Proving anything about basic arithmetic is, of course, undecidable in the fully general case and NP-complete in somewhat less general cases; the optimizer gets away with it because it works strictly on a best effort basis. But surface language semantics cannot be best-effort.

jrose

June 8, 2026, 4:10pm

(This is not what C does, C only implicitly goes up to int.)

jdahlstrom

June 8, 2026, 4:11pm

Oops, should've checked, I thought it was to long (which is the same thing in many cases, but anyway…) Fixed.

chrefr

June 8, 2026, 4:42pm

The first problem is performance. Widening integer operations to i/u128 makes them way more expensive; widening float operations to ℝ will require extremely costly software calculations.

The second problem is that this is silently breaking a lot of code and there is basically no way to estimate the breakage; this is the worst kind of breakage.

But the worst of all is that C has shown that promotion rules are deeply unintuitive and confusing, and the vast majority of developers never understand them well. The current "no implicit conversions" policy is a very good idea even if it sometimes costs in extra characters. Performing implicit widening conversions is bad but acceptable; performing implicit narrowing conversions, like you suggest here, is a terrible idea.

3 Likes

zackw

June 8, 2026, 6:02pm

jdahlstrom:

This is, btw, essentially what C does

Besides what @jrose already said about this, there is a huge practical difference between "only goes up to [some fixed-length type]" and actually going to infinity in both directions. For example, in C comparisons between signed and unsigned values silently do the Wrong Thing, and in Rust (as it is now)

pub fn isless(a: i32, b: u32) -> bool {<br>fails to compile but the suggested fix does not produce code that computes the mathematically correct answer. Under my proposal this would be equivalent to

pub fn isless(a: i32, b: u32) -> bool {<br>// a u32 value that doesn't fit in i32 must be...

arithmetic type conversions june infinite precision

Related Articles