Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsigned shift right in C# Using Java semantics for negative numbers

I'm trying to port Java code to C# and I'm running into odd bugs related to the unsigned shift right operator >>> normally the code:

long l = (long) ((ulong) number) >> 2;

Would be the equivalent of Java's:

long l = number >>> 2;

However for the case of -2147483648L which you might recognized as Integer.MIN_VALUE this returns a different number than it would in Java since the cast to ulong changes the semantics of the number hence I get a different result.

How would something like this be possible in C#?

I'd like to preserve the code semantics as much as possible since its a pretty complex body of code.

like image 772
Shai Almog Avatar asked Jan 17 '14 14:01

Shai Almog


People also ask

What is unsigned shift right?

The unsigned right shift operator ( >>> ) (zero-fill right shift) evaluates the left-hand operand as an unsigned number, and shifts the binary representation of that number by the number of bits, modulo 32, specified by the right-hand operand.

What is shift right in C?

It is a bitwise operator that we use in the C language for operating on bits. The right shift operator is binary- which means that the working of this operator would require two of the operands. We represent the right shift operator using the >> sign.

Is >> in C logical or arithmetic?

When shifting an unsigned value, the >> operator in C is a logical shift. When shifting a signed value, the >> operator is an arithmetic shift.

What is left shift and right shift in C?

The bitwise shift operators move the bit values of a binary object. The left operand specifies the value to be shifted. The right operand specifies the number of positions that the bits in the value are to be shifted.


Video Answer


1 Answers

I believe your expression is incorrect when considering C#'s order precedence. Your code I believe is converting your long to ulong, then back to long, then shifting. I'm assuming your intent was to perform the shift on the ulong.

From the C# Specification §7.2.1, Unary (or in your case, the casting operation) takes precedence over the shifting. Thus your code:

long l = (long) ((ulong) number) >> 2;

would be interpreted as:

ulong ulongNumber = (ulong)number;
long longNumber = (long)ulongNumber;
long shiftedlongNumber = longNumber >> 2;

Given number as -2147483648L, this yields 536870912.

By wrapping the conversion and shifting in parenthesis:

long l = (long) (((ulong) number) >> 2);

Produces logic that could be rewritten as:

ulong ulongNumber = (ulong)number;
ulong shiftedulongNumber = ulongNumber >> 2;
long longShiftedNumber = (long)shiftedulongNumber;

Which given number as -2147483648L, this yields 4611686017890516992.


EDIT: Note that given those ordering rules, there's an extra set of parenthesis in my answer that aren't necessary. The correct expression could be written as:

long l = (long) ((ulong) number >> 2);
like image 67
Chris Sinclair Avatar answered Sep 28 '22 07:09

Chris Sinclair