digitalmars.D.learn - Integer promotion... what I'm missing? (It's monday...)
- Paolo Invernizzi (8/8) Jun 19 2006 Hi all,
- Daniel Keep (19/31) Jun 19 2006 If you read http://digitalmars.com/d/type.html, you will find the rules
- Tony (13/39) Jun 19 2006 I believe it is a mistake to have an operation like this occur when it i...
- Lionello Lunesu (6/10) Jun 19 2006 I agree!
- Derek Parnell (10/20) Jun 19 2006 No argument from me. This has often caused me grief. The two most often ...
- Deewiant (6/11) Jun 19 2006 What should be done when one number is an ulong too big to fit in a long...
- Paolo Invernizzi (7/15) Jun 19 2006 Instead of a warning, I would prefer an error, forcing for an explicit
- Tom S (5/8) Jun 19 2006 I'd also like DMD to issue an error in this case, as I've stumbled upon
- Derek Parnell (11/25) Jun 19 2006 Just to note that with DMD, a 'warning' is really an optional error. In
- Alexander Panek (10/22) Jun 27 2006 If you take a look at how comparison works, you'll know why this one fai...
- Kirk McDonald (4/32) Jun 27 2006 Your point still stands, but -1 is represented as:
- Paolo Invernizzi (15/51) Jun 28 2006 You both are true, and I know about Two's complement...
- Max Samuha (6/38) Jun 28 2006 Maybe it's not a bug but it is very confusing, no matter how integer
- Kirk McDonald (20/68) Jun 28 2006 It's worth noting that this behavior (of a being less than b) follows
- Don Clugston (8/82) Jun 28 2006 That would introduce a massive performance hit. The existing conversion
- Paolo Invernizzi (5/9) Jun 28 2006 That was a comparison between an unsigned/signed CONSTANTS, that's the
- SwiftCoder (3/3) Jun 29 2006 It would seem that this is not unique to D, C++ also exhibits this behav...
Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 19 2006
Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- PaoloIf you read http://digitalmars.com/d/type.html, you will find the rules for integer promotion under arithmetic operations (which I assume also includes comparisons). Note point 5.4 under "Usual Arithmetic Conversions": 5.4. The signed type is converted to the unsigned type. Hence, b is being converted to a uint. cast(uint)(-1) = ~0 = uint.max, hence why b is not less than a. If you're going to compare a signed and unsigned type directly, it's best to explicitly cast them to a common type, or strange things like this could happen :) Either convert a to an int (and watch for overflow), or convert them both to a long (so you don't have problems with overflow). -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Jun 19 2006
"Daniel Keep" <daniel.keep.lists gmail.com> wrote in message news:e75qg4$2bt$1 digitaldaemon.com...Paolo Invernizzi wrote:I believe it is a mistake to have an operation like this occur when it is both mathematically incorrect and unintuitive. It feels like something that is destined to be a Bug Breeder. I would prefer that any type promotions (and any implicit operations for that matter) should guarantee not to introduce any data corruption. In this case, promote both numbers to a third type which can hold all possible values from both. If the user wishes to override that by making explicit conversions, at least this will be visible in the code. Tony Melbourne, AustraliaHi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- PaoloIf you read http://digitalmars.com/d/type.html, you will find the rules for integer promotion under arithmetic operations (which I assume also includes comparisons). Note point 5.4 under "Usual Arithmetic Conversions": 5.4. The signed type is converted to the unsigned type. Hence, b is being converted to a uint. cast(uint)(-1) = ~0 = uint.max, hence why b is not less than a. If you're going to compare a signed and unsigned type directly, it's best to explicitly cast them to a common type, or strange things like this could happen :) Either convert a to an int (and watch for overflow), or convert them both to a long (so you don't have problems with overflow). -- Daniel
Jun 19 2006
Tony wrote:I would prefer that any type promotions (and any implicit operations for that matter) should guarantee not to introduce any data corruption. In this case, promote both numbers to a third type which can hold all possible values from both.I agree! Perhaps this could also prevent the "array.length-1" bug (which is ~0 when array.length == 0), by making "array.length-1" a "long" instead of a "uint". L.
Jun 19 2006
On Mon, 19 Jun 2006 20:11:32 +1000, Tony <ignorethis nowhere.com> wrote:. . .If you read http://digitalmars.com/d/type.html, you will find the rules for integer promotion under arithmetic operations (which I assume also includes comparisons). Note point 5.4 under "Usual Arithmetic Conversions": 5.4. The signed type is converted to the unsigned type.I believe it is a mistake to have an operation like this occur when it is both mathematically incorrect and unintuitive. It feels like something that is destined to be a Bug Breeder.No argument from me. This has often caused me grief. The two most often gotchas for me is mismatched template parameters due to this stupid rule, and that array length is a uint which means that all expressions involving array.length get silently converted to uint before the evaluation and that can mess up index accesses. -- Derek Parnell Melbourne, Australia
Jun 19 2006
Tony wrote:I would prefer that any type promotions (and any implicit operations for that matter) should guarantee not to introduce any data corruption. In this case, promote both numbers to a third type which can hold all possible values from both.What should be done when one number is an ulong too big to fit in a long and the other is a negative number? (Replace "long" with "cent" if we ever get the type.) No matter how the promotion is done, corruption occurs. I think a warning for all such cases would suffice --- I thought one would be emitted for the original code, but evidently not.
Jun 19 2006
Deewiant wrote:Tony wrote:Instead of a warning, I would prefer an error, forcing for an explicit cast if the comparison it's what you really want to to. But only for rule number 4. Cheers --- PaoloI would prefer that any type promotions (and any implicit operations for that matter) should guarantee not to introduce any data corruption. In this case, promote both numbers to a third type which can hold all possible values from both.I think a warning for all such cases would suffice --- I thought one would be emitted for the original code, but evidently not.
Jun 19 2006
Paolo Invernizzi wrote:Instead of a warning, I would prefer an error, forcing for an explicit cast if the comparison it's what you really want to to. But only for rule number 4.I'd also like DMD to issue an error in this case, as I've stumbled upon it a few times. -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jun 19 2006
On Tue, 20 Jun 2006 04:06:37 +0200, Paolo Invernizzi wrote:Deewiant wrote:Just to note that with DMD, a 'warning' is really an optional error. In other words, if you have -w switch and it displays a 'warning', the compiler still fails to create the object file because it treats such warnings as if they were errors. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 20/06/2006 11:04:06 AMTony wrote:Instead of a warning, I would prefer an error, forcing for an explicit cast if the comparison it's what you really want to to. But only for rule number 4.I would prefer that any type promotions (and any implicit operations for that matter) should guarantee not to introduce any data corruption. In this case, promote both numbers to a third type which can hold all possible values from both.I think a warning for all such cases would suffice --- I thought one would be emitted for the original code, but evidently not.
Jun 19 2006
If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001 You might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 27 2006
Alexander Panek wrote:If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001Your point still stands, but -1 is represented as: 11111111 11111111 11111111 11111111 http://en.wikipedia.org/wiki/Two%27s_complementYou might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 27 2006
You both are true, and I know about Two's complement... But, as others in the thread pointed out, that's just a way of "represent" a number, and, worst, in this case, they are just "constant": uint a = 16; int b = -1; assert(b < a); No ambiguity at all. This can be folded. And in the real world, -1 is less than 16. So, as one of the main principle of the D programming language is to minimize the risks of bugs, I feel that at least a Warning should be raised for that code... But really, it's just a minor glitch... Cheers --- Paolo Kirk McDonald wrote:Alexander Panek wrote:If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001Your point still stands, but -1 is represented as: 11111111 11111111 11111111 11111111 http://en.wikipedia.org/wiki/Two%27s_complementYou might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 28 2006
On Tue, 27 Jun 2006 12:33:32 -0700, Kirk McDonald <kirklin.mcdonald gmail.com> wrote:Alexander Panek wrote:Maybe it's not a bug but it is very confusing, no matter how integer operations work internally. Compiler should give at least a warning about incompatibe types, or try to cast uint to int implicitly or require an explicit cast.If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001Your point still stands, but -1 is represented as: 11111111 11111111 11111111 11111111 http://en.wikipedia.org/wiki/Two%27s_complementYou might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 28 2006
Max Samuha wrote:On Tue, 27 Jun 2006 12:33:32 -0700, Kirk McDonald <kirklin.mcdonald gmail.com> wrote:It's worth noting that this behavior (of a being less than b) follows the implicit conversion rules exactly: http://www.digitalmars.com/d/type.html [snipped non-applicable checks...] 5. Else the integer promotions are done on each operand, followed by: 1. If both are the same type, no more conversions are done. 2. If both are signed or both are unsigned, the smaller type is converted to the larger. 3. If the signed type is larger than the unsigned type, the unsigned type is converted to the signed type. 4. The signed type is converted to the unsigned type. So the int is implicitly converted to the uint, and (apparently) it simply compares 2**32-1 to 16. So I wouldn't call this a bug, just a potential oddity. Maybe it should detect and throw an overflow if a negative signed integer is converted to an unsigned type? Or not: I'd consider this an edge case. It's probably considered bad practice to promiscuously mix signed and unsigned types. -Kirk McDonaldAlexander Panek wrote:Maybe it's not a bug but it is very confusing, no matter how integer operations work internally. Compiler should give at least a warning about incompatibe types, or try to cast uint to int implicitly or require an explicit cast.If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001Your point still stands, but -1 is represented as: 11111111 11111111 11111111 11111111 http://en.wikipedia.org/wiki/Two%27s_complementYou might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paolo
Jun 28 2006
Kirk McDonald wrote:Max Samuha wrote:That would introduce a massive performance hit. The existing conversion from signed to unsigned occurs only at compile time. Or not: I'd consider this an edge case. It'sOn Tue, 27 Jun 2006 12:33:32 -0700, Kirk McDonald <kirklin.mcdonald gmail.com> wrote:It's worth noting that this behavior (of a being less than b) follows the implicit conversion rules exactly: http://www.digitalmars.com/d/type.html [snipped non-applicable checks...] 5. Else the integer promotions are done on each operand, followed by: 1. If both are the same type, no more conversions are done. 2. If both are signed or both are unsigned, the smaller type is converted to the larger. 3. If the signed type is larger than the unsigned type, the unsigned type is converted to the signed type. 4. The signed type is converted to the unsigned type. So the int is implicitly converted to the uint, and (apparently) it simply compares 2**32-1 to 16. So I wouldn't call this a bug, just a potential oddity. Maybe it should detect and throw an overflow if a negative signed integer is converted to an unsigned type?Alexander Panek wrote:Maybe it's not a bug but it is very confusing, no matter how integer operations work internally. Compiler should give at least a warning about incompatibe types, or try to cast uint to int implicitly or require an explicit cast.If you take a look at how comparison works, you'll know why this one fails. Lets take an uint a = 16; as in your example: 00000000 00000000 00000000 00010000 And now a signed integer with the value -1: 10000000 00000000 00000000 00000001Your point still stands, but -1 is represented as: 11111111 11111111 11111111 11111111 http://en.wikipedia.org/wiki/Two%27s_complementYou might guess which number is bigger, when our comparison is done binary (and after all, that's what the processor does) :) Regards, Alex Paolo Invernizzi wrote:Hi all, What I'm missing? uint a = 16; int b = -1; assert( b < a ); // this fails! I was expecting that -1 < 16 Thanks --- Paoloprobably considered bad practice to promiscuously mix signed and unsigned types.It's a hard one. It would be really painful if equality comparisons between signed & unsigned types was an error; it's almost always OK. Comparison of signed/unsigned variables with an unsigned/signed constant is always an error; it would be nice if the compiler detected it.
Jun 28 2006
Don Clugston wrote:It's a hard one. It would be really painful if equality comparisons between signed & unsigned types was an error; it's almost always OK. Comparison of signed/unsigned variables with an unsigned/signed constant is always an error; it would be nice if the compiler detected it.That was a comparison between an unsigned/signed CONSTANTS, that's the mess. They are foldable in that example.... --- Paolo
Jun 28 2006
It would seem that this is not unique to D, C++ also exhibits this behaviour under GCC 4.0 I was just burn't by it in std::vector access.
Jun 29 2006