<PackageReference Include="System.Memory" Version="4.5.0-rc1" />

Number

static class Number
using System.Buffers.Text; using System.Runtime.CompilerServices; namespace System { internal static class Number { private static class DoubleHelper { public unsafe static uint Exponent(double d) { return (*(uint*)((byte*)(&d) + 4) >> 20) & 2047; } public unsafe static ulong Mantissa(double d) { return *(uint*)(&d) | ((ulong)(*(uint*)((byte*)(&d) + 4) & 1048575) << 32); } public unsafe static bool Sign(double d) { return *(uint*)((byte*)(&d) + 4) >> 31 != 0; } } internal const int DECIMAL_PRECISION = 29; private static readonly ulong[] s_rgval64Power10 = new ulong[30] { 11529215046068469760, 14411518807585587200, 18014398509481984000, 11258999068426240000, 14073748835532800000, 17592186044416000000, 10995116277760000000, 13743895347200000000, 17179869184000000000, 10737418240000000000, 13421772800000000000, 16777216000000000000, 10485760000000000000, 13107200000000000000, 16384000000000000000, 14757395258967641293, 11805916207174113035, 9444732965739290428, 15111572745182864686, 12089258196146291749, 9671406556917033399, 15474250491067253438, 12379400392853802751, 9903520314283042201, 15845632502852867522, 12676506002282294018, 10141204801825835215, 16225927682921336344, 12980742146337069075, 10384593717069655260 }; private static readonly sbyte[] s_rgexp64Power10 = new sbyte[15] { 4, 7, 10, 14, 17, 20, 24, 27, 30, 34, 37, 40, 44, 47, 50 }; private static readonly ulong[] s_rgval64Power10By16 = new ulong[42] { 10240000000000000000, 11368683772161602974, 12621774483536188886, 14012984643248170708, 15557538194652854266, 17272337110188889248, 9588073174409622172, 10644899600020376798, 11818212630765741798, 13120851772591970216, 14567071740625403792, 16172698447808779622, 17955302187076837696, 9967194951097567532, 11065809325636130658, 12285516299433008778, 13639663065038175358, 15143067982934716296, 16812182738118149112, 9332636185032188787, 10361307573072618722, 16615349947311448416, 14965776766268445891, 13479973333575319909, 12141680576410806707, 10936253623915059637, 9850501549098619819, 17745086042373215136, 15983352577617880260, 14396524142538228461, 12967236152753103031, 11679847981112819795, 10520271803096747049, 9475818434452569218, 17070116948172427008, 15375394465392026135, 13848924157002783096, 12474001934591998882, 11235582092889474480, 10120112665365530972, 18230774251475056952, 16420821625123739930 }; private static readonly short[] s_rgexp64Power10By16 = new short[21] { 54, 107, 160, 213, 266, 319, 373, 426, 479, 532, 585, 638, 691, 745, 798, 851, 904, 957, 1010, 1064, 1117 }; public static void RoundNumber(ref NumberBuffer number, int pos) { Span<byte> digits = number.Digits; int i; for (i = 0; i < pos && digits[i] != 0; i++) { } if (i != pos || digits[i] < 53) { while (i > 0 && digits[i - 1] == 48) { i--; } } else { while (i > 0 && digits[i - 1] == 57) { i--; } if (i > 0) digits[i - 1]++; else { number.Scale++; digits[0] = 49; i = 1; } } if (i == 0) { number.Scale = 0; number.IsNegative = false; } digits[i] = 0; } internal static bool NumberBufferToDouble(ref NumberBuffer number, out double value) { double num = NumberToDouble(ref number); uint num2 = DoubleHelper.Exponent(num); ulong num3 = DoubleHelper.Mantissa(num); switch (num2) { case 2047: value = 0; return false; case 0: if (num3 == 0) num = 0; break; } value = num; return true; } public unsafe static bool NumberBufferToDecimal(ref NumberBuffer number, ref decimal value) { MutableDecimal source = default(MutableDecimal); byte* ptr = number.UnsafeDigits; int num = number.Scale; if (*ptr == 0) { if (num > 0) num = 0; } else { if (num > 29) return false; while ((num > 0 || (*ptr != 0 && num > -28)) && (source.High < 429496729 || (source.High == 429496729 && (source.Mid < 2576980377 || (source.Mid == 2576980377 && (source.Low < 2576980377 || (source.Low == 2576980377 && *ptr <= 53))))))) { DecimalDecCalc.DecMul10(ref source); if (*ptr != 0) { byte* intPtr = ptr; ptr = intPtr + 1; DecimalDecCalc.DecAddInt32(ref source, (uint)(*intPtr - 48)); } num--; } byte* intPtr2 = ptr; ptr = intPtr2 + 1; if (*intPtr2 >= 53) { bool flag = true; if (*(ptr - 1) == 53 && (int)(*(ptr - 2)) % 2 == 0) { int num2 = 20; while (*ptr == 48 && num2 != 0) { ptr++; num2--; } if (*ptr == 0 || num2 == 0) flag = false; } if (flag) { DecimalDecCalc.DecAddInt32(ref source, 1); if ((source.High | source.Mid | source.Low) == 0) { source.High = 429496729; source.Mid = 2576980377; source.Low = 2576980378; num++; } } } } if (num > 0) return false; if (num <= -29) { source.High = 0; source.Low = 0; source.Mid = 0; source.Scale = 28; } else source.Scale = -num; source.IsNegative = number.IsNegative; value = Unsafe.As<MutableDecimal, decimal>(ref source); return true; } public static void DecimalToNumber(decimal value, ref NumberBuffer number) { ref MutableDecimal reference = ref Unsafe.As<decimal, MutableDecimal>(ref value); Span<byte> digits = number.Digits; number.IsNegative = reference.IsNegative; int num = 29; while ((reference.Mid != 0) | (reference.High != 0)) { uint num2 = DecimalDecCalc.DecDivMod1E9(ref reference); for (int i = 0; i < 9; i++) { digits[--num] = (byte)(num2 % 10 + 48); num2 /= 10; } } for (uint num3 = reference.Low; num3 != 0; num3 /= 10) { digits[--num] = (byte)(num3 % 10 + 48); } int num4 = 29 - num; number.Scale = num4 - reference.Scale; Span<byte> digits2 = number.Digits; int num5 = 0; while (--num4 >= 0) { digits2[num5++] = digits[num++]; } digits2[num5] = 0; } private static uint DigitsToInt(ReadOnlySpan<byte> digits, int count) { uint value; int bytesConsumed; bool flag = Utf8Parser.TryParse(digits.Slice(0, count), out value, out bytesConsumed, 'D'); return value; } private static ulong Mul32x32To64(uint a, uint b) { return (ulong)((long)a * (long)b); } private static ulong Mul64Lossy(ulong a, ulong b, ref int pexp) { ulong num = Mul32x32To64((uint)(a >> 32), (uint)(b >> 32)) + (Mul32x32To64((uint)(a >> 32), (uint)b) >> 32) + (Mul32x32To64((uint)a, (uint)(b >> 32)) >> 32); if (((long)num & -9223372036854775808) == 0) { num <<= 1; pexp--; } return num; } private static int abs(int value) { if (value < 0) return -value; return value; } private unsafe static double NumberToDouble(ref NumberBuffer number) { ReadOnlySpan<byte> digits = number.Digits; int i = 0; int numDigits = number.NumDigits; int num = numDigits; for (; digits[i] == 48; i++) { num--; } if (num == 0) return 0; int num2 = Math.Min(num, 9); num -= num2; ulong num3 = DigitsToInt(digits, num2); if (num > 0) { num2 = Math.Min(num, 9); num -= num2; uint b = (uint)(s_rgval64Power10[num2 - 1] >> 64 - s_rgexp64Power10[num2 - 1]); num3 = Mul32x32To64((uint)num3, b) + DigitsToInt(digits.Slice(9), num2); } int num4 = number.Scale - (numDigits - num); int num5 = abs(num4); if (num5 >= 352) { ulong num6 = (ulong)((num4 > 0) ? 9218868437227405312 : 0); if (number.IsNegative) num6 = (ulong)((long)num6 | -9223372036854775808); return *(double*)(&num6); } int pexp = 64; if (((long)num3 & -4294967296) == 0) { num3 <<= 32; pexp -= 32; } if (((long)num3 & -281474976710656) == 0) { num3 <<= 16; pexp -= 16; } if (((long)num3 & -72057594037927936) == 0) { num3 <<= 8; pexp -= 8; } if (((long)num3 & -1152921504606846976) == 0) { num3 <<= 4; pexp -= 4; } if (((long)num3 & -4611686018427387904) == 0) { num3 <<= 2; pexp -= 2; } if (((long)num3 & -9223372036854775808) == 0) { num3 <<= 1; pexp--; } int num7 = num5 & 15; if (num7 != 0) { int num8 = s_rgexp64Power10[num7 - 1]; pexp += ((num4 < 0) ? (-num8 + 1) : num8); ulong b2 = s_rgval64Power10[num7 + ((num4 < 0) ? 15 : 0) - 1]; num3 = Mul64Lossy(num3, b2, ref pexp); } num7 = num5 >> 4; if (num7 != 0) { int num9 = s_rgexp64Power10By16[num7 - 1]; pexp += ((num4 < 0) ? (-num9 + 1) : num9); ulong b3 = s_rgval64Power10By16[num7 + ((num4 < 0) ? 21 : 0) - 1]; num3 = Mul64Lossy(num3, b3, ref pexp); } if (((int)num3 & 1024) != 0) { ulong num10 = (ulong)((long)(num3 + 1023) + (long)(((int)num3 >> 11) & 1)); if (num10 < num3) { num10 = (ulong)((long)(num10 >> 1) | -9223372036854775808); pexp++; } num3 = num10; } pexp += 1022; num3 = (ulong)((pexp <= 0) ? ((long)((pexp == -52 && num3 >= 9223372036854775896) ? 1 : ((pexp > -52) ? (num3 >> -pexp + 11 + 1) : 0))) : ((pexp < 2047) ? (((long)pexp << 52) + (long)((num3 >> 11) & 4503599627370495)) : 9218868437227405312)); if (number.IsNegative) num3 = (ulong)((long)num3 | -9223372036854775808); return *(double*)(&num3); } } }