> Why? Because it's the choice that doesn't result in information loss when overflow occurs.
AFAIK, arithmetic overflow is exactly means that bits of information were lost during the calculation. Furthermore, for the wrap around behavior, the lost bits are the most significant ones, so the result of a wrapping signed overflow on addition or subtraction couldn't be more erroneous than any other possible behavior: the distance from the mathematical result is exactly 2^N. For multiplication, wrapping signed overflow could happen at any intermediate addition so the distance could go up to somewhere near 2^(2N-1). The best possible way to minimize the distance between the mathematical and the result of computation would be to drop the low order bits instead of the high order bits, which is what saturation arithmetic does.
There are specialized use cases for saturating arithmetic. I'm surprised to see it being repeatedly brought up as a plausible general behaviour for integer overflow.
I keep hearing people bring up the freedom that UB gives to the implementation. Is anyone aware of any implementation that has used this freedom to implement saturating behaviour in order to minimize the error?
Is anyone aware of any popular programming language that defines the behaviour of the built-in arithmetic operations on the built-in integer types to saturate on overflow, or even provides an option to configure the behaviour as such?
What conclusions can we draw? Saturating arithmetic has its use cases, but outside of those use cases the expectation when using integer arithmetic is that the mathematically correct result will be produced. If that result cannot be produced, the code has a bug.
> In particular, for example, in an expression of the form `a + b - c`, if `a + b` overflows but the final result fits in the type, you will actually get the correct result if the type is specified to wrap.
That is not true in the general case, here you assumed that "a>0, b>0, c>=0". What about the case when "c<=0" or "a<0, b<0, c<=0"? Also, if the compiler can deduce that a, b, c are non negative and that "a+b" does not overflow because it is UB, then it can transform "(a+b)-c" into "a+(b-c)" thereby giving a permissible defined behavior; note that this transformation would also be permissible if the overflow behavior is defined to wrap but this wouldn't optimize anything, although if this would change behavior if both trapping and wrapping were required (gcc doesn't allow both, but in principle it could).
I did not assume anything about the signs of `a`, `b`, and `c`. I said that if the final result fits in the type, then wrapping behaviour will give the right answer after the intermediate overflow. No other semantics can guarantee the correct result in that case (UB of course allows it but does not guarantee it).
In general, for a signed integer expression "(a ± b) ± c" if "a ± b" did overflow then the result of the hole expression may be off by 2^N or 2^(N+1) if a second overflow occurs. If you keep on chaining additions or subtractions then the distance from the true result will be in the set {0, 2^N, 2^(N+1), 2^(N+2), ... 2^(N+M)} adding one possible erroneous value for each operation performed, giving you a low probably of yielding the mathematical result. I'm not even gonna try to count the number erroneous possibilities if you put in the multiplication and division operations, but it is clear that the probability space explodes in numbers.
On 04/09/2025 07:48, Peter C++ via Std-Proposals wrote:
> FWIW
>
> one can implement efficient non-UB integer replacement types, eg, for
> safety critical systems using enum class types as representation.
>
> see for example: https://github.com/PeterSommerlad/PSsimplesafeint
> <https://github.com/PeterSommerlad/PSsimplesafeint>
>
> Regards
> Peter
>
You can indeed make such classes - and give them dangerously misleading
names like "Simple Safe Int".
It is fine to implement wrapping signed integer classes if that's what
you want - it is /not/ fine to pretend they are somehow safe or suitable
for safety-critical systems. It doesn't matter if your overflows wrap -
if you have an overflow, your safety-critical system is screwed.
(Some other aspects of your library /are/ positive for safety, such as
disallowing mixed signed operations and limiting certain other
operations. It's only the overflow behaviour I am in strong
disagreement about.)
You'd be a lot better off with :
using SignificantlySaferIntType = int64_t;
That would eliminate the vast majority of signed integer overflow bugs,
and give the /correct/ answer to 32-bit overflows.
And anyone writing new code with enough care about overflow and code
correctness that they might consider something beyond just using "int",
will already be able to handle overflow in various ways - such as
sanitizing values before calculations ("look before you leap", rather
than trying to find a way to recover from jumping off a cliff and
somehow ending up miles in the air). The checked arithmetic functions
in C++26 are another option.
I am in favour of integer class libraries that handle overflow in
different ways. But the naming should be based on what is actually done
- undefined behaviour, wrapping, zeroing, throwing, trapping, calling
terminate/abort/whatever, saturating, returning an unspecified but valid
value, setting errno, etc.
I am not in favour of pretending or implying that the use of a
particular integer class makes the code "safe" (or even just "safer").
I think that actually, wrapping behaviour is safer than UB, saturating behaviour, or producing an unspecified value. I won't claim that it's completely safe.
Why? Because it's the choice that doesn't result in information loss when overflow occurs. In particular, for example, in an expression of the form `a + b - c`, if `a + b` overflows but the final result fits in the type, you will actually get the correct result if the type is specified to wrap.
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals