Skip to content

Commit 7b5eb62

Browse files
committed
Additional changes
1 parent 5657cfc commit 7b5eb62

File tree

2 files changed

+75
-83
lines changed

2 files changed

+75
-83
lines changed

src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ public BigInteger(ReadOnlySpan<byte> value, bool isUnsigned = false, bool isBigE
464464
AssertValid();
465465
}
466466

467-
private BigInteger(int n, uint[]? rgu)
467+
internal BigInteger(int n, uint[]? rgu)
468468
{
469469
_sign = n;
470470
_bits = rgu;
@@ -683,8 +683,7 @@ public static BigInteger Parse(string value, IFormatProvider? provider)
683683

684684
public static BigInteger Parse(string value, NumberStyles style, IFormatProvider? provider)
685685
{
686-
(int sign, uint[]? bits) = BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider));
687-
return new BigInteger(sign, bits);
686+
return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider));
688687
}
689688

690689
public static bool TryParse([NotNullWhen(true)] string? value, out BigInteger result)
@@ -694,17 +693,12 @@ public static bool TryParse([NotNullWhen(true)] string? value, out BigInteger re
694693

695694
public static bool TryParse([NotNullWhen(true)] string? value, NumberStyles style, IFormatProvider? provider, out BigInteger result)
696695
{
697-
bool success = BigNumber.TryParseBigInteger(
698-
value, style, NumberFormatInfo.GetInstance(provider), out int sign, out uint[]? bits);
699-
700-
result = new BigInteger(sign, bits);
701-
return success;
696+
return BigNumber.TryParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider), out result);
702697
}
703698

704699
public static BigInteger Parse(ReadOnlySpan<char> value, NumberStyles style = NumberStyles.Integer, IFormatProvider? provider = null)
705700
{
706-
(int sign, uint[]? bits) = BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider));
707-
return new BigInteger(sign, bits);
701+
return BigNumber.ParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider));
708702
}
709703

710704
public static bool TryParse(ReadOnlySpan<char> value, out BigInteger result)
@@ -714,11 +708,7 @@ public static bool TryParse(ReadOnlySpan<char> value, out BigInteger result)
714708

715709
public static bool TryParse(ReadOnlySpan<char> value, NumberStyles style, IFormatProvider? provider, out BigInteger result)
716710
{
717-
bool success = BigNumber.TryParseBigInteger(
718-
value, style, NumberFormatInfo.GetInstance(provider), out int sign, out uint[]? bits);
719-
720-
result = new BigInteger(sign, bits);
721-
return success;
711+
return BigNumber.TryParseBigInteger(value, style, NumberFormatInfo.GetInstance(provider), out result);
722712
}
723713

724714
public static int Compare(BigInteger left, BigInteger right)

src/libraries/System.Runtime.Numerics/src/System/Numerics/BigNumber.cs

Lines changed: 70 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -325,49 +325,48 @@ internal static bool TryValidateParseStyleInteger(NumberStyles style, [NotNullWh
325325
return true;
326326
}
327327

328-
internal static bool TryParseBigInteger(string? value, NumberStyles style, NumberFormatInfo info, out int sign, out uint[]? bits)
328+
internal static bool TryParseBigInteger(string? value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
329329
{
330330
if (value == null)
331331
{
332-
sign = 0;
333-
bits = null;
332+
result = default;
334333
return false;
335334
}
336335

337-
return TryParseBigInteger(value.AsSpan(), style, info, out sign, out bits);
336+
return TryParseBigInteger(value.AsSpan(), style, info, out result);
338337
}
339338

340-
internal static bool TryParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info, out int sign, out uint[]? bits)
339+
internal static bool TryParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info, out BigInteger result)
341340
{
342-
sign = 0;
343-
bits = null;
344-
345341
ArgumentException? e;
346342
if (!TryValidateParseStyleInteger(style, out e))
347343
throw e; // TryParse still throws ArgumentException on invalid NumberStyles
348344

349345
BigNumberBuffer bignumber = BigNumberBuffer.Create();
350346
if (!FormatProvider.TryStringToBigInteger(value, style, info, bignumber.digits, out bignumber.precision, out bignumber.scale, out bignumber.sign))
347+
{
348+
result = default;
351349
return false;
350+
}
352351

353352
if ((style & NumberStyles.AllowHexSpecifier) != 0)
354353
{
355-
if (!HexNumberToBigInteger(ref bignumber, out sign, out bits))
354+
if (!HexNumberToBigInteger(ref bignumber, out result))
356355
{
357356
return false;
358357
}
359358
}
360359
else
361360
{
362-
if (!NumberToBigInteger(ref bignumber, out sign, out bits))
361+
if (!NumberToBigInteger(ref bignumber, out result))
363362
{
364363
return false;
365364
}
366365
}
367366
return true;
368367
}
369368

370-
internal static (int sign, uint[]? bits) ParseBigInteger(string value, NumberStyles style, NumberFormatInfo info)
369+
internal static BigInteger ParseBigInteger(string value, NumberStyles style, NumberFormatInfo info)
371370
{
372371
if (value == null)
373372
{
@@ -377,41 +376,41 @@ internal static (int sign, uint[]? bits) ParseBigInteger(string value, NumberSty
377376
return ParseBigInteger(value.AsSpan(), style, info);
378377
}
379378

380-
internal static (int sign, uint[]? bits) ParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info)
379+
internal static BigInteger ParseBigInteger(ReadOnlySpan<char> value, NumberStyles style, NumberFormatInfo info)
381380
{
382381
ArgumentException? e;
383382
if (!TryValidateParseStyleInteger(style, out e))
384383
throw e;
385384

386-
if (!TryParseBigInteger(value, style, info, out int sign, out uint[]? bits))
385+
if (!TryParseBigInteger(value, style, info, out BigInteger result))
387386
{
388387
throw new FormatException(SR.Overflow_ParseBigInteger);
389388
}
390-
return (sign, bits);
389+
return result;
391390
}
392391

393-
private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out int sign, out uint[]? bits)
392+
private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
394393
{
395-
sign = 0;
396-
bits = null;
397-
398394
if (number.digits == null || number.digits.Length == 0)
395+
{
396+
result = default;
399397
return false;
398+
}
400399

401400
const int DigitsPerBlock = 8;
402401

403402
int totalDigitCount = number.digits.Length - 1; // Ignore trailing '\0'
404403
int blockCount, partialDigitCount;
405404

406-
if (totalDigitCount % DigitsPerBlock == 0)
405+
if ((uint)totalDigitCount % DigitsPerBlock == 0)
407406
{
408407
blockCount = totalDigitCount / DigitsPerBlock;
409408
partialDigitCount = 0;
410409
}
411410
else
412411
{
413-
blockCount = (totalDigitCount / DigitsPerBlock) + 1;
414-
partialDigitCount = DigitsPerBlock - (totalDigitCount % DigitsPerBlock);
412+
blockCount = Math.DivRem(totalDigitCount, DigitsPerBlock, out int mod) + 1;
413+
partialDigitCount = DigitsPerBlock - mod;
415414
}
416415

417416
bool isNegative = HexConverter.FromChar(number.digits[0]) >= 8;
@@ -427,22 +426,45 @@ private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out int si
427426

428427
try
429428
{
430-
foreach (ReadOnlyMemory<char> digitsChunk in number.digits.GetChunks())
431-
ProcessChunk(digitsChunk.Span, bitsBuffer);
429+
foreach (ReadOnlyMemory<char> digitsChunkMem in number.digits.GetChunks())
430+
{
431+
ReadOnlySpan<char> chunkDigits = digitsChunkMem.Span;
432+
for (int i = 0; i < chunkDigits.Length; i++)
433+
{
434+
char digitChar = chunkDigits[i];
435+
if (digitChar == '\0')
436+
break;
437+
438+
int hexValue = HexConverter.FromChar(digitChar);
439+
Debug.Assert(hexValue != 0xFF);
440+
441+
partialValue = (partialValue << 4) | (uint)hexValue;
442+
partialDigitCount++;
443+
444+
if (partialDigitCount == DigitsPerBlock)
445+
{
446+
bitsBuffer[bitsBufferPos] = (int)partialValue;
447+
bitsBufferPos--;
448+
partialValue = 0;
449+
partialDigitCount = 0;
450+
}
451+
}
452+
}
432453

433454
Debug.Assert(partialDigitCount == 0 && bitsBufferPos == -1);
434455

435456
// BigInteger requires leading zero blocks to be truncated.
436-
int blockCountNoLeadingZeros = blockCount;
437-
while (blockCountNoLeadingZeros > 0 && bitsBuffer[blockCountNoLeadingZeros - 1] == 0)
438-
blockCountNoLeadingZeros--;
457+
bitsBuffer = bitsBuffer.TrimEnd(0);
439458

440-
if (blockCountNoLeadingZeros == 0)
459+
int sign;
460+
uint[]? bits;
461+
462+
if (bitsBuffer.IsEmpty)
441463
{
442464
sign = 0;
443465
bits = null;
444466
}
445-
else if (blockCountNoLeadingZeros == 1)
467+
else if (bitsBuffer.Length == 1)
446468
{
447469
sign = bitsBuffer[0];
448470
bits = null;
@@ -456,50 +478,24 @@ private static bool HexNumberToBigInteger(ref BigNumberBuffer number, out int si
456478
else
457479
{
458480
sign = isNegative ? -1 : 1;
459-
bits = MemoryMarshal.Cast<int, uint>(bitsBuffer).Slice(0, blockCountNoLeadingZeros).ToArray();
481+
bits = MemoryMarshal.Cast<int, uint>(bitsBuffer).ToArray();
460482

461483
if (isNegative)
462484
NumericsHelpers.DangerousMakeTwosComplement(bits);
463485
}
464486

487+
result = new BigInteger(sign, bits);
465488
return true;
466489
}
467490
finally
468491
{
469492
if (arrayFromPool != null)
470493
ArrayPool<int>.Shared.Return(arrayFromPool);
471494
}
472-
473-
void ProcessChunk(ReadOnlySpan<char> chunkDigits, Span<int> _bitsBuffer)
474-
{
475-
for (int i = 0; i < chunkDigits.Length; i++)
476-
{
477-
char digitChar = chunkDigits[i];
478-
if (digitChar == '\0')
479-
return;
480-
481-
int hexValue = HexConverter.FromChar(digitChar);
482-
Debug.Assert(hexValue != 0xFF);
483-
484-
partialValue = (partialValue << 4) | (uint)hexValue;
485-
partialDigitCount++;
486-
487-
if (partialDigitCount == DigitsPerBlock)
488-
{
489-
_bitsBuffer[bitsBufferPos] = (int)partialValue;
490-
bitsBufferPos--;
491-
partialValue = 0;
492-
partialDigitCount = 0;
493-
}
494-
}
495-
}
496495
}
497496

498-
private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign, out uint[]? bits)
497+
private static bool NumberToBigInteger(ref BigNumberBuffer number, out BigInteger result)
499498
{
500-
sign = 0;
501-
bits = null;
502-
503499
Span<int> stackBuffer = stackalloc int[BigInteger.StackallocUInt32Limit];
504500
Span<int> currentBuffer = stackBuffer;
505501
int currentBufferSize = 0;
@@ -517,9 +513,11 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
517513
{
518514
foreach (ReadOnlyMemory<char> digitsChunk in number.digits.GetChunks())
519515
{
520-
bool isValid = ProcessChunk(digitsChunk.Span, ref currentBuffer);
521-
if (!isValid)
516+
if (!ProcessChunk(digitsChunk.Span, ref currentBuffer))
517+
{
518+
result = default;
522519
return false;
520+
}
523521
}
524522

525523
if (partialDigitCount > 0)
@@ -536,12 +534,15 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
536534
if (trailingZeroCount > 0)
537535
MultiplyAdd(ref currentBuffer, s_uint32PowersOfTen[trailingZeroCount], 0);
538536

537+
int sign;
538+
uint[]? bits;
539+
539540
if (currentBufferSize == 0)
540541
{
541542
sign = 0;
542543
bits = null;
543544
}
544-
else if (currentBufferSize == 1 && currentBuffer[0] <= int.MaxValue)
545+
else if (currentBufferSize == 1 && (uint)currentBuffer[0] <= int.MaxValue)
545546
{
546547
sign = number.sign ? -currentBuffer[0] : currentBuffer[0];
547548
bits = null;
@@ -552,6 +553,7 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
552553
bits = MemoryMarshal.Cast<int, uint>(currentBuffer).Slice(0, currentBufferSize).ToArray();
553554
}
554555

556+
result = new BigInteger(sign, bits);
555557
return true;
556558
}
557559
finally
@@ -560,7 +562,7 @@ private static bool NumberToBigInteger(ref BigNumberBuffer number, out int sign,
560562
ArrayPool<int>.Shared.Return(arrayFromPool);
561563
}
562564

563-
bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> _currentBuffer)
565+
bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> currentBuffer)
564566
{
565567
int remainingIntDigitCount = Math.Max(numberScale - totalDigitCount, 0);
566568
ReadOnlySpan<char> intDigitsSpan = chunkDigits.Slice(0, Math.Min(remainingIntDigitCount, chunkDigits.Length));
@@ -578,7 +580,7 @@ bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> _currentBuffer)
578580
// Update the buffer when enough partial digits have been accumulated.
579581
if (partialDigitCount == MaxPartialDigits)
580582
{
581-
MultiplyAdd(ref _currentBuffer, TenPowMaxPartial, partialValue);
583+
MultiplyAdd(ref currentBuffer, TenPowMaxPartial, partialValue);
582584
partialValue = 0;
583585
partialDigitCount = 0;
584586
}
@@ -598,9 +600,9 @@ bool ProcessChunk(ReadOnlySpan<char> chunkDigits, ref Span<int> _currentBuffer)
598600
return true;
599601
}
600602

601-
void MultiplyAdd(ref Span<int> _currentBuffer, uint multiplier, uint addValue)
603+
void MultiplyAdd(ref Span<int> currentBuffer, uint multiplier, uint addValue)
602604
{
603-
Span<int> curBits = _currentBuffer.Slice(0, currentBufferSize);
605+
Span<int> curBits = currentBuffer.Slice(0, currentBufferSize);
604606
uint carry = addValue;
605607

606608
for (int i = 0; i < curBits.Length; i++)
@@ -613,19 +615,19 @@ void MultiplyAdd(ref Span<int> _currentBuffer, uint multiplier, uint addValue)
613615
if (carry == 0)
614616
return;
615617

616-
if (currentBufferSize == _currentBuffer.Length)
618+
if (currentBufferSize == currentBuffer.Length)
617619
{
618620
int[]? arrayToReturn = arrayFromPool;
619621

620622
arrayFromPool = ArrayPool<int>.Shared.Rent(checked(currentBufferSize * 2));
621-
_currentBuffer.CopyTo(arrayFromPool);
622-
_currentBuffer = arrayFromPool;
623+
currentBuffer.CopyTo(arrayFromPool);
624+
currentBuffer = arrayFromPool;
623625

624626
if (arrayToReturn != null)
625627
ArrayPool<int>.Shared.Return(arrayToReturn);
626628
}
627629

628-
_currentBuffer[currentBufferSize] = (int)carry;
630+
currentBuffer[currentBufferSize] = (int)carry;
629631
currentBufferSize++;
630632
}
631633
}

0 commit comments

Comments
 (0)