bitwise operator !!

F

Flash Gordon

CBFalconer wrote, On 09/12/08 01:22:
I'm not disagreeing with you. I AM disagreeing with the
advisability of implementing blarggs suggestion.

Blarg is suggesting an implementation could have INT_MIN = -INT_MAX with
2s complement. I am suggesting that not only is this allowed but that
there are actually very good reasons why this might be done. So I don't
see how you can be suggesting that implementing Blargg's suggestion is
inadvisable without disagreeing with my claim that there are good
reasons to implement what Blarrg is suggesting.

To be clear, I think there are *very* good reasons to implement what
Blarrg is suggesting could be implemented, so I believe that any banket
suggestion that doing so is inadvisable is just plain wrong.
 
C

CBFalconer

Flash said:
CBFalconer wrote:
.... snip ...

.... snip ...

To be clear, I think there are *very* good reasons to implement
what Blarrg is suggesting could be implemented, so I believe
that any banket suggestion that doing so is inadvisable is just
plain wrong.

My earlier message detailed my reasons for disagreement.
 
F

Flash Gordon

CBFalconer wrote, On 16/12/08 02:41:
My earlier message detailed my reasons for disagreement.

My earlier post said why you were likely to be wrong. I.e. an
implementation where INT_MIN==-INT_MAX is likely to have the remaining
bit-pattern as a trap in all languages, not just in C, so your complaint
that it would not be compatible with other languages was bogus. Having
INT_MIN==-INT_MAX is very useful for signal processing. The C standards
committee thought it sufficiently useful to explicitly allow it.
 
D

David Thompson

That's because E1 << E2 may produce a trap representation,
whereas E1 >> E2 can't. It may produce a negative zero,
but only if you start with a negative zero, assuming
normal shifting behaviour.
Is that a typo? For the IME-normal shifting behavior on 1sC and S&M,
sufficient rightshift of any negative can go to neg zero.
Of course, implementation-defined means that any value
could be produced, but not a trap representation. So,
if the right shift produces a negative zero on a given
implementation, it cannot be a trap representation on
that implementation.

Right, assuming it (the impl-def) is documented.
 
T

Tim Rentsch

CBFalconer said:
Fatal. If x == INT_MIN on entry to that, you can have undefined
behavior in the x = -x statement. However the simple, and
understandable, x = x / 32 will work.

Using / avoids the problem of undefined behavior, but it has a
different problem, namely, it isn't guaranteed to produce the
same answer as the shifting method (which rounds toward zero),
because of differences in how / is specified between C90 and C99.

Exercise for the reader: write code to accomplish this operation,
with rounding towards zero, and no undefined behavior:
(a) using >>
(b) using / and %
 
T

Tim Rentsch

jameskuyper said:
CBFalconer said:
Your quote (repeated above) specifies implementation-defined. This
also means that you don't know what your code will do on another
compiler or system.

You're confusing "implementation-defined value" with "undefined
behavior", which is precisely the distinction he's making. If the
behavior were undefined, as was incorrectly claimed, it would indeed
be the case that "you don't know what your code will do on another
machine", and the implemenation for that other machine has no
obligation to document what that behavior will be.

Since the behavior is in fact implementation-defined, you know that
such code will produce a valid value of the specified type, no matter
which conforming implementation you use. [...]

Except that 6.2.6.2 p 4 means there can be undefined behavior:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with arguments
that would produce such a value is undefined.
 
T

Tim Rentsch

CBFalconer said:
No, I'm not. You have no a-priori knowledge of what that 'other
system' consists, thus you don't know what your code will do.
Implementation-defined is only better than undefined when you are
writing code for exactly one known system, which is adequately
documented. If so, your queries don't belong on c.l.c.

I feel I must disagree with the last two sentences. I don't
know what a majority opinion on this would be, but I think
there are plenty of implementation-defined related questions
that are of interest to many readers of CLC, and for which
CLC presents the best venue for their discussion, at least
of the venues reasonably widely available.
 
T

Tim Rentsch

Keith Thompson said:
CBFalconer said:
Nate Eldredge wrote: [...]
Well, there is a difference; the possible behavior is more limited.
In particular, you know that E1 >> E2 has a value.

For example, this program:

#include <stdio.h>
int main(void) {
printf("Your system thinks -10 >> 2 == %d. Isn't that nice?\n",
-10 >> 2);
return 0;
}

may print
... snip ...

Your system thinks -10 >> 2 == 196. Isn't that nice?
But it may not print

Your system thinks -10 >> 2 == a fish. Isn't that nice?

Why shouldn't it? The system creator only has to document that any
right shift of a negative value results in the string "a fish".
That meets all requirements of the standard. It may not meet with
the approval of the users, but that is immaterial. :)

No, it doesn't meet all requirements of the standard. In particular,
it fails to meet the requirement stated in C99 6.5.7p3:

The integer promotions are performed on each of the operands. The
type of the result is that of the promoted left operand.

or p5:

If E1 has a signed type and a negative value, the resulting value
is implementation-defined.

The result of -10 >> 2 is implementation-defined, but it must be of
type int. Passing a value of type int to printf with a "%d" format
cannot result in the output "a fish" unless undefined behavior has
been invoked. (The result cannot be a trap representation, since a
trap representation is not a value.)

Except, the possibility of undefined behavior (under 6.2.6.2 p 4)
may end up producing a trap representation.
 
T

Tim Rentsch

Peter Nilsson said:
That's because E1 << E2 may produce a trap representation,
whereas E1 >> E2 can't. It may produce a negative zero,
but only if you start with a negative zero, assuming
normal shifting behaviour.

Of course, implementation-defined means that any value
could be produced, but not a trap representation. So,
if the right shift produces a negative zero on a given
implementation, it cannot be a trap representation on
that implementation.

I suspect you didn't take into account 6.2.6.2 p 4.
 
T

Tim Rentsch

David Thompson said:
Is that a typo? For the IME-normal shifting behavior on 1sC and S&M,
sufficient rightshift of any negative can go to neg zero.

David has it right here -- 6.2.6.2 p 3 specifically allows
negative zeros for >>, "with arguments that produce such a value",
without regard to one of the arguments necessarily being
negative zero.
 
J

jameskuyper

Tim said:
jameskuyper said:
CBFalconer said:
blargg wrote:

... snip ...

BTW, in another message in this thread someone said that shifting
a signed value right is undefined. My copy of the C99 standard
says otherwise:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If
E1 has an unsigned type or if E1 has a signed type and a
nonnegative value, the value of the result is the integral part
of the quotient of E1 / 2^E2. If E1 has a signed type and a
negative value, the resulting value is implementation-defined.

Your quote (repeated above) specifies implementation-defined. This
also means that you don't know what your code will do on another
compiler or system.

You're confusing "implementation-defined value" with "undefined
behavior", which is precisely the distinction he's making. If the
behavior were undefined, as was incorrectly claimed, it would indeed
be the case that "you don't know what your code will do on another
machine", and the implemenation for that other machine has no
obligation to document what that behavior will be.

Since the behavior is in fact implementation-defined, you know that
such code will produce a valid value of the specified type, no matter
which conforming implementation you use. [...]

Except that 6.2.6.2 p 4 means there can be undefined behavior:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with arguments
that would produce such a value is undefined.

3.17.1: "implementation-defined value
unspecified value where each implementation documents how the choice
is made"
3.17.1: "unspecified value
valid value of the relevant type where this International Standard
imposes no
requirements on which value is chosen in any instance."

Therefore, an implementation-defined value is required to be a valid
value. On a system where negative zeros are not valid, they can never
be that implementation's choice in any situation where the standard
says that a value is implementation-defined. This means that 6.2.6.2p4
can only apply when the result is NOT implementation-defined.

This interpretation has a problem: with this interpretation, I can't
find any way to apply 6.2.6.2p4 to any operation involving either
shift operator that would otherwise have defined behavior, so
inclusion of the shift operators in 6.2.6.2p4 seems to be redundant;
it does not, however, contradict anything said elsewhere. For the
other four operators, it's trivial to come up with cases where the
resulting value would otherwise be standard-defined as the one
represented by the bit pattern for negative zero, if it weren't for
the fact that this clause renders the behavior undefined.
 
K

Keith Thompson

Tim Rentsch said:
I suspect you didn't take into account 6.2.6.2 p 4.

For the benefit of anyone who doesn't have a copy of the standard
handy, it says:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with arguments
that would produce such a value is undefined.
 
H

Harald van Dijk

Using / avoids the problem of undefined behavior, but it has a different
problem, namely, it isn't guaranteed to produce the same answer as the
shifting method (which rounds toward zero),

The shifting method doesn't round towards zero, but division may.
because of differences in
how / is specified between C90 and C99.

Exercise for the reader: write code to accomplish this operation, with
rounding towards zero, and no undefined behavior:
(a) using >>
(b) using / and %

How about

(a)

if (x < 0) {
x = ~(~x >> 5);
}

(b)

if (x < 0) {
x = ~(~x / (32 % 33));
}

Did I miss something here?
 
C

CBFalconer

pete said:
David Thompson wrote:
.... snip ...


An arithmetic right shift of (-1) in signed magnitude,
produces a negative zero.

No. It produces undefined behaviour (or possibly implementation
defined).
 
C

CBFalconer

Tim said:
.... snip ...


I feel I must disagree with the last two sentences. I don't know
what a majority opinion on this would be, but I think there are
plenty of implementation-defined related questions that are of
interest to many readers of CLC, and for which CLC presents the
best venue for their discussion, at least of the venues reasonably
widely available.

Now that is a reasonable objection. I don't agree with it,
however. :)
 
C

CBFalconer

Keith said:
.... snip ...


For the benefit of anyone who doesn't have a copy of the standard
handy, it says:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with
arguments that would produce such a value is undefined.

This may be one of the differences from n869, which says:

[#4] The precision of an integer type is the number of bits
it uses to represent values, excluding any sign and padding
bits. The width of an integer type is the same but
including any sign bit; thus for unsigned integer types the
two values are the same, while for signed integer types the
width is one greater than the precision.
 
R

Richard Tobin

pete wrote:
No. It produces undefined behaviour (or possibly implementation
defined).

C doesn't have anything called an arithmetic right shift, or a signed
magnitude data type, so obviously Pete was not talking about what
behaviour C specifies. Please try to understand what people are
saying before sending a knee-jerk "it's undefined" message.

-- Richard
 
K

Keith Thompson

CBFalconer said:
Keith said:
... snip ...


For the benefit of anyone who doesn't have a copy of the standard
handy, it says:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with
arguments that would produce such a value is undefined.

This may be one of the differences from n869, which says:

[#4] The precision of an integer type is the number of bits
it uses to represent values, excluding any sign and padding
bits. The width of an integer type is the same but
including any sign bit; thus for unsigned integer types the
two values are the same, while for signed integer types the
width is one greater than the precision.

Yes, that's paragraph 6 in C99 and in n1256. (Also, the first
occurrences of the words "precision" and "width" are in italics in all
three versions.)

The text of C99 6.2.6.2p4 doesn't appear in n869.

Even if you prefer plain text to PDF, it wouldn't be a bad idea to
have a copy of C99 and/or n1256.pdf so you can check such things
yourself.
 
C

CBFalconer

Keith said:
CBFalconer said:
Keith said:
... snip ...

I suspect you didn't take into account 6.2.6.2 p 4.

For the benefit of anyone who doesn't have a copy of the standard
handy, it says:

If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with
arguments that would produce such a value is undefined.

This may be one of the differences from n869, which says:

[#4] The precision of an integer type is the number of bits
it uses to represent values, excluding any sign and padding
bits. The width of an integer type is the same but
including any sign bit; thus for unsigned integer types the
two values are the same, while for signed integer types the
width is one greater than the precision.

Yes, that's paragraph 6 in C99 and in n1256. (Also, the first
occurrences of the words "precision" and "width" are in italics
in all three versions.)

The text of C99 6.2.6.2p4 doesn't appear in n869.

Even if you prefer plain text to PDF, it wouldn't be a bad idea
to have a copy of C99 and/or n1256.pdf so you can check such
things yourself.

Actually I do have those, and the (hidden) purpose of my message
was to alert others to this particular difference. I think the
original reference was made to n869.
 
J

jameskuyper

It is implementation-defined; NOT undefined.
Correct.
The negative zero result is either undefined
or implementation defined.

You said, positively, that it does produce a negative zero. However,
because the result is implementation-defined, implementations have no
obligation to have such an expression produce negative zero. In fact,
the standard requires that implementation-defined results be valid
values of the appropriate type, and it explicitly allows
implementations to choose negative zero to be a trap representation.
If the implementation does designate negative zero as a trap
representation, it's therefore prohibited by the standard from making
negative zero the implementation-defined result of such an expression.

You can only make your statement true by limiting it to particular
implementations; it is not true in the general case.
 

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