diff --git a/src/libraries/Common/tests/System/GenericMathHelpers.cs b/src/libraries/Common/tests/System/GenericMathHelpers.cs index a3729f35b5a8fe..8a3550afaaaaca 100644 --- a/src/libraries/Common/tests/System/GenericMathHelpers.cs +++ b/src/libraries/Common/tests/System/GenericMathHelpers.cs @@ -64,6 +64,8 @@ public static TSelf RemainderExpected(TSelf left, TSelf right, DivisionRounding public static TSelf LeadingZeroCount(TSelf value) => TSelf.LeadingZeroCount(value); + public static TSelf Log10(TSelf value) => TSelf.Log10(value); + public static TSelf PopCount(TSelf value) => TSelf.PopCount(value); public static TSelf ReadBigEndian(byte[] source, bool isUnsigned) => TSelf.ReadBigEndian(source, isUnsigned); diff --git a/src/libraries/System.Private.CoreLib/src/System/Byte.cs b/src/libraries/System.Private.CoreLib/src/System/Byte.cs index 1c933aaaced78b..331d28cf1d4304 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Byte.cs @@ -281,6 +281,9 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) /// public static byte LeadingZeroCount(byte value) => (byte)(BitOperations.LeadingZeroCount(value) - 24); + /// + public static byte Log10(byte value) => (byte)uint.Log10(value); + /// public static byte PopCount(byte value) => (byte)BitOperations.PopCount(value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Char.cs b/src/libraries/System.Private.CoreLib/src/System/Char.cs index e8ee0692a82d32..42078fa8e05d94 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Char.cs @@ -1214,6 +1214,9 @@ public static int ConvertToUtf32(string s, int index) /// static char IBinaryInteger.LeadingZeroCount(char value) => (char)(BitOperations.LeadingZeroCount(value) - 16); + /// + static char IBinaryInteger.Log10(char value) => (char)uint.Log10(value); + /// static char IBinaryInteger.PopCount(char value) => (char)BitOperations.PopCount(value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int128.cs b/src/libraries/System.Private.CoreLib/src/System/Int128.cs index bfc8e8c8bf0e25..9387db8636ef71 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int128.cs @@ -726,6 +726,16 @@ private static int LeadingZeroCountAsInt32(Int128 value) return BitOperations.LeadingZeroCount(value._upper); } + /// + public static Int128 Log10(Int128 value) + { + if (IsNegative(value)) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + return (Int128)UInt128.Log10((UInt128)value); + } + /// public static Int128 PopCount(Int128 value) => ulong.PopCount(value._lower) + ulong.PopCount(value._upper); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int16.cs b/src/libraries/System.Private.CoreLib/src/System/Int16.cs index b1a90999ea5e9e..c6312f3334c01a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int16.cs @@ -284,6 +284,16 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) /// public static short LeadingZeroCount(short value) => (short)(BitOperations.LeadingZeroCount((ushort)value) - 16); + /// + public static short Log10(short value) + { + if (value < 0) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + return (short)uint.Log10((uint)value); + } + /// public static short PopCount(short value) => (short)BitOperations.PopCount((ushort)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int32.cs b/src/libraries/System.Private.CoreLib/src/System/Int32.cs index 7a0cce55bc8099..b48c681f4b0105 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int32.cs @@ -300,6 +300,17 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) [Intrinsic] public static int LeadingZeroCount(int value) => BitOperations.LeadingZeroCount((uint)value); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Log10(int value) + { + if (value < 0) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + return (int)uint.Log10((uint)value); + } + /// [Intrinsic] public static int PopCount(int value) => BitOperations.PopCount((uint)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Int64.cs b/src/libraries/System.Private.CoreLib/src/System/Int64.cs index aa07dbb7d0327b..18c343fdac1808 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Int64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Int64.cs @@ -297,6 +297,17 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) [Intrinsic] public static long LeadingZeroCount(long value) => BitOperations.LeadingZeroCount((ulong)value); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static long Log10(long value) + { + if (value < 0) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + return (long)ulong.Log10((ulong)value); + } + /// [Intrinsic] public static long PopCount(long value) => BitOperations.PopCount((ulong)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs index 4abd1b935f0eb5..cd6f768526f722 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IntPtr.cs @@ -320,6 +320,17 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro [Intrinsic] public static nint LeadingZeroCount(nint value) => BitOperations.LeadingZeroCount((nuint)value); + /// + public static nint Log10(nint value) + { + if (value < 0) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + + return (nint)nuint.Log10((nuint)value); + } + /// [Intrinsic] public static nint PopCount(nint value) => BitOperations.PopCount((nuint)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs index e44d1bdbd12e84..065519417526ea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs @@ -260,6 +260,35 @@ static virtual TSelf Remainder(TSelf left, TSelf right, DivisionRounding mode) return remainder; } + /// Computes the integer logarithm base 10 of a value. + /// The value whose integer logarithm base 10 is to be computed. + /// The integer logarithm base 10 of . + /// is negative. + /// The result of computing the integer logarithm base 10 of zero is zero. + static virtual TSelf Log10(TSelf value) + { + if (!typeof(TSelf).IsValueType) + { + ArgumentNullException.ThrowIfNull(value); + } + + if (TSelf.IsNegative(value)) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + + TSelf ten = TSelf.CreateChecked(10); + TSelf result = TSelf.Zero; + + while (value >= ten) + { + value /= ten; + result++; + } + + return result; + } + /// Computes the number of leading zero bits in a value. /// The value whose leading zero bits are to be counted. /// The number of leading zero bits in . diff --git a/src/libraries/System.Private.CoreLib/src/System/SByte.cs b/src/libraries/System.Private.CoreLib/src/System/SByte.cs index 4ba9c4372de61b..c22e77da475053 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SByte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SByte.cs @@ -287,6 +287,16 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) /// public static sbyte LeadingZeroCount(sbyte value) => (sbyte)(BitOperations.LeadingZeroCount((byte)value) - 24); + /// + public static sbyte Log10(sbyte value) + { + if (value < 0) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + return (sbyte)uint.Log10((uint)value); + } + /// public static sbyte PopCount(sbyte value) => (sbyte)BitOperations.PopCount((byte)value); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs index 20ad904bc423a2..a2be3c33114199 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt128.cs @@ -797,6 +797,66 @@ private static int LeadingZeroCountAsInt32(UInt128 value) return BitOperations.LeadingZeroCount(value._upper); } + /// + public static UInt128 Log10(UInt128 value) + { + if (value._upper == 0) + { + return ulong.Log10(value._lower); + } + + // Approximate log10 via log2, then correct with a powers of 10 lookup table. + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + value |= 1U; + uint log2 = (uint)Log2(value) + 1; + uint approx = (log2 * 1233) >> 12; + return value < PowersOf10[(int)approx] ? approx - 1 : approx; + } + + // Lookup table for power-of-10 boundaries corrections + private static readonly UInt128[] PowersOf10 = + [ + new UInt128(0, 1UL), + new UInt128(0, 10UL), + new UInt128(0, 100UL), + new UInt128(0, 1_000UL), + new UInt128(0, 10_000UL), + new UInt128(0, 100_000UL), + new UInt128(0, 1_000_000UL), + new UInt128(0, 10_000_000UL), + new UInt128(0, 100_000_000UL), + new UInt128(0, 1_000_000_000UL), + new UInt128(0, 10_000_000_000UL), + new UInt128(0, 100_000_000_000UL), + new UInt128(0, 1_000_000_000_000UL), + new UInt128(0, 10_000_000_000_000UL), + new UInt128(0, 100_000_000_000_000UL), + new UInt128(0, 1_000_000_000_000_000UL), + new UInt128(0, 10_000_000_000_000_000UL), + new UInt128(0, 100_000_000_000_000_000UL), + new UInt128(0, 1_000_000_000_000_000_000UL), + new UInt128(0, 10_000_000_000_000_000_000UL), + new UInt128(5, 7766279631452241920UL), + new UInt128(54, 3875820019684212736UL), + new UInt128(542, 1864712049423024128UL), + new UInt128(5421, 200376420520689664UL), + new UInt128(54210, 2003764205206896640UL), + new UInt128(542101, 1590897978359414784UL), + new UInt128(5421010, 15908979783594147840UL), + new UInt128(54210108, 11515845246265065472UL), + new UInt128(542101086, 4477988020393345024UL), + new UInt128(5421010862, 7886392056514347008UL), + new UInt128(54210108624, 5076944270305263616UL), + new UInt128(542101086242, 13875954555633532928UL), + new UInt128(5421010862427, 9632337040368467968UL), + new UInt128(54210108624275, 4089650035136921600UL), + new UInt128(542101086242752, 4003012203950112768UL), + new UInt128(5421010862427522, 3136633892082024448UL), + new UInt128(54210108624275221, 12919594847110692864UL), + new UInt128(542101086242752217, 68739955140067328UL), + new UInt128(5421010862427522170, 687399551400673280UL), + ]; + /// public static UInt128 PopCount(UInt128 value) => ulong.PopCount(value._lower) + ulong.PopCount(value._upper); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs index 87d4f12a9a10d9..c477fcaaf56ad5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt16.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt16.cs @@ -278,6 +278,9 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) /// public static ushort LeadingZeroCount(ushort value) => (ushort)(BitOperations.LeadingZeroCount(value) - 16); + /// + public static ushort Log10(ushort value) => (ushort)uint.Log10(value); + /// public static ushort PopCount(ushort value) => (ushort)BitOperations.PopCount(value); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs index a774069fb560b2..dc3282ad146444 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt32.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt32.cs @@ -295,6 +295,35 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) [Intrinsic] public static uint LeadingZeroCount(uint value) => (uint)BitOperations.LeadingZeroCount(value); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint Log10(uint value) + { + // Use Log2 to get approximate Log10 via the relationship: + // log10(x) ≈ (log2(x) + 1) * 1233 >> 12 + // Then correct with a powers-of-10 lookup table. + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + value |= 1; + uint log2 = (uint)BitOperations.Log2(value) + 1; + uint approx = (log2 * 1233) >> 12; + return value < PowersOf10[(int)approx] ? approx - 1 : approx; + } + + // Lookup table for power-of-10 boundaries corrections + private static ReadOnlySpan PowersOf10 => + [ + 1, + 10, + 100, + 1_000, + 10_000, + 100_000, + 1_000_000, + 10_000_000, + 100_000_000, + 1_000_000_000, + ]; + /// [Intrinsic] public static uint PopCount(uint value) => (uint)BitOperations.PopCount(value); diff --git a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs index 56d9fc2cc2015a..8abc0f1b5a4a9d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UInt64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UInt64.cs @@ -294,6 +294,43 @@ object IConvertible.ToType(Type type, IFormatProvider? provider) [Intrinsic] public static ulong LeadingZeroCount(ulong value) => (ulong)BitOperations.LeadingZeroCount(value); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong Log10(ulong value) + { + // Approximate log10 via log2, then correct with a powers of 10 lookup table. + // http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + value |= 1; + uint log2 = (uint)BitOperations.Log2(value) + 1; + uint approx = (log2 * 1233) >> 12; + return value < PowersOf10[(int)approx] ? approx - 1 : approx; + } + + // Lookup table for power-of-10 boundaries corrections + private static ReadOnlySpan PowersOf10 => + [ + 1, + 10, + 100, + 1_000, + 10_000, + 100_000, + 1_000_000, + 10_000_000, + 100_000_000, + 1_000_000_000, + 10_000_000_000, + 100_000_000_000, + 1_000_000_000_000, + 10_000_000_000_000, + 100_000_000_000_000, + 1_000_000_000_000_000, + 10_000_000_000_000_000, + 100_000_000_000_000_000, + 1_000_000_000_000_000_000, + 10_000_000_000_000_000_000, + ]; + /// [Intrinsic] public static ulong PopCount(ulong value) => (ulong)BitOperations.PopCount(value); diff --git a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs index 450160040fb4f7..fe1f01e314ab58 100644 --- a/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs +++ b/src/libraries/System.Private.CoreLib/src/System/UIntPtr.cs @@ -316,6 +316,16 @@ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatPro [Intrinsic] public static nuint LeadingZeroCount(nuint value) => (nuint)BitOperations.LeadingZeroCount(value); + /// + public static nuint Log10(nuint value) + { +#if TARGET_64BIT + return (nuint)ulong.Log10((ulong)value); +#else + return (nuint)uint.Log10((uint)value); +#endif + } + /// [Intrinsic] public static nuint PopCount(nuint value) => (nuint)BitOperations.PopCount(value); diff --git a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs index 9c3e42270020ca..e080d40f99ce11 100644 --- a/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs +++ b/src/libraries/System.Runtime.Numerics/ref/System.Runtime.Numerics.cs @@ -200,6 +200,7 @@ namespace System.Numerics public static System.Numerics.BigInteger Subtract(System.Numerics.BigInteger left, System.Numerics.BigInteger right) { throw null; } int System.Numerics.IBinaryInteger.GetByteCount() { throw null; } int System.Numerics.IBinaryInteger.GetShortestBitLength() { throw null; } + static System.Numerics.BigInteger System.Numerics.IBinaryInteger.Log10(System.Numerics.BigInteger value) { throw null; } static bool System.Numerics.IBinaryInteger.TryReadBigEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } static bool System.Numerics.IBinaryInteger.TryReadLittleEndian(System.ReadOnlySpan source, bool isUnsigned, out System.Numerics.BigInteger value) { throw null; } bool System.Numerics.IBinaryInteger.TryWriteBigEndian(System.Span destination, out int bytesWritten) { throw null; } diff --git a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs index aa6389fcf94c8f..10ea7468af201e 100644 --- a/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs +++ b/src/libraries/System.Runtime.Numerics/src/System/Numerics/BigInteger.cs @@ -3141,6 +3141,36 @@ private void AssertValid() // IBinaryInteger // + /// + static BigInteger IBinaryInteger.Log10(BigInteger value) + { + value.AssertValid(); + + if (IsNegative(value)) + { + ThrowHelper.ThrowValueArgumentOutOfRange_NeedNonNegNumException(); + } + + // For small values stored in _sign, use the fast path + if (value._bits is null) + { + return uint.Log10((uint)value._sign); + } + + // For large values, use Log2-based estimation with single correction. + // log10(x) = log2(x) * log10(2); we approximate log10(2) as N/2^S. + // The smaller fixed-width types (uint, ulong, UInt128) use 1233/4096 + // (~4.6e-6 error per bit), which is sufficient for up to ~217K bits. + // For BigInteger, which has no upper bound on bit count, we use + // 1292913986/2^32 (~1.1e-10 error per bit), safe up to ~8.7B bits, + // which covers the full BigInteger range. + BigInteger log2Value = Log2(value); + BigInteger approx = ((log2Value + 1) * 1292913986L) >> 32; + BigInteger power = Pow(10, (int)approx); + + return value < power ? approx - 1 : approx; + } + /// public static (BigInteger Quotient, BigInteger Remainder) DivRem(BigInteger left, BigInteger right) { diff --git a/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs b/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs index 721ac8bc3fe9d7..e5fb00728bffc7 100644 --- a/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs +++ b/src/libraries/System.Runtime.Numerics/tests/BigIntegerTests.GenericMath.cs @@ -206,6 +206,46 @@ public static void DivRemTest() Assert.Equal((Int64MaxValue, One), BinaryIntegerHelper.DivRem(UInt64MaxValue, 2)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((BigInteger)0, BinaryIntegerHelper.Log10(Zero)); + Assert.Equal((BigInteger)0, BinaryIntegerHelper.Log10(One)); + + BigInteger power = 1; + for (int n = 0; n < 25; n++) + { + Assert.Equal((BigInteger)n, BinaryIntegerHelper.Log10(power)); + if (power > 1) + { + Assert.Equal((BigInteger)(n - 1), BinaryIntegerHelper.Log10(power - 1)); + } + power *= 10; + } + + Assert.Equal((BigInteger)18, BinaryIntegerHelper.Log10(Int64MaxValue)); + Assert.Throws(() => BinaryIntegerHelper.Log10(NegativeOne)); + Assert.Throws(() => BinaryIntegerHelper.Log10(Int64MinValue)); + } + + [Fact] + public static void Log10Test_LargeValues() + { + // 2^681 produces log10 = 205, verifying correctness for values + // beyond the fixed-width type range. + Assert.Equal((BigInteger)205, BinaryIntegerHelper.Log10(BigInteger.Pow(2, 681))); + } + + [Fact] + [OuterLoop] + public static void Log10Test_VeryLargeValues() + { + // 2^217769 produces log10 = 65555, verifying correctness for + // very large values where a less precise approximation constant + // would fail. + Assert.Equal((BigInteger)65555, BinaryIntegerHelper.Log10(BigInteger.Pow(2, 217769))); + } + [Fact] public static void LeadingZeroCountTest() { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 6bb8a8766c5e88..fe3fa7b429897b 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -965,6 +965,7 @@ public static void SetByte(System.Array array, int index, byte value) { } public static bool IsOddInteger(byte value) { throw null; } public static bool IsPow2(byte value) { throw null; } public static byte LeadingZeroCount(byte value) { throw null; } + public static byte Log10(byte value) { throw null; } public static byte Log2(byte value) { throw null; } public static byte Max(byte x, byte y) { throw null; } public static byte Min(byte x, byte y) { throw null; } @@ -1182,6 +1183,7 @@ public CannotUnloadAppDomainException(string? message, System.Exception? innerEx int System.Numerics.IBinaryInteger.GetByteCount() { throw null; } int System.Numerics.IBinaryInteger.GetShortestBitLength() { throw null; } static char System.Numerics.IBinaryInteger.LeadingZeroCount(char value) { throw null; } + static char System.Numerics.IBinaryInteger.Log10(char value) { throw null; } static char System.Numerics.IBinaryInteger.PopCount(char value) { throw null; } static char System.Numerics.IBinaryInteger.RotateLeft(char value, int rotateAmount) { throw null; } static char System.Numerics.IBinaryInteger.RotateRight(char value, int rotateAmount) { throw null; } @@ -3612,6 +3614,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static bool IsPositive(System.Int128 value) { throw null; } public static bool IsPow2(System.Int128 value) { throw null; } public static System.Int128 LeadingZeroCount(System.Int128 value) { throw null; } + public static System.Int128 Log10(System.Int128 value) { throw null; } public static System.Int128 Log2(System.Int128 value) { throw null; } public static System.Int128 Max(System.Int128 x, System.Int128 y) { throw null; } public static System.Int128 MaxMagnitude(System.Int128 x, System.Int128 y) { throw null; } @@ -3799,6 +3802,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static bool IsPositive(short value) { throw null; } public static bool IsPow2(short value) { throw null; } public static short LeadingZeroCount(short value) { throw null; } + public static short Log10(short value) { throw null; } public static short Log2(short value) { throw null; } public static short Max(short x, short y) { throw null; } public static short MaxMagnitude(short x, short y) { throw null; } @@ -3940,6 +3944,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static bool IsPositive(int value) { throw null; } public static bool IsPow2(int value) { throw null; } public static int LeadingZeroCount(int value) { throw null; } + public static int Log10(int value) { throw null; } public static int Log2(int value) { throw null; } public static int Max(int x, int y) { throw null; } public static int MaxMagnitude(int x, int y) { throw null; } @@ -4081,6 +4086,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static bool IsPositive(long value) { throw null; } public static bool IsPow2(long value) { throw null; } public static long LeadingZeroCount(long value) { throw null; } + public static long Log10(long value) { throw null; } public static long Log2(long value) { throw null; } public static long Max(long x, long y) { throw null; } public static long MaxMagnitude(long x, long y) { throw null; } @@ -4228,6 +4234,7 @@ public InsufficientMemoryException(string? message, System.Exception? innerExcep public static bool IsPositive(nint value) { throw null; } public static bool IsPow2(nint value) { throw null; } public static nint LeadingZeroCount(nint value) { throw null; } + public static nint Log10(nint value) { throw null; } public static nint Log2(nint value) { throw null; } public static nint Max(nint x, nint y) { throw null; } public static nint MaxMagnitude(nint x, nint y) { throw null; } @@ -5242,6 +5249,7 @@ public void GetObjectData(System.Runtime.Serialization.SerializationInfo info, S public static bool IsPositive(sbyte value) { throw null; } public static bool IsPow2(sbyte value) { throw null; } public static sbyte LeadingZeroCount(sbyte value) { throw null; } + public static sbyte Log10(sbyte value) { throw null; } public static sbyte Log2(sbyte value) { throw null; } public static sbyte Max(sbyte x, sbyte y) { throw null; } public static sbyte MaxMagnitude(sbyte x, sbyte y) { throw null; } @@ -6901,6 +6909,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static bool IsOddInteger(System.UInt128 value) { throw null; } public static bool IsPow2(System.UInt128 value) { throw null; } public static System.UInt128 LeadingZeroCount(System.UInt128 value) { throw null; } + public static System.UInt128 Log10(System.UInt128 value) { throw null; } public static System.UInt128 Log2(System.UInt128 value) { throw null; } public static System.UInt128 Max(System.UInt128 x, System.UInt128 y) { throw null; } public static System.UInt128 Min(System.UInt128 x, System.UInt128 y) { throw null; } @@ -7094,6 +7103,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static bool IsOddInteger(ushort value) { throw null; } public static bool IsPow2(ushort value) { throw null; } public static ushort LeadingZeroCount(ushort value) { throw null; } + public static ushort Log10(ushort value) { throw null; } public static ushort Log2(ushort value) { throw null; } public static ushort Max(ushort x, ushort y) { throw null; } public static ushort Min(ushort x, ushort y) { throw null; } @@ -7235,6 +7245,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static bool IsOddInteger(uint value) { throw null; } public static bool IsPow2(uint value) { throw null; } public static uint LeadingZeroCount(uint value) { throw null; } + public static uint Log10(uint value) { throw null; } public static uint Log2(uint value) { throw null; } public static uint Max(uint x, uint y) { throw null; } public static uint Min(uint x, uint y) { throw null; } @@ -7376,6 +7387,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static bool IsOddInteger(ulong value) { throw null; } public static bool IsPow2(ulong value) { throw null; } public static ulong LeadingZeroCount(ulong value) { throw null; } + public static ulong Log10(ulong value) { throw null; } public static ulong Log2(ulong value) { throw null; } public static ulong Max(ulong x, ulong y) { throw null; } public static ulong Min(ulong x, ulong y) { throw null; } @@ -7522,6 +7534,7 @@ public TypeUnloadedException(string? message, System.Exception? innerException) public static bool IsOddInteger(nuint value) { throw null; } public static bool IsPow2(nuint value) { throw null; } public static nuint LeadingZeroCount(nuint value) { throw null; } + public static nuint Log10(nuint value) { throw null; } public static nuint Log2(nuint value) { throw null; } public static nuint Max(nuint x, nuint y) { throw null; } public static nuint Min(nuint x, nuint y) { throw null; } @@ -11621,6 +11634,7 @@ public partial interface IBinaryInteger : System.IComparable, System.ICom static virtual TSelf Remainder(TSelf left, TSelf right, System.Numerics.DivisionRounding mode) { throw null; } int GetByteCount(); int GetShortestBitLength(); + static virtual TSelf Log10(TSelf value) { throw null; } static virtual TSelf LeadingZeroCount(TSelf value) { throw null; } static abstract TSelf PopCount(TSelf value); static virtual TSelf ReadBigEndian(byte[] source, bool isUnsigned) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs index f61cac08977f1f..c98230725abf21 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ByteTests.GenericMath.cs @@ -180,6 +180,20 @@ public static void LeadingZeroCountTest() Assert.Equal((byte)0x00, BinaryIntegerHelper.LeadingZeroCount((byte)0xFF)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((byte)0, BinaryIntegerHelper.Log10((byte)0)); + Assert.Equal((byte)0, BinaryIntegerHelper.Log10((byte)1)); + Assert.Equal((byte)0, BinaryIntegerHelper.Log10((byte)9)); + Assert.Equal((byte)1, BinaryIntegerHelper.Log10((byte)10)); + Assert.Equal((byte)1, BinaryIntegerHelper.Log10((byte)99)); + Assert.Equal((byte)2, BinaryIntegerHelper.Log10((byte)100)); + Assert.Equal((byte)2, BinaryIntegerHelper.Log10((byte)127)); + Assert.Equal((byte)2, BinaryIntegerHelper.Log10((byte)128)); + Assert.Equal((byte)2, BinaryIntegerHelper.Log10((byte)255)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs index fbdc9862c29dc7..c6e19a47df6872 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/CharTests.GenericMath.cs @@ -179,6 +179,24 @@ public static void LeadingZeroCountTest() Assert.Equal((char)0x0000, BinaryIntegerHelper.LeadingZeroCount((char)0xFFFF)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((char)0, BinaryIntegerHelper.Log10((char)0)); + Assert.Equal((char)0, BinaryIntegerHelper.Log10((char)1)); + Assert.Equal((char)0, BinaryIntegerHelper.Log10((char)9)); + Assert.Equal((char)1, BinaryIntegerHelper.Log10((char)10)); + Assert.Equal((char)1, BinaryIntegerHelper.Log10((char)99)); + Assert.Equal((char)2, BinaryIntegerHelper.Log10((char)100)); + Assert.Equal((char)2, BinaryIntegerHelper.Log10((char)999)); + Assert.Equal((char)3, BinaryIntegerHelper.Log10((char)1000)); + Assert.Equal((char)3, BinaryIntegerHelper.Log10((char)9999)); + Assert.Equal((char)4, BinaryIntegerHelper.Log10((char)10000)); + Assert.Equal((char)4, BinaryIntegerHelper.Log10((char)32767)); + Assert.Equal((char)4, BinaryIntegerHelper.Log10((char)32768)); + Assert.Equal((char)4, BinaryIntegerHelper.Log10((char)65535)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs index 6b3a9bc643b37f..e2986a79883746 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int128Tests.GenericMath.cs @@ -229,6 +229,28 @@ public static void LeadingZeroCountTest() Assert.Equal(0x00, BinaryIntegerHelper.LeadingZeroCount(NegativeOne)); } + [Fact] + public static void Log10Test() + { + Assert.Equal(0, BinaryIntegerHelper.Log10(Zero)); + Assert.Equal(0, BinaryIntegerHelper.Log10(One)); + + Int128 power = 1; + for (int n = 0; n < 38; n++) + { + Assert.Equal((Int128)n, BinaryIntegerHelper.Log10(power)); + if (power > 1) + { + Assert.Equal((Int128)(n - 1), BinaryIntegerHelper.Log10(power - 1)); + } + power *= 10; + } + + Assert.Equal(38, BinaryIntegerHelper.Log10(MaxValue)); + Assert.Throws(() => BinaryIntegerHelper.Log10(MinValue)); + Assert.Throws(() => BinaryIntegerHelper.Log10(NegativeOne)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs index c2c2baeadb585b..44f3f57461faec 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int16Tests.GenericMath.cs @@ -192,6 +192,24 @@ public static void LeadingZeroCountTest() Assert.Equal((short)0x0000, BinaryIntegerHelper.LeadingZeroCount(unchecked((short)0xFFFF))); } + [Fact] + public static void Log10Test() + { + Assert.Equal((short)0, BinaryIntegerHelper.Log10((short)0)); + Assert.Equal((short)0, BinaryIntegerHelper.Log10((short)1)); + Assert.Equal((short)0, BinaryIntegerHelper.Log10((short)9)); + Assert.Equal((short)1, BinaryIntegerHelper.Log10((short)10)); + Assert.Equal((short)1, BinaryIntegerHelper.Log10((short)99)); + Assert.Equal((short)2, BinaryIntegerHelper.Log10((short)100)); + Assert.Equal((short)2, BinaryIntegerHelper.Log10((short)999)); + Assert.Equal((short)3, BinaryIntegerHelper.Log10((short)1000)); + Assert.Equal((short)3, BinaryIntegerHelper.Log10((short)9999)); + Assert.Equal((short)4, BinaryIntegerHelper.Log10((short)10000)); + Assert.Equal((short)4, BinaryIntegerHelper.Log10((short)32767)); + Assert.Throws(() => BinaryIntegerHelper.Log10((short)(-32768))); + Assert.Throws(() => BinaryIntegerHelper.Log10((short)(-1))); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.GenericMath.cs index 5d98e93a7084a8..a6166828336e85 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int32Tests.GenericMath.cs @@ -192,6 +192,34 @@ public static void LeadingZeroCountTest() Assert.Equal((int)0x00000000, BinaryIntegerHelper.LeadingZeroCount(unchecked((int)0xFFFFFFFF))); } + [Fact] + public static void Log10Test() + { + Assert.Equal(0, BinaryIntegerHelper.Log10(0)); + Assert.Equal(0, BinaryIntegerHelper.Log10(1)); + Assert.Equal(0, BinaryIntegerHelper.Log10(9)); + Assert.Equal(1, BinaryIntegerHelper.Log10(10)); + Assert.Equal(1, BinaryIntegerHelper.Log10(99)); + Assert.Equal(2, BinaryIntegerHelper.Log10(100)); + Assert.Equal(2, BinaryIntegerHelper.Log10(999)); + Assert.Equal(3, BinaryIntegerHelper.Log10(1_000)); + Assert.Equal(3, BinaryIntegerHelper.Log10(9_999)); + Assert.Equal(4, BinaryIntegerHelper.Log10(10_000)); + Assert.Equal(4, BinaryIntegerHelper.Log10(99_999)); + Assert.Equal(5, BinaryIntegerHelper.Log10(100_000)); + Assert.Equal(5, BinaryIntegerHelper.Log10(999_999)); + Assert.Equal(6, BinaryIntegerHelper.Log10(1_000_000)); + Assert.Equal(6, BinaryIntegerHelper.Log10(9_999_999)); + Assert.Equal(7, BinaryIntegerHelper.Log10(10_000_000)); + Assert.Equal(7, BinaryIntegerHelper.Log10(99_999_999)); + Assert.Equal(8, BinaryIntegerHelper.Log10(100_000_000)); + Assert.Equal(8, BinaryIntegerHelper.Log10(999_999_999)); + Assert.Equal(9, BinaryIntegerHelper.Log10(1_000_000_000)); + Assert.Equal(9, BinaryIntegerHelper.Log10(2_147_483_647)); + Assert.Throws(() => BinaryIntegerHelper.Log10(-2_147_483_648)); + Assert.Throws(() => BinaryIntegerHelper.Log10(-1)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.GenericMath.cs index 46561b30232607..2f2fc0098fac91 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Int64Tests.GenericMath.cs @@ -192,6 +192,52 @@ public static void LeadingZeroCountTest() Assert.Equal((long)0x0000000000000000, BinaryIntegerHelper.LeadingZeroCount(unchecked((long)0xFFFFFFFFFFFFFFFF))); } + [Fact] + public static void Log10Test() + { + Assert.Equal((long)0, BinaryIntegerHelper.Log10((long)0)); + Assert.Equal((long)0, BinaryIntegerHelper.Log10((long)1)); + Assert.Equal((long)0, BinaryIntegerHelper.Log10((long)9)); + Assert.Equal((long)1, BinaryIntegerHelper.Log10((long)10)); + Assert.Equal((long)1, BinaryIntegerHelper.Log10((long)99)); + Assert.Equal((long)2, BinaryIntegerHelper.Log10((long)100)); + Assert.Equal((long)2, BinaryIntegerHelper.Log10((long)999)); + Assert.Equal((long)3, BinaryIntegerHelper.Log10((long)1_000)); + Assert.Equal((long)3, BinaryIntegerHelper.Log10((long)9_999)); + Assert.Equal((long)4, BinaryIntegerHelper.Log10((long)10_000)); + Assert.Equal((long)4, BinaryIntegerHelper.Log10((long)99_999)); + Assert.Equal((long)5, BinaryIntegerHelper.Log10((long)100_000)); + Assert.Equal((long)5, BinaryIntegerHelper.Log10((long)999_999)); + Assert.Equal((long)6, BinaryIntegerHelper.Log10((long)1_000_000)); + Assert.Equal((long)6, BinaryIntegerHelper.Log10((long)9_999_999)); + Assert.Equal((long)7, BinaryIntegerHelper.Log10((long)10_000_000)); + Assert.Equal((long)7, BinaryIntegerHelper.Log10((long)99_999_999)); + Assert.Equal((long)8, BinaryIntegerHelper.Log10((long)100_000_000)); + Assert.Equal((long)8, BinaryIntegerHelper.Log10((long)999_999_999)); + Assert.Equal((long)9, BinaryIntegerHelper.Log10((long)1_000_000_000)); + Assert.Equal((long)9, BinaryIntegerHelper.Log10((long)9_999_999_999)); + Assert.Equal((long)10, BinaryIntegerHelper.Log10((long)10_000_000_000)); + Assert.Equal((long)10, BinaryIntegerHelper.Log10((long)99_999_999_999)); + Assert.Equal((long)11, BinaryIntegerHelper.Log10((long)100_000_000_000)); + Assert.Equal((long)11, BinaryIntegerHelper.Log10((long)999_999_999_999)); + Assert.Equal((long)12, BinaryIntegerHelper.Log10((long)1_000_000_000_000)); + Assert.Equal((long)12, BinaryIntegerHelper.Log10((long)9_999_999_999_999)); + Assert.Equal((long)13, BinaryIntegerHelper.Log10((long)10_000_000_000_000)); + Assert.Equal((long)13, BinaryIntegerHelper.Log10((long)99_999_999_999_999)); + Assert.Equal((long)14, BinaryIntegerHelper.Log10((long)100_000_000_000_000)); + Assert.Equal((long)14, BinaryIntegerHelper.Log10((long)999_999_999_999_999)); + Assert.Equal((long)15, BinaryIntegerHelper.Log10((long)1_000_000_000_000_000)); + Assert.Equal((long)15, BinaryIntegerHelper.Log10((long)9_999_999_999_999_999)); + Assert.Equal((long)16, BinaryIntegerHelper.Log10((long)10_000_000_000_000_000)); + Assert.Equal((long)16, BinaryIntegerHelper.Log10((long)99_999_999_999_999_999)); + Assert.Equal((long)17, BinaryIntegerHelper.Log10((long)100_000_000_000_000_000)); + Assert.Equal((long)17, BinaryIntegerHelper.Log10((long)999_999_999_999_999_999)); + Assert.Equal((long)18, BinaryIntegerHelper.Log10((long)1_000_000_000_000_000_000)); + Assert.Equal((long)18, BinaryIntegerHelper.Log10((long)9_223_372_036_854_775_807)); + Assert.Throws(() => BinaryIntegerHelper.Log10(-9_223_372_036_854_775_808)); + Assert.Throws(() => BinaryIntegerHelper.Log10(-1)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.GenericMath.cs index 18ab5ad3f276ae..cfac7e4164c2aa 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/IntPtrTests.GenericMath.cs @@ -343,6 +343,33 @@ public static void LeadingZeroCountTest() } } + [Fact] + public static void Log10Test() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(unchecked((nint)0), BinaryIntegerHelper.Log10(unchecked((nint)0))); + Assert.Equal(unchecked((nint)0), BinaryIntegerHelper.Log10(unchecked((nint)1))); + Assert.Equal(unchecked((nint)0), BinaryIntegerHelper.Log10(unchecked((nint)9))); + Assert.Equal(unchecked((nint)1), BinaryIntegerHelper.Log10(unchecked((nint)10))); + Assert.Equal(unchecked((nint)2), BinaryIntegerHelper.Log10(unchecked((nint)100))); + Assert.Equal(unchecked((nint)18), BinaryIntegerHelper.Log10(unchecked((nint)9_223_372_036_854_775_807))); + Assert.Throws(() => BinaryIntegerHelper.Log10(unchecked((nint)0x8000000000000000))); + Assert.Throws(() => BinaryIntegerHelper.Log10(unchecked((nint)0xFFFFFFFFFFFFFFFF))); + } + else + { + Assert.Equal((nint)0, BinaryIntegerHelper.Log10((nint)0)); + Assert.Equal((nint)0, BinaryIntegerHelper.Log10((nint)1)); + Assert.Equal((nint)0, BinaryIntegerHelper.Log10((nint)9)); + Assert.Equal((nint)1, BinaryIntegerHelper.Log10((nint)10)); + Assert.Equal((nint)2, BinaryIntegerHelper.Log10((nint)100)); + Assert.Equal((nint)9, BinaryIntegerHelper.Log10((nint)2_147_483_647)); + Assert.Throws(() => BinaryIntegerHelper.Log10(unchecked((nint)0x80000000))); + Assert.Throws(() => BinaryIntegerHelper.Log10(unchecked((nint)0xFFFFFFFF))); + } + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/DimTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/DimTests.GenericMath.cs index 45c86664f6e597..cdcf4898609f45 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/DimTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/Numerics/DimTests.GenericMath.cs @@ -316,6 +316,30 @@ public static void LeadingZeroCountUInt32Test() Assert.Equal((BinaryIntegerWrapper)0x00000000, BinaryIntegerHelper>.LeadingZeroCount((uint)0xFFFFFFFF)); } + [Fact] + public static void Log10Int32Test() + { + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((int)0)); + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((int)1)); + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((int)9)); + Assert.Equal((BinaryIntegerWrapper)1, BinaryIntegerHelper>.Log10((int)10)); + Assert.Equal((BinaryIntegerWrapper)2, BinaryIntegerHelper>.Log10((int)100)); + Assert.Equal((BinaryIntegerWrapper)9, BinaryIntegerHelper>.Log10(int.MaxValue)); + Assert.Throws(() => BinaryIntegerHelper>.Log10(int.MinValue)); + Assert.Throws(() => BinaryIntegerHelper>.Log10((int)(-1))); + } + + [Fact] + public static void Log10UInt32Test() + { + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((uint)0)); + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((uint)1)); + Assert.Equal((BinaryIntegerWrapper)0, BinaryIntegerHelper>.Log10((uint)9)); + Assert.Equal((BinaryIntegerWrapper)1, BinaryIntegerHelper>.Log10((uint)10)); + Assert.Equal((BinaryIntegerWrapper)2, BinaryIntegerHelper>.Log10((uint)100)); + Assert.Equal((BinaryIntegerWrapper)9, BinaryIntegerHelper>.Log10(uint.MaxValue)); + } + [Fact] public static void RotateLeftInt32Test() { @@ -716,6 +740,12 @@ public int CompareTo(object? obj) static bool INumberBase>.TryConvertFromChecked(TOther value, out BinaryIntegerWrapper result) { + if (typeof(TOther) == typeof(T)) + { + result = (T)(object)value; + return true; + } + bool succeeded = T.TryConvertFromChecked(value, out T actualResult); if (!succeeded) @@ -728,6 +758,12 @@ static bool INumberBase>.TryConvertFromChecked(T } static bool INumberBase>.TryConvertFromSaturating(TOther value, out BinaryIntegerWrapper result) { + if (typeof(TOther) == typeof(T)) + { + result = (T)(object)value; + return true; + } + bool succeeded = T.TryConvertFromSaturating(value, out T actualResult); if (!succeeded) @@ -740,6 +776,12 @@ static bool INumberBase>.TryConvertFromSaturating>.TryConvertFromTruncating(TOther value, out BinaryIntegerWrapper result) { + if (typeof(TOther) == typeof(T)) + { + result = (T)(object)value; + return true; + } + bool succeeded = T.TryConvertFromTruncating(value, out T actualResult); if (!succeeded) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs index 82a0f58cbf5b3d..48412bf11c52ee 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SByteTests.GenericMath.cs @@ -192,6 +192,20 @@ public static void LeadingZeroCountTest() Assert.Equal((sbyte)0x00, BinaryIntegerHelper.LeadingZeroCount(unchecked((sbyte)0xFF))); } + [Fact] + public static void Log10Test() + { + Assert.Equal((sbyte)0, BinaryIntegerHelper.Log10((sbyte)0)); + Assert.Equal((sbyte)0, BinaryIntegerHelper.Log10((sbyte)1)); + Assert.Equal((sbyte)0, BinaryIntegerHelper.Log10((sbyte)9)); + Assert.Equal((sbyte)1, BinaryIntegerHelper.Log10((sbyte)10)); + Assert.Equal((sbyte)1, BinaryIntegerHelper.Log10((sbyte)99)); + Assert.Equal((sbyte)2, BinaryIntegerHelper.Log10((sbyte)100)); + Assert.Equal((sbyte)2, BinaryIntegerHelper.Log10((sbyte)127)); + Assert.Throws(() => BinaryIntegerHelper.Log10((sbyte)(-128))); + Assert.Throws(() => BinaryIntegerHelper.Log10((sbyte)(-1))); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.GenericMath.cs index 8492d36367bc03..797e1e322426e7 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt128Tests.GenericMath.cs @@ -230,6 +230,26 @@ public static void LeadingZeroCountTest() Assert.Equal(0x00U, BinaryIntegerHelper.LeadingZeroCount(MaxValue)); } + [Fact] + public static void Log10Test() + { + Assert.Equal(0U, BinaryIntegerHelper.Log10(Zero)); + Assert.Equal(0U, BinaryIntegerHelper.Log10(One)); + + UInt128 power = 1; + for (uint n = 0; n < 38; n++) + { + Assert.Equal((UInt128)n, BinaryIntegerHelper.Log10(power)); + if (power > 1) + { + Assert.Equal((UInt128)(n - 1), BinaryIntegerHelper.Log10(power - 1)); + } + power *= 10; + } + + Assert.Equal(38U, BinaryIntegerHelper.Log10(MaxValue)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs index 38d0b2ccdb6b74..4a0109d26a222b 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt16Tests.GenericMath.cs @@ -180,6 +180,24 @@ public static void LeadingZeroCountTest() Assert.Equal((ushort)0x0000, BinaryIntegerHelper.LeadingZeroCount((ushort)0xFFFF)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((ushort)0, BinaryIntegerHelper.Log10((ushort)0)); + Assert.Equal((ushort)0, BinaryIntegerHelper.Log10((ushort)1)); + Assert.Equal((ushort)0, BinaryIntegerHelper.Log10((ushort)9)); + Assert.Equal((ushort)1, BinaryIntegerHelper.Log10((ushort)10)); + Assert.Equal((ushort)1, BinaryIntegerHelper.Log10((ushort)99)); + Assert.Equal((ushort)2, BinaryIntegerHelper.Log10((ushort)100)); + Assert.Equal((ushort)2, BinaryIntegerHelper.Log10((ushort)999)); + Assert.Equal((ushort)3, BinaryIntegerHelper.Log10((ushort)1000)); + Assert.Equal((ushort)3, BinaryIntegerHelper.Log10((ushort)9999)); + Assert.Equal((ushort)4, BinaryIntegerHelper.Log10((ushort)10000)); + Assert.Equal((ushort)4, BinaryIntegerHelper.Log10((ushort)32767)); + Assert.Equal((ushort)4, BinaryIntegerHelper.Log10((ushort)32768)); + Assert.Equal((ushort)4, BinaryIntegerHelper.Log10((ushort)65535)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.GenericMath.cs index b6ea65ed198988..25db7c87f97b85 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt32Tests.GenericMath.cs @@ -181,6 +181,32 @@ public static void LeadingZeroCountTest() Assert.Equal((uint)0x00000000, BinaryIntegerHelper.LeadingZeroCount((uint)0xFFFFFFFF)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((uint)0, BinaryIntegerHelper.Log10((uint)0)); + Assert.Equal((uint)0, BinaryIntegerHelper.Log10((uint)1)); + Assert.Equal((uint)0, BinaryIntegerHelper.Log10((uint)9)); + Assert.Equal((uint)1, BinaryIntegerHelper.Log10((uint)10)); + Assert.Equal((uint)1, BinaryIntegerHelper.Log10((uint)99)); + Assert.Equal((uint)2, BinaryIntegerHelper.Log10((uint)100)); + Assert.Equal((uint)2, BinaryIntegerHelper.Log10((uint)999)); + Assert.Equal((uint)3, BinaryIntegerHelper.Log10((uint)1_000)); + Assert.Equal((uint)3, BinaryIntegerHelper.Log10((uint)9_999)); + Assert.Equal((uint)4, BinaryIntegerHelper.Log10((uint)10_000)); + Assert.Equal((uint)4, BinaryIntegerHelper.Log10((uint)99_999)); + Assert.Equal((uint)5, BinaryIntegerHelper.Log10((uint)100_000)); + Assert.Equal((uint)5, BinaryIntegerHelper.Log10((uint)999_999)); + Assert.Equal((uint)6, BinaryIntegerHelper.Log10((uint)1_000_000)); + Assert.Equal((uint)6, BinaryIntegerHelper.Log10((uint)9_999_999)); + Assert.Equal((uint)7, BinaryIntegerHelper.Log10((uint)10_000_000)); + Assert.Equal((uint)7, BinaryIntegerHelper.Log10((uint)99_999_999)); + Assert.Equal((uint)8, BinaryIntegerHelper.Log10((uint)100_000_000)); + Assert.Equal((uint)8, BinaryIntegerHelper.Log10((uint)999_999_999)); + Assert.Equal((uint)9, BinaryIntegerHelper.Log10((uint)1_000_000_000)); + Assert.Equal((uint)9, BinaryIntegerHelper.Log10((uint)4_294_967_295)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.GenericMath.cs index 87ed615d6ca5e0..5c2c77fd52fd13 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UInt64Tests.GenericMath.cs @@ -188,6 +188,52 @@ public static void LeadingZeroCountTest() Assert.Equal((ulong)0x0000000000000000, BinaryIntegerHelper.LeadingZeroCount((ulong)0xFFFFFFFFFFFFFFFF)); } + [Fact] + public static void Log10Test() + { + Assert.Equal((ulong)0, BinaryIntegerHelper.Log10((ulong)0)); + Assert.Equal((ulong)0, BinaryIntegerHelper.Log10((ulong)1)); + Assert.Equal((ulong)0, BinaryIntegerHelper.Log10((ulong)9)); + Assert.Equal((ulong)1, BinaryIntegerHelper.Log10((ulong)10)); + Assert.Equal((ulong)1, BinaryIntegerHelper.Log10((ulong)99)); + Assert.Equal((ulong)2, BinaryIntegerHelper.Log10((ulong)100)); + Assert.Equal((ulong)2, BinaryIntegerHelper.Log10((ulong)999)); + Assert.Equal((ulong)3, BinaryIntegerHelper.Log10((ulong)1_000)); + Assert.Equal((ulong)3, BinaryIntegerHelper.Log10((ulong)9_999)); + Assert.Equal((ulong)4, BinaryIntegerHelper.Log10((ulong)10_000)); + Assert.Equal((ulong)4, BinaryIntegerHelper.Log10((ulong)99_999)); + Assert.Equal((ulong)5, BinaryIntegerHelper.Log10((ulong)100_000)); + Assert.Equal((ulong)5, BinaryIntegerHelper.Log10((ulong)999_999)); + Assert.Equal((ulong)6, BinaryIntegerHelper.Log10((ulong)1_000_000)); + Assert.Equal((ulong)6, BinaryIntegerHelper.Log10((ulong)9_999_999)); + Assert.Equal((ulong)7, BinaryIntegerHelper.Log10((ulong)10_000_000)); + Assert.Equal((ulong)7, BinaryIntegerHelper.Log10((ulong)99_999_999)); + Assert.Equal((ulong)8, BinaryIntegerHelper.Log10((ulong)100_000_000)); + Assert.Equal((ulong)8, BinaryIntegerHelper.Log10((ulong)999_999_999)); + Assert.Equal((ulong)9, BinaryIntegerHelper.Log10((ulong)1_000_000_000)); + Assert.Equal((ulong)9, BinaryIntegerHelper.Log10((ulong)9_999_999_999)); + Assert.Equal((ulong)10, BinaryIntegerHelper.Log10((ulong)10_000_000_000)); + Assert.Equal((ulong)10, BinaryIntegerHelper.Log10((ulong)99_999_999_999)); + Assert.Equal((ulong)11, BinaryIntegerHelper.Log10((ulong)100_000_000_000)); + Assert.Equal((ulong)11, BinaryIntegerHelper.Log10((ulong)999_999_999_999)); + Assert.Equal((ulong)12, BinaryIntegerHelper.Log10((ulong)1_000_000_000_000)); + Assert.Equal((ulong)12, BinaryIntegerHelper.Log10((ulong)9_999_999_999_999)); + Assert.Equal((ulong)13, BinaryIntegerHelper.Log10((ulong)10_000_000_000_000)); + Assert.Equal((ulong)13, BinaryIntegerHelper.Log10((ulong)99_999_999_999_999)); + Assert.Equal((ulong)14, BinaryIntegerHelper.Log10((ulong)100_000_000_000_000)); + Assert.Equal((ulong)14, BinaryIntegerHelper.Log10((ulong)999_999_999_999_999)); + Assert.Equal((ulong)15, BinaryIntegerHelper.Log10((ulong)1_000_000_000_000_000)); + Assert.Equal((ulong)15, BinaryIntegerHelper.Log10((ulong)9_999_999_999_999_999)); + Assert.Equal((ulong)16, BinaryIntegerHelper.Log10((ulong)10_000_000_000_000_000)); + Assert.Equal((ulong)16, BinaryIntegerHelper.Log10((ulong)99_999_999_999_999_999)); + Assert.Equal((ulong)17, BinaryIntegerHelper.Log10((ulong)100_000_000_000_000_000)); + Assert.Equal((ulong)17, BinaryIntegerHelper.Log10((ulong)999_999_999_999_999_999)); + Assert.Equal((ulong)18, BinaryIntegerHelper.Log10((ulong)1_000_000_000_000_000_000)); + Assert.Equal((ulong)18, BinaryIntegerHelper.Log10((ulong)9_999_999_999_999_999_999)); + Assert.Equal((ulong)19, BinaryIntegerHelper.Log10((ulong)10_000_000_000_000_000_000)); + Assert.Equal((ulong)19, BinaryIntegerHelper.Log10((ulong)18_446_744_073_709_551_615)); + } + [Fact] public static void PopCountTest() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.GenericMath.cs index b67413444cbf80..4a3b6236ad1e99 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/UIntPtrTests.GenericMath.cs @@ -351,6 +351,33 @@ public static void LeadingZeroCountTest() } } + [Fact] + public static void Log10Test() + { + if (Environment.Is64BitProcess) + { + Assert.Equal(unchecked((nuint)0), BinaryIntegerHelper.Log10(unchecked((nuint)0))); + Assert.Equal(unchecked((nuint)0), BinaryIntegerHelper.Log10(unchecked((nuint)1))); + Assert.Equal(unchecked((nuint)0), BinaryIntegerHelper.Log10(unchecked((nuint)9))); + Assert.Equal(unchecked((nuint)1), BinaryIntegerHelper.Log10(unchecked((nuint)10))); + Assert.Equal(unchecked((nuint)2), BinaryIntegerHelper.Log10(unchecked((nuint)100))); + Assert.Equal(unchecked((nuint)18), BinaryIntegerHelper.Log10(unchecked((nuint)9_223_372_036_854_775_807))); + Assert.Equal(unchecked((nuint)18), BinaryIntegerHelper.Log10(unchecked((nuint)9_223_372_036_854_775_808))); + Assert.Equal(unchecked((nuint)19), BinaryIntegerHelper.Log10(unchecked((nuint)18_446_744_073_709_551_615))); + } + else + { + Assert.Equal((nuint)0, BinaryIntegerHelper.Log10((nuint)0)); + Assert.Equal((nuint)0, BinaryIntegerHelper.Log10((nuint)1)); + Assert.Equal((nuint)0, BinaryIntegerHelper.Log10((nuint)9)); + Assert.Equal((nuint)1, BinaryIntegerHelper.Log10((nuint)10)); + Assert.Equal((nuint)2, BinaryIntegerHelper.Log10((nuint)100)); + Assert.Equal((nuint)9, BinaryIntegerHelper.Log10((nuint)2_147_483_647)); + Assert.Equal((nuint)9, BinaryIntegerHelper.Log10((nuint)2_147_483_648)); + Assert.Equal((nuint)9, BinaryIntegerHelper.Log10((nuint)4_294_967_295)); + } + } + [Fact] public static void PopCountTest() {