@@ -1701,7 +1701,7 @@ private static BigInteger Add(ReadOnlySpan<uint> leftBits, int leftSign, ReadOnl
1701
1701
}
1702
1702
1703
1703
if ( bitsFromPool != null )
1704
- ArrayPool < uint > . Shared . Return ( bitsFromPool ) ;
1704
+ ArrayPool < uint > . Shared . Return ( bitsFromPool ) ;
1705
1705
1706
1706
return result ;
1707
1707
}
@@ -2636,7 +2636,7 @@ public static implicit operator BigInteger(nuint value)
2636
2636
2637
2637
if ( zdFromPool != null )
2638
2638
ArrayPool < uint > . Shared . Return ( zdFromPool ) ;
2639
- exit :
2639
+ exit :
2640
2640
if ( xdFromPool != null )
2641
2641
ArrayPool < uint > . Shared . Return ( xdFromPool ) ;
2642
2642
@@ -3239,7 +3239,27 @@ public static BigInteger PopCount(BigInteger value)
3239
3239
public static BigInteger RotateLeft ( BigInteger value , int rotateAmount )
3240
3240
{
3241
3241
value . AssertValid ( ) ;
3242
- int byteCount = ( value . _bits is null ) ? sizeof ( int ) : ( value . _bits . Length * 4 ) ;
3242
+
3243
+ bool negx = value . _sign < 0 ;
3244
+ uint smallBits = NumericsHelpers . Abs ( value . _sign ) ;
3245
+ scoped ReadOnlySpan < uint > bits = value . _bits ;
3246
+ if ( bits . IsEmpty )
3247
+ {
3248
+ bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3249
+ }
3250
+
3251
+ int xl = bits . Length ;
3252
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3253
+ {
3254
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3255
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3256
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3257
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3258
+ // If the 2's component's last element is a 0, we will track the sign externally
3259
+ ++ xl ;
3260
+ }
3261
+
3262
+ int byteCount = xl * 4 ;
3243
3263
3244
3264
// Normalize the rotate amount to drop full rotations
3245
3265
rotateAmount = ( int ) ( rotateAmount % ( byteCount * 8L ) ) ;
@@ -3256,14 +3276,13 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
3256
3276
( int digitShift , int smallShift ) = Math . DivRem ( rotateAmount , kcbitUint ) ;
3257
3277
3258
3278
uint [ ] ? xdFromPool = null ;
3259
- int xl = value . _bits ? . Length ?? 1 ;
3260
-
3261
3279
Span < uint > xd = ( xl <= BigIntegerCalculator . StackAllocThreshold )
3262
3280
? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3263
3281
: xdFromPool = ArrayPool < uint > . Shared . Rent ( xl ) ;
3264
3282
xd = xd . Slice ( 0 , xl ) ;
3283
+ xd [ ^ 1 ] = 0 ;
3265
3284
3266
- bool negx = value . GetPartsForBitManipulation ( xd ) ;
3285
+ bits . CopyTo ( xd ) ;
3267
3286
3268
3287
int zl = xl ;
3269
3288
uint [ ] ? zdFromPool = null ;
@@ -3374,7 +3393,28 @@ public static BigInteger RotateLeft(BigInteger value, int rotateAmount)
3374
3393
public static BigInteger RotateRight ( BigInteger value , int rotateAmount )
3375
3394
{
3376
3395
value . AssertValid ( ) ;
3377
- int byteCount = ( value . _bits is null ) ? sizeof ( int ) : ( value . _bits . Length * 4 ) ;
3396
+
3397
+
3398
+ bool negx = value . _sign < 0 ;
3399
+ uint smallBits = NumericsHelpers . Abs ( value . _sign ) ;
3400
+ scoped ReadOnlySpan < uint > bits = value . _bits ;
3401
+ if ( bits . IsEmpty )
3402
+ {
3403
+ bits = new ReadOnlySpan < uint > ( in smallBits ) ;
3404
+ }
3405
+
3406
+ int xl = bits . Length ;
3407
+ if ( negx && ( bits [ ^ 1 ] >= kuMaskHighBit ) && ( ( bits [ ^ 1 ] != kuMaskHighBit ) || bits . IndexOfAnyExcept ( 0u ) != ( bits . Length - 1 ) ) )
3408
+ {
3409
+ // We check for a special case where its sign bit could be outside the uint array after 2's complement conversion.
3410
+ // For example given [0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF], its 2's complement is [0x01, 0x00, 0x00]
3411
+ // After a 32 bit right shift, it becomes [0x00, 0x00] which is [0x00, 0x00] when converted back.
3412
+ // The expected result is [0x00, 0x00, 0xFFFFFFFF] (2's complement) or [0x00, 0x00, 0x01] when converted back
3413
+ // If the 2's component's last element is a 0, we will track the sign externally
3414
+ ++ xl ;
3415
+ }
3416
+
3417
+ int byteCount = xl * 4 ;
3378
3418
3379
3419
// Normalize the rotate amount to drop full rotations
3380
3420
rotateAmount = ( int ) ( rotateAmount % ( byteCount * 8L ) ) ;
@@ -3391,14 +3431,13 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3391
3431
( int digitShift , int smallShift ) = Math . DivRem ( rotateAmount , kcbitUint ) ;
3392
3432
3393
3433
uint [ ] ? xdFromPool = null ;
3394
- int xl = value . _bits ? . Length ?? 1 ;
3395
-
3396
3434
Span < uint > xd = ( xl <= BigIntegerCalculator . StackAllocThreshold )
3397
3435
? stackalloc uint [ BigIntegerCalculator . StackAllocThreshold ]
3398
3436
: xdFromPool = ArrayPool < uint > . Shared . Rent ( xl ) ;
3399
3437
xd = xd . Slice ( 0 , xl ) ;
3438
+ xd [ ^ 1 ] = 0 ;
3400
3439
3401
- bool negx = value . GetPartsForBitManipulation ( xd ) ;
3440
+ bits . CopyTo ( xd ) ;
3402
3441
3403
3442
int zl = xl ;
3404
3443
uint [ ] ? zdFromPool = null ;
@@ -3445,19 +3484,12 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3445
3484
{
3446
3485
int carryShift = kcbitUint - smallShift ;
3447
3486
3448
- int dstIndex = 0 ;
3449
- int srcIndex = digitShift ;
3487
+ int dstIndex = xd . Length - 1 ;
3488
+ int srcIndex = digitShift == 0
3489
+ ? xd . Length - 1
3490
+ : digitShift - 1 ;
3450
3491
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
- }
3492
+ uint carry = xd [ digitShift ] << carryShift ;
3461
3493
3462
3494
do
3463
3495
{
@@ -3466,22 +3498,22 @@ public static BigInteger RotateRight(BigInteger value, int rotateAmount)
3466
3498
zd [ dstIndex ] = ( part >> smallShift ) | carry ;
3467
3499
carry = part << carryShift ;
3468
3500
3469
- dstIndex ++ ;
3470
- srcIndex ++ ;
3501
+ dstIndex -- ;
3502
+ srcIndex -- ;
3471
3503
}
3472
- while ( srcIndex < xd . Length ) ;
3504
+ while ( ( uint ) srcIndex < ( uint ) xd . Length ) ; // is equivalent to (srcIndex >= 0 && srcIndex < xd.Length)
3473
3505
3474
- srcIndex = 0 ;
3506
+ srcIndex = xd . Length - 1 ;
3475
3507
3476
- while ( dstIndex < zd . Length )
3508
+ while ( ( uint ) dstIndex < ( uint ) zd . Length ) // is equivalent to (dstIndex >= 0 && dstIndex < zd.Length)
3477
3509
{
3478
3510
uint part = xd [ srcIndex ] ;
3479
3511
3480
3512
zd [ dstIndex ] = ( part >> smallShift ) | carry ;
3481
3513
carry = part << carryShift ;
3482
3514
3483
- dstIndex ++ ;
3484
- srcIndex ++ ;
3515
+ dstIndex -- ;
3516
+ srcIndex -- ;
3485
3517
}
3486
3518
}
3487
3519
0 commit comments