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

  • Thread starter Hallvard B Furuseth
  • Start date
H

Hallvard B Furuseth

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.)
 
H

Hallvard B Furuseth

I said:
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.
 
A

Ark Khasin

Hallvard said:
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.
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
 
H

Hallvard B Furuseth

Ark said:
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.
 
A

Ark Khasin

Hallvard said:
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
 
P

pete

Ark said:
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)
 
H

Hallvard B Furuseth

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.
(...)
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".
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.
 
C

Charlie Gordon

Hallvard B Furuseth said:
Duh, a%16 as pete says.


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.
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.
 
H

Hallvard B Furuseth

Charlie said:
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.
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.)
 
C

CBFalconer

Hallvard said:
.... snip ...


Why not? Does the standard say? That's what I'm asking about.


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.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

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.
 
C

Coos Haak

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
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

Op Wed, 19 Sep 2007 16:49:08 +0000 (UTC) schreef $)CHarald van D) &k:


+0

My point was that -0 is always the same thing as +0. -0 is not allowed to
give you a negative zero.
 
C

CBFalconer

$)CHarald van D)&k said:
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) :)
 
D

Dik T. Winter

> My point was that -0 is always the same thing as +0. -0 is not allowed to
> give you a negative zero.

Where in the standard is that stated? Note that on 1's complement
machines negative and positive zero compare as equal.
 
R

Ralf Damaschke

Dik said:
=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0Fk?=


Where in the standard is that stated? Note that on 1's
complement machines negative and positive zero compare as
equal.

| 6.2.6.2 (Representations of) Integer types, p3.
| If the implementation supports negative zeros, they shall be
| generated only by:
| — the &, |, ^, ~, <<, and >> 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
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

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.
 
C

Coos Haak

Op Thu, 20 Sep 2007 16:56:14 +0000 (UTC) schreef Ralf Damaschke:
| 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.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

Op Thu, 20 Sep 2007 16:56:14 +0000 (UTC) schreef Ralf Damaschke:


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.
 
H

Hallvard B Furuseth

CBFalconer said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top