@@ -1701,7 +1701,7 @@ private static BigInteger Add(ReadOnlySpan<uint> leftBits, int leftSign, ReadOnl
17011701 }
17021702
17031703 if ( bitsFromPool != null )
1704- ArrayPool < uint > . Shared . Return ( bitsFromPool ) ;
1704+ ArrayPool < uint > . Shared . Return ( bitsFromPool ) ;
17051705
17061706 return result ;
17071707 }
@@ -2636,7 +2636,7 @@ public static implicit operator BigInteger(nuint value)
26362636
26372637 if ( zdFromPool != null )
26382638 ArrayPool < uint > . Shared . Return ( zdFromPool ) ;
2639- exit :
2639+ exit :
26402640 if ( xdFromPool != null )
26412641 ArrayPool < uint > . Shared . Return ( xdFromPool ) ;
26422642
@@ -3227,7 +3227,6 @@ public static BigInteger PopCount(BigInteger value)
32273227
32283228 part = ~ value . _bits [ i ] ;
32293229 result += uint . PopCount ( part ) ;
3230-
32313230 i ++ ;
32323231 }
32333232 }
@@ -3239,267 +3238,89 @@ public static BigInteger PopCount(BigInteger value)
32393238 public static BigInteger RotateLeft ( BigInteger value , int rotateAmount )
32403239 {
32413240 value . AssertValid ( ) ;
3242- int byteCount = ( value . _bits is null ) ? sizeof ( int ) : ( value . _bits . Length * 4 ) ;
3243-
3244- // Normalize the rotate amount to drop full rotations
3245- rotateAmount = ( int ) ( rotateAmount % ( byteCount * 8L ) ) ;
32463241
32473242 if ( rotateAmount == 0 )
32483243 return value ;
32493244
3250- if ( rotateAmount == int . MinValue )
3251- return RotateRight ( RotateRight ( value , int . MaxValue ) , 1 ) ;
3252-
3253- if ( rotateAmount < 0 )
3254- return RotateRight ( value , - rotateAmount ) ;
3255-
3256- ( int digitShift , int smallShift ) = Math . DivRem ( rotateAmount , kcbitUint ) ;
3257-
3258- uint [ ] ? xdFromPool = null ;
3259- int xl = value . _bits ? . Length ?? 1 ;
3260-
3261- Span < uint > xd = ( xl <= BigIntegerCalculator . StackAllocThreshold )
3262- ? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3263- : xdFromPool = ArrayPool < uint > . Shared . Rent ( xl ) ;
3264- xd = xd . Slice ( 0 , xl ) ;
3265-
3266- bool negx = value . GetPartsForBitManipulation ( xd ) ;
3267-
3268- int zl = xl ;
3269- uint [ ] ? zdFromPool = null ;
3270-
3271- Span < uint > zd = ( zl <= BigIntegerCalculator . StackAllocThreshold )
3272- ? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3273- : zdFromPool = ArrayPool < uint > . Shared . Rent ( zl ) ;
3274- zd = zd . Slice ( 0 , zl ) ;
3275-
3276- zd . Clear ( ) ;
3277-
3278- if ( negx )
3279- {
3280- NumericsHelpers . DangerousMakeTwosComplement ( xd ) ;
3281- }
3282-
3283- if ( smallShift == 0 )
3284- {
3285- int dstIndex = 0 ;
3286- int srcIndex = xd . Length - digitShift ;
3287-
3288- do
3289- {
3290- // Copy last digitShift elements from xd to the start of zd
3291- zd [ dstIndex ] = xd [ srcIndex ] ;
3292-
3293- dstIndex ++ ;
3294- srcIndex ++ ;
3295- }
3296- while ( srcIndex < xd . Length ) ;
3297-
3298- srcIndex = 0 ;
3299-
3300- while ( dstIndex < zd . Length )
3301- {
3302- // Copy remaining elements from start of xd to end of zd
3303- zd [ dstIndex ] = xd [ srcIndex ] ;
3245+ bool neg = value . _sign < 0 ;
33043246
3305- dstIndex ++ ;
3306- srcIndex ++ ;
3307- }
3308- }
3309- else
3310- {
3311- int carryShift = kcbitUint - smallShift ;
3312-
3313- int dstIndex = 0 ;
3314- int srcIndex = 0 ;
3315-
3316- uint carry = 0 ;
3317-
3318- if ( digitShift == 0 )
3319- {
3320- carry = xd [ ^ 1 ] >> carryShift ;
3321- }
3322- else
3323- {
3324- srcIndex = xd . Length - digitShift ;
3325- carry = xd [ srcIndex - 1 ] >> carryShift ;
3326- }
3327-
3328- do
3329- {
3330- uint part = xd [ srcIndex ] ;
3331-
3332- zd [ dstIndex ] = ( part << smallShift ) | carry ;
3333- carry = part >> carryShift ;
3334-
3335- dstIndex ++ ;
3336- srcIndex ++ ;
3337- }
3338- while ( srcIndex < xd . Length ) ;
3339-
3340- srcIndex = 0 ;
3341-
3342- while ( dstIndex < zd . Length )
3343- {
3344- uint part = xd [ srcIndex ] ;
3345-
3346- zd [ dstIndex ] = ( part << smallShift ) | carry ;
3347- carry = part >> carryShift ;
3348-
3349- dstIndex ++ ;
3350- srcIndex ++ ;
3351- }
3352- }
3353-
3354- if ( negx && ( int ) zd [ ^ 1 ] < 0 )
3355- {
3356- NumericsHelpers . DangerousMakeTwosComplement ( zd ) ;
3357- }
3358- else
3247+ if ( value . _bits is null )
33593248 {
3360- negx = false ;
3249+ uint rs = BitOperations . RotateLeft ( ( uint ) value . _sign , rotateAmount ) ;
3250+ return neg
3251+ ? new BigInteger ( ( int ) rs )
3252+ : new BigInteger ( rs ) ;
33613253 }
33623254
3363- var result = new BigInteger ( zd , negx ) ;
3364-
3365- if ( xdFromPool != null )
3366- ArrayPool < uint > . Shared . Return ( xdFromPool ) ;
3367- if ( zdFromPool != null )
3368- ArrayPool < uint > . Shared . Return ( zdFromPool ) ;
3369-
3370- return result ;
3255+ return Rotate ( value . _bits , neg , rotateAmount ) ;
33713256 }
33723257
33733258 /// <inheritdoc cref="IBinaryInteger{TSelf}.RotateRight(TSelf, int)" />
33743259 public static BigInteger RotateRight ( BigInteger value , int rotateAmount )
33753260 {
33763261 value . AssertValid ( ) ;
3377- int byteCount = ( value . _bits is null ) ? sizeof ( int ) : ( value . _bits . Length * 4 ) ;
3378-
3379- // Normalize the rotate amount to drop full rotations
3380- rotateAmount = ( int ) ( rotateAmount % ( byteCount * 8L ) ) ;
33813262
33823263 if ( rotateAmount == 0 )
33833264 return value ;
33843265
3385- if ( rotateAmount == int . MinValue )
3386- return RotateLeft ( RotateLeft ( value , int . MaxValue ) , 1 ) ;
3387-
3388- if ( rotateAmount < 0 )
3389- return RotateLeft ( value , - rotateAmount ) ;
3390-
3391- ( int digitShift , int smallShift ) = Math . DivRem ( rotateAmount , kcbitUint ) ;
3266+ bool neg = value . _sign < 0 ;
33923267
3393- uint [ ] ? xdFromPool = null ;
3394- int xl = value . _bits ? . Length ?? 1 ;
3395-
3396- Span < uint > xd = ( xl <= BigIntegerCalculator . StackAllocThreshold )
3397- ? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3398- : xdFromPool = ArrayPool < uint > . Shared . Rent ( xl ) ;
3399- xd = xd . Slice ( 0 , xl ) ;
3400-
3401- bool negx = value . GetPartsForBitManipulation ( xd ) ;
3402-
3403- int zl = xl ;
3404- uint [ ] ? zdFromPool = null ;
3405-
3406- Span < uint > zd = ( zl <= BigIntegerCalculator . StackAllocThreshold )
3407- ? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3408- : zdFromPool = ArrayPool < uint > . Shared . Rent ( zl ) ;
3409- zd = zd . Slice ( 0 , zl ) ;
3410-
3411- zd . Clear ( ) ;
3412-
3413- if ( negx )
3268+ if ( value . _bits is null )
34143269 {
3415- NumericsHelpers . DangerousMakeTwosComplement ( xd ) ;
3270+ uint rs = BitOperations . RotateRight ( ( uint ) value . _sign , rotateAmount ) ;
3271+ return neg
3272+ ? new BigInteger ( ( int ) rs )
3273+ : new BigInteger ( rs ) ;
34163274 }
34173275
3418- if ( smallShift == 0 )
3419- {
3420- int dstIndex = 0 ;
3421- int srcIndex = digitShift ;
3422-
3423- do
3424- {
3425- // Copy first digitShift elements from xd to the end of zd
3426- zd [ dstIndex ] = xd [ srcIndex ] ;
3427-
3428- dstIndex ++ ;
3429- srcIndex ++ ;
3430- }
3431- while ( srcIndex < xd . Length ) ;
3432-
3433- srcIndex = 0 ;
3434-
3435- while ( dstIndex < zd . Length )
3436- {
3437- // Copy remaining elements from end of xd to start of zd
3438- zd [ dstIndex ] = xd [ srcIndex ] ;
3439-
3440- dstIndex ++ ;
3441- srcIndex ++ ;
3442- }
3443- }
3444- else
3445- {
3446- int carryShift = kcbitUint - smallShift ;
3447-
3448- int dstIndex = 0 ;
3449- int srcIndex = digitShift ;
3450-
3451- uint carry = 0 ;
3452-
3453- if ( digitShift == 0 )
3454- {
3455- carry = xd [ ^ 1 ] << carryShift ;
3456- }
3457- else
3458- {
3459- carry = xd [ srcIndex - 1 ] << carryShift ;
3460- }
3276+ return Rotate ( value . _bits , neg , - ( long ) rotateAmount ) ;
3277+ }
34613278
3462- do
3463- {
3464- uint part = xd [ srcIndex ] ;
3279+ private static BigInteger Rotate ( ReadOnlySpan < uint > bits , bool negative , long rotateLeftAmount )
3280+ {
3281+ Debug . Assert ( bits . Length > 0 ) ;
3282+ Debug . Assert ( Math . Abs ( rotateLeftAmount ) <= 0x80000000 ) ;
34653283
3466- zd [ dstIndex ] = ( part >> smallShift ) | carry ;
3467- carry = part << carryShift ;
3284+ int zLength = bits . Length ;
3285+ int leadingZeroCount = negative ? bits . IndexOfAnyExcept ( 0u ) : 0 ;
34683286
3469- dstIndex ++ ;
3470- srcIndex ++ ;
3471- }
3472- while ( srcIndex < xd . Length ) ;
3287+ if ( negative && bits [ ^ 1 ] >= kuMaskHighBit
3288+ && ! ( leadingZeroCount == bits . Length - 1 && bits [ ^ 1 ] == kuMaskHighBit ) )
3289+ ++ zLength ;
34733290
3474- srcIndex = 0 ;
3291+ uint [ ] ? zFromPool = null ;
3292+ Span < uint > zd = ( ( uint ) zLength <= BigIntegerCalculator . StackAllocThreshold
3293+ ? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3294+ : zFromPool = ArrayPool < uint > . Shared . Rent ( zLength ) ) . Slice ( 0 , zLength ) ;
34753295
3476- while ( dstIndex < zd . Length )
3477- {
3478- uint part = xd [ srcIndex ] ;
3296+ zd [ ^ 1 ] = 0 ;
3297+ bits . CopyTo ( zd ) ;
34793298
3480- zd [ dstIndex ] = ( part >> smallShift ) | carry ;
3481- carry = part << carryShift ;
3299+ if ( negative )
3300+ {
3301+ Debug . Assert ( ( uint ) leadingZeroCount < ( uint ) zd . Length ) ;
34823302
3483- dstIndex ++ ;
3484- srcIndex ++ ;
3485- }
3303+ // Same as NumericsHelpers.DangerousMakeTwosComplement(zd);
3304+ // Leading zero count is already calculated.
3305+ zd [ leadingZeroCount ] = ( uint ) ( - ( int ) zd [ leadingZeroCount ] ) ;
3306+ NumericsHelpers . DangerousMakeOnesComplement ( zd . Slice ( leadingZeroCount + 1 ) ) ;
34863307 }
34873308
3488- if ( negx && ( int ) zd [ ^ 1 ] < 0 )
3309+ BigIntegerCalculator . RotateLeft ( zd , rotateLeftAmount ) ;
3310+
3311+ if ( negative && ( int ) zd [ ^ 1 ] < 0 )
34893312 {
34903313 NumericsHelpers . DangerousMakeTwosComplement ( zd ) ;
34913314 }
34923315 else
34933316 {
3494- negx = false ;
3317+ negative = false ;
34953318 }
34963319
3497- var result = new BigInteger ( zd , negx ) ;
3320+ var result = new BigInteger ( zd , negative ) ;
34983321
3499- if ( xdFromPool != null )
3500- ArrayPool < uint > . Shared . Return ( xdFromPool ) ;
3501- if ( zdFromPool != null )
3502- ArrayPool < uint > . Shared . Return ( zdFromPool ) ;
3322+ if ( zFromPool != null )
3323+ ArrayPool < uint > . Shared . Return ( zFromPool ) ;
35033324
35043325 return result ;
35053326 }
0 commit comments