| Thread overview | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 03, 2009 Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Is it portable to rely on unsigned integer types wrapping to their max value when they are subtracted from too many times, i.e. uint foo = 0; foo--; assert(foo == uint.max); ulong bar = 0; bar--; assert(bar == ulong.max); ubyte baz = 0; baz--; assert(baz == ubyte.max); I assume that in theory this is hardware-specific behavior and not guaranteed by the spec, but is it universal enough that it can be considered portable in practice? | ||||
January 03, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote: > Is it portable to rely on unsigned integer types wrapping to their max value > when they are subtracted from too many times, i.e. > > uint foo = 0; > foo--; > assert(foo == uint.max); > > ulong bar = 0; > bar--; > assert(bar == ulong.max); > > ubyte baz = 0; > baz--; > assert(baz == ubyte.max); > > I assume that in theory this is hardware-specific behavior and not guaranteed > by the spec, Not so. You can rely on this. It's a fundamental mathematical property. but is it universal enough that it can be considered portable in > practice? | |||
January 03, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don:
> Not so. You can rely on this. It's a fundamental mathematical property.
If integral overflow checks are introduced, they will become compile/runtime errors.
Bye,
bearophile
| |||
January 03, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote: > Don: >> Not so. You can rely on this. It's a fundamental mathematical property. > > If integral overflow checks are introduced, they will become compile/runtime errors. The question was about incrementing uint, not int. Preventing wraparound on uints would break everything! > > Bye, > bearophile | |||
January 03, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote:
> Is it portable to rely on unsigned integer types wrapping to their max value
> when they are subtracted from too many times, i.e.
>
> uint foo = 0;
> foo--;
> assert(foo == uint.max);
>
> ulong bar = 0;
> bar--;
> assert(bar == ulong.max);
>
> ubyte baz = 0;
> baz--;
> assert(baz == ubyte.max);
>
> I assume that in theory this is hardware-specific behavior and not guaranteed
> by the spec, but is it universal enough that it can be considered portable in
> practice?
Walter's intent is to put that guarantee in the language.
Andrei
| |||
January 05, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | Don:
> The question was about incrementing uint, not int. Preventing wraparound on uints would break everything!
If optional runtime overflow controls are added to integral values, then they are performed on ubyte/ushort/uint/ulong/ucent too, because leaving a hole in that safety net is very bad and useless.
In modules where you need wraparounds, you can tell the compiler to disable such controls (recently I have suggested a syntax that works locally: safe(...) {...}, but Walter seems to prefer a module-level syntax for this).
Bye,
bearophile
| |||
January 05, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | bearophile wrote: > Don: >> The question was about incrementing uint, not int. Preventing wraparound on uints would break everything! > > If optional runtime overflow controls are added to integral values, then they are performed on ubyte/ushort/uint/ulong/ucent too, because leaving a hole in that safety net is very bad and useless. But uints HAVE no overflow! In the case of an int, you are approximating a mathematical infinite-precision integer. An overflow means you went outside the available precision. A uint is quite different. uint arithmetic is perfectly standard modulo 2^32 arithmetic. Don't be confused by the fact that many people use them as approximations to infinite-precision positive integers. That's _not_ what they are. Consider for example machine addresses on a 32-bit address bus. Given pointers p and q, p + q - p is perfectly well defined, and is always equal to q. It makes no difference whether p is greater than or less than q. q-p is definitely not an int. (q could be uint.max, and p could be 0). Likewise, p+1 is always defined, even if p is uint.max (p+1 will then be 0). > In modules where you need wraparounds, you can tell the compiler to disable such controls (recently I have suggested a syntax that works locally: safe(...) {...}, but Walter seems to prefer a module-level syntax for this). > > Bye, > bearophile | |||
January 05, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Don | "Don" <nospam@nospam.com> wrote in message news:gjsnf2$26g4$1@digitalmars.com... > bearophile wrote: >> Don: >>> The question was about incrementing uint, not int. Preventing wraparound on uints would break everything! >> >> If optional runtime overflow controls are added to integral values, then they are performed on ubyte/ushort/uint/ulong/ucent too, because leaving a hole in that safety net is very bad and useless. > > But uints HAVE no overflow! In the case of an int, you are approximating a > mathematical infinite-precision integer. An overflow means you went > outside the available precision. > A uint is quite different. > uint arithmetic is perfectly standard modulo 2^32 arithmetic. > Don't be confused by the fact that many people use them as approximations > to infinite-precision positive integers. That's _not_ what they are. > A uint is an int with the domain of possible values shifted by +uint.max/2 (while retaining binary compatibility with the overlapping values, of course). Modulo 2^32 arithmetic is just one possible use for them. For other uses, detecting overflow can be useful. | |||
January 05, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | == Quote from Nick Sabalausky (a@a.a)'s article
> "Don" <nospam@nospam.com> wrote in message news:gjsnf2$26g4$1@digitalmars.com...
> > bearophile wrote:
> >> Don:
> >>> The question was about incrementing uint, not int. Preventing wraparound on uints would break everything!
> >>
> >> If optional runtime overflow controls are added to integral values, then they are performed on ubyte/ushort/uint/ulong/ucent too, because leaving a hole in that safety net is very bad and useless.
> >
> > But uints HAVE no overflow! In the case of an int, you are approximating a
> > mathematical infinite-precision integer. An overflow means you went
> > outside the available precision.
> > A uint is quite different.
> > uint arithmetic is perfectly standard modulo 2^32 arithmetic.
> > Don't be confused by the fact that many people use them as approximations
> > to infinite-precision positive integers. That's _not_ what they are.
> >
> A uint is an int with the domain of possible values shifted by +uint.max/2 (while retaining binary compatibility with the overlapping values, of course). Modulo 2^32 arithmetic is just one possible use for them. For other uses, detecting overflow can be useful.
Mostly, I was thinking that relying on this behavior wouldn't work if some DS9K architecture used a signed int representation other than two's complement or used saturation arithmetic. Am I wrong here, too?
| |||
January 05, 2009 Re: Portability of uint over/underflow behavior | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | Nick Sabalausky wrote:
> "Don" <nospam@nospam.com> wrote in message news:gjsnf2$26g4$1@digitalmars.com...
>> bearophile wrote:
>>> Don:
>>>> The question was about incrementing uint, not int. Preventing wraparound on uints would break everything!
>>> If optional runtime overflow controls are added to integral values, then they are performed on ubyte/ushort/uint/ulong/ucent too, because leaving a hole in that safety net is very bad and useless.
>> But uints HAVE no overflow! In the case of an int, you are approximating a mathematical infinite-precision integer. An overflow means you went outside the available precision.
>> A uint is quite different.
>> uint arithmetic is perfectly standard modulo 2^32 arithmetic.
>> Don't be confused by the fact that many people use them as approximations to infinite-precision positive integers. That's _not_ what they are.
>>
>
> A uint is an int with the domain of possible values shifted by +uint.max/2 (while retaining binary compatibility with the overlapping values, of course). Modulo 2^32 arithmetic is just one possible use for them. For other
> uses, detecting overflow can be useful.
I suspect that in most of the cases you're thinking of, you actually want to detect when the result is greater than int.max, not when it exceeds uint.max?
What you're calling 'overflow' in unsigned operations is actually the carry flag. The CPU also an overflow flag which applies to signed operations. When it's set, it means the result was so big that the sign was corrupted. (eg int.max + int.max gives a negative result). An overflow is always an error, I think. (And if you were using (say) a sign-magnitude representation instead of 2-s complement, int.max+int.max would be a _different_ wrong number).
But a carry is not an error. It's expected, and indicates that a wraparound occured.
By the way, there are other forms of integer which _are_ supported in x86 hardware. Integers which saturate to a maximum value can be useful. ie, (int.max + 1 == int.max)
| |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply