445,812 Members | 1,324 Online
Need help? Post your question and get tips & solutions from a community of 445,812 IT Pros & Developers. It's quick & easy.

# x == 0 && (x & -1) != 0 for negative zero?

 P: n/a As far as I can tell, (x & -1) is nonzero if the integer x is negative zero. So for signed types, x == 0 does not guarantee (x & foo) == 0. Is that right? (Not that I expect to ever encounter a non-two's-complement machine. Just wondering.) -- Hallvard Sep 11 '07 #1
23 Replies

 P: n/a I wrote: As far as I can tell, (x & -1) is nonzero if the integer x is negative zero. Er, for one's complement anyway. To get weirdness with sign/magnitude as well, we'd need x == 0 && (x ^ 1) < 0. Or (x >1) != 0, but that's implementation-defined. So for signed types, x == 0 does not guarantee (x & foo) == 0. Is that right? (Not that I expect to ever encounter a non-two's-complement machine. Just wondering.) -- Hallvard Sep 11 '07 #2

 P: n/a Hallvard B Furuseth wrote: I wrote: >As far as I can tell, (x & -1) is nonzero if the integer x isnegative zero. Er, for one's complement anyway. To get weirdness with sign/magnitude as well, we'd need x == 0 && (x ^ 1) < 0. Or (x >1) != 0, but that's implementation-defined. >So for signed types, x == 0 does not guarantee(x & foo) == 0. Is that right? (Not that I expect to everencounter a non-two's-complement machine. Just wondering.) Why would you ever use bitwise operations on signed operands? Bitwise logic implies that you've got some bitmap, the natural (and the C) model for it is an unsigned type. [And I suppose you meant (unsigned)-1.] -- Ark Sep 12 '07 #3

 P: n/a Ark Khasin writes: >Hallvard B Furuseth wrote: >>I wrote: >>As far as I can tell, (x & -1) is nonzero if the integer x isnegative zero. Er, for one's complement anyway. To get weirdness withsign/magnitude as well, we'd need x == 0 && (x ^ 1) < 0.Or (x >1) != 0, but that's implementation-defined. >>So for signed types, x == 0 does not guarantee(x & foo) == 0. Is that right? (Not that I expect to everencounter a non-two's-complement machine. Just wondering.) Why would you ever use bitwise operations on signed operands? Bitwise logic implies that you've got some bitmap, the natural (and the C) model for it is an unsigned type. Bitwise logic implies that bitwise operations are useful at the moment. Could be just for e.g. 'a & 15' instead of 'a / 16'. Bit operations on signed integers are common enough, e.g. if one knows that only a fwe of the least siginificant bits are used. Also the choice of type for a variable depends on all the ways it's used, including things like the API for passing it, how it's read/written, and what other integer types it will meet. [And I suppose you meant (unsigned)-1.] No, (unsigned)-1 is not signed. -- Hallvard Sep 13 '07 #4

 P: n/a Hallvard B Furuseth wrote: Bitwise logic implies that bitwise operations are useful at the moment. Could be just for e.g. 'a & 15' instead of 'a / 16'. Those are not the same (think of negative a). `a & 15U` is the same as `a / 16U` if sizeof(a) <=sizeof(unsigned). But I want to see a compiler that doesn't optimize the latter. > Bit operations on signed integers are common enough, which doesn't make it a good practice e.g. if one knows that only a fwe of the least siginificant bits are used. > Also the choice of type for a variable depends on all the ways it's used, including things like the API for passing it, how it's read/written, and what other integer types it will meet. Yes. Designing good API is not for the faint of heart. Which fact doesn't change the point. -- Ark Sep 16 '07 #5

 P: n/a Ark Khasin wrote: > Hallvard B Furuseth wrote: Bitwise logic implies that bitwise operations are useful at the moment. Could be just for e.g. 'a & 15' instead of 'a / 16'. Those are not the same (think of negative a). `a & 15U` is the same as `a / 16U` if sizeof(a) <=sizeof(unsigned). But I want to see a compiler that doesn't optimize the latter. (a & 15) is closer to (a % 16) than to (a / 16) -- pete Sep 16 '07 #6

 P: n/a Ark Khasin writes: >Hallvard B Furuseth wrote: >Bitwise logic implies that bitwise operations are useful at the moment.Could be just for e.g. 'a & 15' instead of 'a / 16'. Duh, a%16 as pete says. Those are not the same (think of negative a). They are the same if you know, which you sometimes do, that a is nonnegtive. _Unless_ (negative zero) & 15 can be 15. (...) >Bit operations on signed integers are common enough, which doesn't make it a good practice What is not good practice is to make a strict rule out of a general guideline like "be careful about signed bit operations". Or "avoid goto". >e.g. if one knowsthat only a fwe of the least siginificant bits are used. >Also the choice of type for a variable depends on all the ways it'sused, including things like the API for passing it, how it'sread/written, and what other integer types it will meet. Yes. Designing good API is not for the faint of heart. Indeed. And two things to keep in mind is that (a) the API can be more important than how a function works internally, and (b) the API may anyway be imposed by something or someone else. Which fact doesn't change the point. The point is that I asked a technical question about code which occurs every now and then, and I wondered if that code is correct. -- Hallvard Sep 17 '07 #7

 P: n/a "Hallvard B Furuseth" >Hallvard B Furuseth wrote: >>Bitwise logic implies that bitwise operations are useful at the moment.Could be just for e.g. 'a & 15' instead of 'a / 16'. Duh, a%16 as pete says. >Those are not the same (think of negative a). They are the same if you know, which you sometimes do, that a is nonnegtive. You the programmer may know that, but if the compiler cannot determine for sure that the value is always positive, it has to generate code that can handle all cases. Since division truncates toward zero, ASR (arithmetic right shift for division) or bitmask (for modulo) is not a solution, it has to be corrected for negative values, which can be done through appropriate bit trickery (on 2s complement architectures ;-). If you know a can only hold positive values, you can tell the compiler by casting it as unsigned (how ugly!) or you can use the shift or mask operations (if the divisor is an explicit power of two). _Unless_ (negative zero) & 15 can be 15. I don't think that's possible. but negative_zero >4 invokes UB anyway. >>Bit operations on signed integers are common enough, which doesn't make it a good practice What is not good practice is to make a strict rule out of a general guideline like "be careful about signed bit operations". Or "avoid goto". There is one good thing about right shifting negative values: the result is implementation defined, not undefined behaviour. You can rely on this operation having consistent behaviour for a given implementation. -- Chqrlie. Sep 18 '07 #8

 P: n/a Charlie Gordon writes: >"Hallvard B Furuseth" Ark Khasin writes: >>>Hallvard B Furuseth wrote:Bitwise logic implies that bitwise operations are useful at the moment.Could be just for e.g. 'a & 15' instead of 'a / 16'. Duh, a%16 as pete says. >>Those are not the same (think of negative a). They are the same if you know, which you sometimes do, thata is nonnegtive. You the programmer may know that, but if the compiler cannot determine for sure that the value is always positive, it has to generate code that can handle all cases. (...) If you know a can only hold positive values, you can tell the compiler by casting it as unsigned (how ugly!) or you can use the shift or mask operations (if the divisor is an explicit power of two). Yes. So despite purist "don't use bit operations on signed values", doing that does make sense at times and is done at times. Except, that should be "nonnegative", not "positive" (which means larger than zero), and of course the compiler sometimes can know if a value is nonnegative, regardless of its signedness. >_Unless_ (negative zero) & 15 can be 15. I don't think that's possible. Why not? Does the standard say? That's what I'm asking about. but negative_zero >4 invokes UB anyway. I suspect so, yes. Which is one reason I asked about the "gentler" bit operations, & and |. (If even they can produce nonzero, certainly >can.) -- Hallvard Sep 18 '07 #9

 P: n/a Hallvard B Furuseth wrote: Charlie Gordon writes: >"Hallvard B Furuseth" >>_Unless_ (negative zero) & 15 can be 15. I don't think that's possible. Why not? Does the standard say? That's what I'm asking about. >but negative_zero >4 invokes UB anyway. I suspect so, yes. Which is one reason I asked about the "gentler" bit operations, & and |. (If even they can produce nonzero, certainly >can.) The only form -0 can take, in an int, ignoring padding bits and expressing the result as a hex 16 bit value (for other lengths insert more copies of the middle bits) are: 0x0000 2's complement 0xFFFF 1's complement 0x8000 sign/magnitude. Since these are the only representations allowed in C, it is obvious that a masking operation can only produce 15 for a 1's complement machine. With any luck, this will exterminate this thread. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. -- Posted via a free Usenet account from http://www.teranews.com Sep 19 '07 #10

 P: n/a On Tue, 18 Sep 2007 16:57:50 -0400, CBFalconer wrote: The only form -0 can take, in an int, ignoring padding bits and expressing the result as a hex 16 bit value (for other lengths insert more copies of the middle bits) are: 0x0000 2's complement 0xFFFF 1's complement 0x8000 sign/magnitude. The only forms negative zero can take are: 0xFFFF 1s' complement 0x8000 sign/magnitude. Negative zero doesn't exist in 2's complement. And the only forms -0 can take are: 0x0000 2's complement 0x0000 1s' complement 0x0000 sign/magnitude. since -0 is not negative zero regardless of representation. Sep 19 '07 #11

 P: n/a Op Wed, 19 Sep 2007 16:49:08 +0000 (UTC) schreef \$)CHarald van D)&k: Negative zero doesn't exist in 2's complement. And the only forms -0 can +0 ;-) take are: 0x0000 2's complement 0x0000 1s' complement 0x0000 sign/magnitude. since -0 is not negative zero regardless of representation. +0 -- Coos Sep 19 '07 #12

 P: n/a On Wed, 19 Sep 2007 19:03:07 +0200, Coos Haak wrote: Op Wed, 19 Sep 2007 16:49:08 +0000 (UTC) schreef \$)CHarald van D) &k: > >Negative zero doesn't exist in 2's complement. And the only forms -0can +0 ;-) >take are: 0x0000 2's complement 0x0000 1s' complement 0x0000 sign/magnitude.since -0 is not negative zero regardless of representation. +0 My point was that -0 is always the same thing as +0. -0 is not allowed to give you a negative zero. Sep 19 '07 #13

 P: n/a \$)CHarald van D)&k wrote: CBFalconer wrote: >The only form -0 can take, in an int, ignoring padding bits andexpressing the result as a hex 16 bit value (for other lengthsinsert more copies of the middle bits) are: 0x0000 2's complement 0xFFFF 1's complement 0x8000 sign/magnitude. The only forms negative zero can take are: 0xFFFF 1s' complement 0x8000 sign/magnitude. Negative zero doesn't exist in 2's complement. And the only forms -0 can take are: No, in 2's complement (-ve zero == +ve zero). Both are zero. However, in all systems, ((-0 + +0) == 0) :-) -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. -- Posted via a free Usenet account from http://www.teranews.com Sep 20 '07 #14

 P: n/a In article

 P: n/a Dik T. Winter wrote: In article =?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0Fk?= operators with arguments that | produce such a value; | — the +, -, *, /, and % operators where one argument is a | negative zero and the result is zero; | — compound assignment operators based on the above cases. | It is unspecified whether these cases actually generate a | negative zero or a normal zero, and whether a negative zero | becomes a normal zero when stored in an object. That forbids -0 to be negative zero. Ralf Sep 20 '07 #16

 P: n/a On Wed, 19 Sep 2007 22:09:41 -0400, CBFalconer wrote: \$)CHarald van D)&k wrote: >CBFalconer wrote: >>The only form -0 can take, in an int, ignoring padding bits andexpressing the result as a hex 16 bit value (for other lengths insertmore copies of the middle bits) are: 0x0000 2's complement 0xFFFF 1's complement 0x8000 sign/magnitude. The only forms negative zero can take are: 0xFFFF 1s' complement 0x8000 sign/magnitude.Negative zero doesn't exist in 2's complement. And the only forms -0can take are: No, in 2's complement (-ve zero == +ve zero). Both are zero. This is the definition of negative zero, from 6.2.6.2p2: "Which of these applies is implementation-defined, as is whether the value with sign bit 1 and all value bits zero (for the first two), or with sign bit and all value bits 1 (for ones' complement), is a trap representation or a normal value. In the case of sign and magnitude and ones' complement, if this representation is a normal value it is called a /negative zero/." Negative zero doesn't exist in 2's complement. It's not equal to positive zero. It simply doesn't exist. However, in all systems, ((-0 + +0) == 0) :-) Yes, because -0 is the same thing as +0 and plain 0, and because negative zero compares equal to normal zero. But negative zero plus normal zero is allowed to give you a negative zero. Sep 20 '07 #17

 P: n/a Op Thu, 20 Sep 2007 16:56:14 +0000 (UTC) schreef Ralf Damaschke: Dik T. Winter wrote: >In article =?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0Fk?=>My point was that -0 is always the same thing as +0. -0 isnot allowed to give you a negative zero. Where in the standard is that stated? Note that on 1'scomplement machines negative and positive zero compare asequal. | 6.2.6.2 (Representations of) Integer types, p3.| If the implementation supports negative zeros, they shall be| generated only by:| ¡X the &, |, ^, ~, <<, and >operators with arguments that| produce such a value;| ¡X the +, -, *, /, and % operators where one argument is a| negative zero and the result is zero;| ¡X compound assignment operators based on the above cases.| It is unspecified whether these cases actually generate a| negative zero or a normal zero, and whether a negative zero| becomes a normal zero when stored in an object. That forbids -0 to be negative zero. In 1-complement, a row of only zero-bits represents zero (+0). A row of only one-bits represents minus zero (-0). The last sentence of 6.2.6.2 leaves _unspecified_ whether minus zero becomes plus zero. It doesn't forbid it either. -- Coos Sep 20 '07 #18

 P: n/a On Thu, 20 Sep 2007 19:32:46 +0200, Coos Haak wrote: Op Thu, 20 Sep 2007 16:56:14 +0000 (UTC) schreef Ralf Damaschke: >Dik T. Winter wrote: >>In article =?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0Fk?=operators with arguments that | producesuch a value;| â€” the +, -, *, /, and % operators where one argument is a | negativezero and the result is zero; | â€” compound assignment operators based onthe above cases. | It is unspecified whether these cases actuallygenerate a | negative zero or a normal zero, and whether a negative zero| becomes a normal zero when stored in an object.That forbids -0 to be negative zero. In 1-complement, a row of only zero-bits represents zero (+0). A row of only one-bits represents minus zero (-0). The last sentence of 6.2.6.2 leaves _unspecified_ whether minus zero becomes plus zero. It doesn't forbid it either. Correct, but that doesn't matter here. It's the first sentence that matters: -0 (negated plain zero) has none of the bitwise operators, and doesn't have a negative zero as an operand to any other operator, so it's not allowed to be negative zero. Sep 20 '07 #19

 P: n/a CBFalconer writes: Since these are the only representations allowed in C, it is obvious that a masking operation can only produce 15 for a 1's complement machine. Well, yes. What I wondered was if it _can_ produce 15, or if I've missed something and it can produce 0: In C89, I can't find anything so I guess anything goes. In C99, 6.2.6.2p3 says what can _generate_ negative zero and that it's unspecified whether that becomes normal zero when stored in an object. I find nothing else which says an existing negative zero can be converted to normal zero. With any luck, this will exterminate this thread. Har har. -- Hallvard Sep 20 '07 #20

 P: n/a In data Wed, 19 Sep 2007 16:49:08 +0000 (UTC), \$)CHarald van D)&k On Tue, 18 Sep 2007 16:57:50 -0400, CBFalconer wrote: >The only form -0 can take, in an int, ignoring padding bits andexpressing the result as a hex 16 bit value (for other lengths insertmore copies of the middle bits) are: 0x0000 2's complement 0xFFFF 1's complement 0x8000 sign/magnitude. The only forms negative zero can take are: 0xFFFF 1s' complement 0x8000 sign/magnitude.Negative zero doesn't exist in 2's complement. And the only forms -0 cantake are: 0x0000 2's complement 0x0000 1s' complement 0x0000 sign/magnitude.since -0 is not negative zero regardless of representation. pheraps: unsigned i=0; --i; so it should be "--0" and not "-0" Sep 21 '07 #21

 P: n/a iRo >Negative zero doesn't exist in 2's complement. And the only forms -0 cantake are: 0x0000 2's complement 0x0000 1s' complement 0x0000 sign/magnitude.since -0 is not negative zero regardless of representation. pheraps: unsigned i=0; --i; I'm not sure what you're trying to say here. The above decrements i, setting it to UINT_MAX. so it should be "--0" and not "-0" --0 is illegal, since "--" is a single token. Did you mean to apply unary '-' twice? If so, you can write it as '- -0', or as '-(-0)' (or, equivalently, just as 0). -- Keith Thompson (The_Other_Keith) ks***@mib.org San Diego Supercomputer Center <* "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister" Sep 21 '07 #22

 P: n/a iRo wrote: > .... snip ... > pheraps: unsigned i=0; --i; so it should be "--0" and not "-0" You just generated UINT_MAX. -- Chuck F (cbfalconer at maineline dot net) Available for consulting/temporary embedded and systems. -- Posted via a free Usenet account from http://www.teranews.com Sep 21 '07 #23

 P: n/a CBFalconer -- Posted via a free Usenet account from http://www.teranews.com Fix your .sig. Richard Sep 24 '07 #24

### This discussion thread is closed

Replies have been disabled for this discussion.