tags:

views:

92

answers:

1

I wrote an Int128 type and it works great. I thought I could improve on its performance with a simple idea: Improve the shift operations which are a bit clumsy.

Because they are heavily used in multiplication and division, an improvement would have a ripple effect. So I began creating a dynamic method (to shift low and rotate high), only to discover that there are no OpCodes.Rol or OpCodes.Ror instructions.

Is this possible in IL?

+2  A: 

No.

You need to implement it with bit shifts

UInt64 highBits = 0;
UInt64 lowBits = 1;
Int32 n = 63;
var altShift = (n - 63);

var lowShiftedOff = (n - 63) > 0 ? 0 : (lowBits << n);
var highShiftedOff = (n - 63) > 0 ? 0 : (highBits << n);

var highResult = (UInt64)(highShiftedOff | (altShift > 0 ? (lowBits << altShift - 1) : 0));
var lowResult= (UInt64)(lowShiftedOff | (altShift > 0 ? (highBits << altShift - 1) : 0));
codekaizen
Thank you. You confirmed what I feared.I dug around in .NET 4.0's BigInteger to see how they did it and now I don't feel quite so bad about mine.
Tergiver
Not only is it bad, but I had neglected that SHL and SHR only look at the last 5 (for U/Int32) or 6 (for U/Int64) bits of the shift operand, effectively creating a modulus for the full shift value. This is a big pain when trying to shift bits through, and I can't understand why it was implemented like this.
codekaizen
The shift operands are only defined for shifts less than the size of the type involved, since shifting more than *n* bits for an *n*-bit type doesn't make much sense. The standard (ECMA 335: §3.59) says: `The return value is unspecified if 'shiftAmount' is greater than or equal to the width of 'value'.`
Porges
@Porges - It makes sense when you are trying to shift through like this.
codekaizen