diff --git a/src/MissingValues/Int256.Conversions.cs b/src/MissingValues/Int256.Conversions.cs index f995ed7..609f8a8 100644 --- a/src/MissingValues/Int256.Conversions.cs +++ b/src/MissingValues/Int256.Conversions.cs @@ -77,6 +77,11 @@ private static bool TryConvertFromChecked(TOther value, out Int256 resul float actual => (Int256)actual, double actual => (Int256)actual, NFloat actual => (Int256)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (Int256)actual, + Decimal64 actual => (Int256)actual, + Decimal128 actual => (Int256)actual, +#endif decimal actual => (Int256)actual, byte actual => (Int256)actual, ushort actual => (Int256)actual, @@ -112,10 +117,16 @@ private static bool TryConvertFromSaturating(TOther value, out Int256 re result = value switch { char actual => actual, - Half actual => (Int256)actual, - float actual => (Int256)actual, + Half actual => (Half.IsPositiveInfinity(actual)) ? MaxValue : (Half.IsNegativeInfinity(actual)) ? MinValue : (Int256)actual, + float actual => (float.IsPositiveInfinity(actual)) ? MaxValue : (float.IsNegativeInfinity(actual)) ? MinValue : (Int256)actual, double actual => (actual <= -TwoPow255) ? MinValue : (actual > +TwoPow255) ? MaxValue : (Int256)actual, NFloat actual => (actual <= -TwoPow255) ? MinValue : (actual > +TwoPow255) ? MaxValue : (Int256)actual, +#if NET11_0_OR_GREATER + // 2^255 in Binary Encoding + Decimal32 actual => (actual <= Decimal32.DecodeBinary(0xD5D8_57A4)) ? MinValue : (actual > Decimal32.DecodeBinary(0x55D8_57A4)) ? MaxValue : (Int256)actual, + Decimal64 actual => (actual <= Decimal64.DecodeBinary(0xB974_919D_5556_EB52)) ? MinValue : (actual > Decimal64.DecodeBinary(0x3974_919D_5556_EB52)) ? MaxValue : (Int256)actual, + Decimal128 actual => (actual <= Decimal128.DecodeBinary(new UInt128(0xB097_1D73_14F5_34B6, 0x09C6_EFE6_C11D_255B))) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3097_1D73_14F5_34B6, 0x09C6_EFE6_C11D_255B))) ? MaxValue : (Int256)actual, +#endif decimal actual => (Int256)actual, byte actual => (Int256)actual, ushort actual => (Int256)actual, @@ -152,6 +163,12 @@ private static bool TryConvertFromTruncating(TOther value, out Int256 re float actual => (float.IsPositiveInfinity(actual)) ? MaxValue : (float.IsNegativeInfinity(actual)) ? MinValue : (Int256)actual, double actual => (actual <= -TwoPow255) ? MinValue : (actual > +TwoPow255) ? MaxValue : (Int256)actual, NFloat actual => (actual <= -TwoPow255) ? MinValue : (actual > +TwoPow255) ? MaxValue : (Int256)actual, +#if NET11_0_OR_GREATER + // 2^255 in Binary Encoding + Decimal32 actual => (actual <= Decimal32.DecodeBinary(0xD5D8_57A4)) ? MinValue : (actual > Decimal32.DecodeBinary(0x55D8_57A4)) ? MaxValue : (Int256)actual, + Decimal64 actual => (actual <= Decimal64.DecodeBinary(0xB974_919D_5556_EB52)) ? MinValue : (actual > Decimal64.DecodeBinary(0x3974_919D_5556_EB52)) ? MaxValue : (Int256)actual, + Decimal128 actual => (actual <= Decimal128.DecodeBinary(new UInt128(0xB097_1D73_14F5_34B6, 0x09C6_EFE6_C11D_255B))) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3097_1D73_14F5_34B6, 0x09C6_EFE6_C11D_255B))) ? MaxValue : (Int256)actual, +#endif decimal actual => (Int128)actual, byte actual => (Int256)actual, ushort actual => (Int256)actual, @@ -186,6 +203,11 @@ static bool INumberBase.TryConvertToChecked(Int256 value, out TO float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -223,6 +245,11 @@ static bool INumberBase.TryConvertToSaturating(Int256 value, out float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= (Int256)byte.MaxValue) ? byte.MaxValue : (value <= (Int256)byte.MinValue) ? byte.MinValue : (byte)value), ushort => (TOther)(object)((value >= (Int256)ushort.MaxValue) ? ushort.MaxValue : (value <= (Int256)ushort.MinValue) ? ushort.MinValue : (ushort)value), @@ -258,6 +285,11 @@ static bool INumberBase.TryConvertToTruncating(Int256 value, out float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -645,6 +677,34 @@ public static explicit operator decimal(in Int256 value) } return (decimal)(double)(UInt256)(value); } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(in Int256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(in Int256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(in Int256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } +#endif + /// /// Explicitly converts a value to a . /// @@ -872,6 +932,63 @@ public static explicit operator checked Int256(BigInteger value) /// The value to convert. /// is outside the range of . public static explicit operator checked Int256(decimal value) => checked((Int256)(double)value); + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int256(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int256(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int256(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int256(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int256(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int256(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } +#endif + /// /// Explicitly converts a value to a . /// diff --git a/src/MissingValues/Int512.Conversions.cs b/src/MissingValues/Int512.Conversions.cs index e24c830..4a5f4ad 100644 --- a/src/MissingValues/Int512.Conversions.cs +++ b/src/MissingValues/Int512.Conversions.cs @@ -78,6 +78,11 @@ private static bool TryConvertFromChecked(TOther value, out Int512 resul double actual => (Int512)actual, NFloat actual => (Int512)actual, Quad actual => (Int512)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (Int512)actual, + Decimal64 actual => (Int512)actual, + Decimal128 actual => (Int512)actual, +#endif decimal actual => (Int512)actual, byte actual => (Int512)actual, ushort actual => (Int512)actual, @@ -117,7 +122,12 @@ private static bool TryConvertFromSaturating(TOther value, out Int512 re float actual => (float.IsPositiveInfinity(actual)) ? MaxValue : (float.IsNegativeInfinity(actual)) ? MinValue : (Int512)actual, double actual => (actual <= -TwoPow511) ? MinValue : (actual > +TwoPow511) ? MaxValue : (Int512)actual, NFloat actual => (actual <= -TwoPow511) ? MinValue : (actual > +TwoPow511) ? MaxValue : (Int512)actual, - Quad actual => (actual <= (new Quad(0xC1FE_0000_0000_0000, 0x0000_0000_0000_0000))) ? MinValue : (actual > (new Quad(0x41FE_0000_0000_0000, 0x0000_0000_0000_0000))) ? MaxValue : (Int512)actual, +#if NET11_0_OR_GREATER + // 2^511 in Binary Encoding + Decimal32 actual => (Decimal32.IsPositiveInfinity(actual)) ? MaxValue : (Decimal32.IsNegativeInfinity(actual)) ? MinValue : (Int256)actual, + Decimal64 actual => (actual <= Decimal64.DecodeBinary(14057934741360918819)) ? MinValue : (actual > Decimal64.DecodeBinary(4834562704506143011)) ? MaxValue : (Int256)actual, + Decimal128 actual => (actual <= Decimal128.DecodeBinary(new UInt128(0xB131_4A87_29FC_3DDB, 0x71FD_852E_9D69_DCCB))) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3131_4A87_29FC_3DDB, 0x71FD_852E_9D69_DCCB))) ? MaxValue : (Int256)actual, +#endif decimal actual => (Int512)actual, byte actual => (Int512)actual, ushort actual => (Int512)actual, @@ -156,7 +166,12 @@ private static bool TryConvertFromTruncating(TOther value, out Int512 re float actual => (float.IsPositiveInfinity(actual)) ? MaxValue : (float.IsNegativeInfinity(actual)) ? MinValue : (Int512)actual, double actual => (actual <= -TwoPow511) ? MinValue : (actual > +TwoPow511) ? MaxValue : (Int512)actual, NFloat actual => (actual <= -TwoPow511) ? MinValue : (actual > +TwoPow511) ? MaxValue : (Int512)actual, - Quad actual => (actual <= (new Quad(0xC1FE_0000_0000_0000, 0x0000_0000_0000_0000))) ? MinValue : (actual > (new Quad(0x41FE_0000_0000_0000, 0x0000_0000_0000_0000))) ? MaxValue : (Int512)actual, +#if NET11_0_OR_GREATER + // 2^511 in Binary Encoding + Decimal32 actual => (Decimal32.IsPositiveInfinity(actual)) ? MaxValue : (Decimal32.IsNegativeInfinity(actual)) ? MinValue : (Int256)actual, + Decimal64 actual => (actual <= Decimal64.DecodeBinary(14057934741360918819)) ? MinValue : (actual > Decimal64.DecodeBinary(4834562704506143011)) ? MaxValue : (Int256)actual, + Decimal128 actual => (actual <= Decimal128.DecodeBinary(new UInt128(0xB131_4A87_29FC_3DDB, 0x71FD_852E_9D69_DCCB))) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3131_4A87_29FC_3DDB, 0x71FD_852E_9D69_DCCB))) ? MaxValue : (Int256)actual, +#endif decimal actual => (Int512)actual, byte actual => (Int512)actual, ushort actual => (Int512)actual, @@ -195,6 +210,11 @@ static bool INumberBase.TryConvertToChecked(Int512 value, out TO double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)(Quad)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -233,6 +253,11 @@ static bool INumberBase.TryConvertToSaturating(Int512 value, out double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)(Quad)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= (Int512)byte.MaxValue) ? byte.MaxValue : (value <= (Int512)byte.MinValue) ? byte.MinValue : (byte)value), ushort => (TOther)(object)((value >= (Int512)ushort.MaxValue) ? ushort.MaxValue : (value <= (Int512)ushort.MinValue) ? ushort.MinValue : (ushort)value), @@ -269,6 +294,11 @@ static bool INumberBase.TryConvertToTruncating(Int512 value, out double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)(Quad)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -658,6 +688,34 @@ public static explicit operator decimal(in Int512 value) } return (decimal)(UInt512)(value); } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(in Int512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(in Int512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(in Int512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } +#endif + /// /// Explicitly converts a value to a . /// @@ -894,6 +952,63 @@ public static explicit operator checked Int512(BigInteger value) /// The value to convert. /// is outside the range of . public static explicit operator checked Int512(decimal value) => checked((Int512)(double)value); + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int512(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int512(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int512(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int512(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Int512(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked Int512(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } +#endif + /// /// Explicitly converts a value to a . /// diff --git a/src/MissingValues/Internals/BitHelper.Ieee.cs b/src/MissingValues/Internals/BitHelper.Ieee.cs index a4eda28..79dd4c4 100644 --- a/src/MissingValues/Internals/BitHelper.Ieee.cs +++ b/src/MissingValues/Internals/BitHelper.Ieee.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System.Buffers.Binary; +using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; using MissingValues.Primitives; @@ -767,6 +768,141 @@ internal static void FastFloor(in Quad x, out Quad ai, out Quad ar) ar = x - ai; } +#if NET11_0_OR_GREATER + private static void GetExponentAndSignificand(T value, out int exponent, out UInt512 significand) + where T : IDecimalFloatingPointIeee754 + { + Span exponentBuffer = stackalloc byte[8]; + Span significandBuffer = stackalloc byte[64]; + + value.TryWriteExponentLittleEndian(exponentBuffer, out int written); + Debug.Assert(written <= 8); + value.TryWriteSignificandLittleEndian(significandBuffer, out written); + Debug.Assert(written <= 64); + + exponent = BinaryPrimitives.ReadInt32LittleEndian(exponentBuffer); + significand = BinaryOperations.ReadUInt512LittleEndian(significandBuffer); + } + + internal static TInteger ConvertFromDecimalN(TDecimal value, bool isChecked = false) + where TInteger : IBigInteger, IMinMaxValue + where TDecimal : IDecimalFloatingPointIeee754 + { + if (TDecimal.IsNaN(value)) + { + if (isChecked) + { + Thrower.IntegerOverflow(); + } + return TInteger.Zero; + } + + bool isNegative = TDecimal.IsNegative(value); + + if (TDecimal.IsInfinity(value)) + { + if (isChecked) + { + Thrower.IntegerOverflow(); + } + return isNegative ? TInteger.MinValue : TInteger.MaxValue; + } + + GetExponentAndSignificand(value, out var exponent, out var significand); + + if (significand == UInt512.Zero) + { + return TInteger.Zero; + } + + UInt512 magnitude; + bool exceedsUInt512 = false; + if (exponent >= 0) + { + // magnitude = significand * 10^exponent. UInt512 holds at most 155 digits, so any exponent that + // would push the product past that bound overflows every integer type and saturates/throws. + UInt512 maxValueBy10 = UInt512.MaxValue / 10; + for (int i = 0; i < exponent && !exceedsUInt512; i++) + { + if (significand > maxValueBy10) + { + exceedsUInt512 = true; + break; + } + significand *= 10; + } + + magnitude = exceedsUInt512 ? UInt512.Zero : significand; + } + else + { + // magnitude = significand / 10^(-exponent), truncated toward zero. Once the divisor has more + // digits than the significand the quotient is zero. + int drop = -exponent; + + for (int i = 0; i < drop && significand != UInt512.Zero; i++) + { + significand /= 10; + } + + magnitude = significand; + } + + bool isUnsigned = TInteger.IsZero(TInteger.MinValue); + UInt512 maxMagnitude = UInt512.CreateTruncating(TInteger.MaxValue); + + UInt512 minMagnitude = isUnsigned ? UInt512.Zero : maxMagnitude + UInt512.One; + + if (!isNegative) + { + if (exceedsUInt512 || (magnitude > maxMagnitude)) + { + if (isChecked) + { + Thrower.IntegerOverflow(); + } + return TInteger.MaxValue; + } + + return TInteger.CreateTruncating(magnitude); + } + + // Negative magnitude. + if (isUnsigned) + { + if (isChecked && (magnitude != UInt512.Zero)) + { + Thrower.IntegerOverflow(); + } + return TInteger.Zero; + } + + if (exceedsUInt512 || (magnitude > minMagnitude)) + { + if (isChecked) + { + Thrower.IntegerOverflow(); + } + return TInteger.MinValue; + } + + if (magnitude == minMagnitude) + { + return TInteger.MinValue; + } + + return TInteger.Zero - TInteger.CreateTruncating(magnitude); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static TDecimal ConvertToDecimalN(in TInteger value) + where TDecimal : IDecimalFloatingPointIeee754 + where TInteger : IBigInteger, IMinMaxValue + { + throw new NotImplementedException(); + } +#endif + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static UInt128 AddQuadBits(UInt128 uiA, UInt128 uiB, bool signZ) { diff --git a/src/MissingValues/Octo.Conversions.cs b/src/MissingValues/Octo.Conversions.cs index b9fed8d..b74c4b8 100644 --- a/src/MissingValues/Octo.Conversions.cs +++ b/src/MissingValues/Octo.Conversions.cs @@ -80,6 +80,11 @@ private static bool TryConvertFrom(TOther value, out Octo result) NFloat actual => (Octo)actual, Quad actual => (Octo)actual, Octo actual => actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (Octo)actual, + Decimal64 actual => (Octo)actual, + Decimal128 actual => (Octo)actual, +#endif decimal actual => (Octo)actual, byte actual => (Octo)actual, ushort actual => (Octo)actual, @@ -118,6 +123,11 @@ static bool INumberBase.TryConvertToChecked(Octo value, out TOther NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)(Quad)value, Octo => (TOther)(object)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -160,6 +170,11 @@ private static bool TryConvertTo(Octo value, out TOther result) NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)(Quad)value, Octo => (TOther)(object)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= byte.MaxValue) ? byte.MaxValue : (value <= Octo.Zero) ? byte.MinValue : (byte)value), ushort => (TOther)(object)((value >= ushort.MaxValue) ? ushort.MaxValue : (value <= Octo.Zero) ? ushort.MinValue : (ushort)value), @@ -1310,6 +1325,33 @@ public static explicit operator decimal(in Octo value) { return (decimal)(double)value; } +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(in Octo value) + { + return (Decimal128)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(in Octo value) + { + return (Decimal64)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(in Octo value) + { + return (Decimal32)(double)value; + } +#endif + /// /// Explicitly converts a value to a . /// @@ -1686,6 +1728,33 @@ public static implicit operator Octo(decimal value) { return (Octo)(double)value; } +#if NET11_0_OR_GREATER + /// + /// Implicitly converts a value to a . + /// + /// The value to convert. + public static implicit operator Octo(Decimal128 value) + { + return (Octo)(double)value; + } + /// + /// Implicitly converts a value to a . + /// + /// The value to convert. + public static implicit operator Octo(Decimal64 value) + { + return (Octo)(double)value; + } + /// + /// Implicitly converts a value to a . + /// + /// The value to convert. + public static implicit operator Octo(Decimal32 value) + { + return (Octo)(double)value; + } +#endif + /// /// Implicitly converts a value to a . /// diff --git a/src/MissingValues/Quad.Conversions.cs b/src/MissingValues/Quad.Conversions.cs index 5d8f022..da610c9 100644 --- a/src/MissingValues/Quad.Conversions.cs +++ b/src/MissingValues/Quad.Conversions.cs @@ -81,6 +81,11 @@ private static bool TryConvertFrom(TOther value, out Quad result) double actual => (Quad)actual, NFloat actual => (Quad)actual, Quad actual => actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (Quad)actual, + Decimal64 actual => (Quad)actual, + Decimal128 actual => (Quad)actual, +#endif decimal actual => (Quad)actual, byte actual => (Quad)actual, ushort actual => (Quad)actual, @@ -119,6 +124,11 @@ static bool INumberBase.TryConvertToChecked(Quad value, out TOther NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)value, Octo => (TOther)(object)(Octo)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -161,6 +171,11 @@ private static bool TryConvertTo(Quad value, out TOther result) NFloat => (TOther)(object)(NFloat)value, Quad => (TOther)(object)value, Octo => (TOther)(object)(Octo)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= byte.MaxValue) ? byte.MaxValue : (value <= Quad.Zero) ? byte.MinValue : (byte)value), ushort => (TOther)(object)((value >= ushort.MaxValue) ? ushort.MaxValue : (value <= Quad.Zero) ? ushort.MinValue : (ushort)value), @@ -1330,6 +1345,33 @@ public static explicit operator decimal(Quad value) { return (decimal)(double)value; } +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(Quad value) + { + return (Decimal128)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(Quad value) + { + return (Decimal64)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(Quad value) + { + return (Decimal32)(double)value; + } +#endif + /// /// Implicitly converts a value to a . /// @@ -1703,6 +1745,33 @@ public static explicit operator Quad(decimal value) { return (Quad)(double)value; } +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Quad(Decimal128 value) + { + return (Quad)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Quad(Decimal64 value) + { + return (Quad)(double)value; + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Quad(Decimal32 value) + { + return (Quad)(double)value; + } +#endif + /// /// Implicitly converts a value to a . /// diff --git a/src/MissingValues/UInt256.Conversions.cs b/src/MissingValues/UInt256.Conversions.cs index f3fcec0..079acd4 100644 --- a/src/MissingValues/UInt256.Conversions.cs +++ b/src/MissingValues/UInt256.Conversions.cs @@ -77,6 +77,11 @@ private static bool TryConvertFromChecked(TOther value, out UInt256 resu Half actual => (UInt256)actual, float actual => (UInt256)actual, double actual => (UInt256)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (UInt256)actual, + Decimal64 actual => (UInt256)actual, + Decimal128 actual => (UInt256)actual, +#endif decimal actual => (UInt256)actual, byte actual => (UInt256)actual, ushort actual => (UInt256)actual, @@ -119,6 +124,11 @@ private static bool TryConvertFromSaturating(TOther value, out UInt256 r Half actual => (actual < Half.Zero) ? MinValue : (UInt256)actual, float actual => (actual < 0) ? MinValue : (UInt256)actual, double actual => (actual < 0) ? MinValue : (actual > TwoPow256) ? MaxValue : (UInt256)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (actual < Decimal32.Zero) ? MinValue : (actual > Decimal32.DecodeBinary(1443998497)) ? MaxValue : (UInt256)actual, + Decimal64 actual => (actual < Decimal64.Zero) ? MinValue : (actual > Decimal64.DecodeBinary(4144469578073229482)) ? MaxValue : (UInt256)actual, + Decimal128 actual => (actual < Decimal128.Zero) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3098_3917_0431_0A8A, 0xCEC1_632E_269F_6DDF))) ? MaxValue : (UInt256)actual, +#endif decimal actual => (actual < 0) ? MinValue : (UInt128)actual, byte actual => actual, ushort actual => actual, @@ -154,6 +164,11 @@ private static bool TryConvertFromTruncating(TOther value, out UInt256 r Half actual => (actual < Half.Zero) ? MinValue : (UInt256)actual, float actual => (actual < 0) ? MinValue : (UInt256)actual, double actual => (actual < 0) ? MinValue : (UInt256)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (actual < Decimal32.Zero) ? MinValue : (actual > Decimal32.DecodeBinary(1443998497)) ? MaxValue : (UInt256)actual, + Decimal64 actual => (actual < Decimal64.Zero) ? MinValue : (actual > Decimal64.DecodeBinary(4144469578073229482)) ? MaxValue : (UInt256)actual, + Decimal128 actual => (actual < Decimal128.Zero) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3098_3917_0431_0A8A, 0xCEC1_632E_269F_6DDF))) ? MaxValue : (UInt256)actual, +#endif decimal actual => (actual < 0) ? MinValue : (UInt256)actual, byte actual => actual, ushort actual => actual, @@ -190,6 +205,11 @@ static bool INumberBase.TryConvertToChecked(UInt256 value, out Half => (TOther)(object)(Half)value, float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -226,6 +246,11 @@ static bool INumberBase.TryConvertToSaturating(UInt256 value, o Half => (TOther)(object)(Half)value, float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= 0xFF) ? byte.MaxValue : (byte)value), ushort => (TOther)(object)((value >= 0xFFFF) ? ushort.MaxValue : (ushort)value), @@ -271,6 +296,11 @@ static bool INumberBase.TryConvertToTruncating(UInt256 value, o float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, NFloat => (TOther)(object)(NFloat)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -604,6 +634,34 @@ public static explicit operator decimal(in UInt256 value) return (decimal)value.Lower; } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(in UInt256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(in UInt256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(in UInt256 value) + { + return BitHelper.ConvertToDecimalN(in value); + } +#endif + /// /// Explicitly converts a value to a . /// @@ -781,6 +839,63 @@ public static explicit operator checked UInt256(double value) return ToUInt256(value); } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt256(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt256(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt256(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt256(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt256(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt256(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } +#endif + /// /// Explicitly converts a value to a . /// diff --git a/src/MissingValues/UInt512.Conversions.cs b/src/MissingValues/UInt512.Conversions.cs index e571c7f..952d7f9 100644 --- a/src/MissingValues/UInt512.Conversions.cs +++ b/src/MissingValues/UInt512.Conversions.cs @@ -76,7 +76,11 @@ private static bool TryConvertFromChecked(TOther value, out UInt512 resu Half actual => (UInt512)actual, float actual => (UInt512)actual, double actual => (UInt512)actual, - Quad actual => (UInt512)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (UInt256)actual, + Decimal64 actual => (UInt256)actual, + Decimal128 actual => (UInt256)actual, +#endif decimal actual => (UInt512)actual, byte actual => (UInt512)actual, ushort actual => (UInt512)actual, @@ -119,6 +123,11 @@ private static bool TryConvertFromSaturating(TOther value, out UInt512 r float actual => (actual < 0) ? MinValue : (UInt512)actual, double actual => (actual < 0) ? MinValue : (actual > TwoPow512) ? MaxValue : (UInt512)actual, Quad actual => (actual >= new Quad(0x41FF_0000_0000_0000, 0x0000_0000_0000_0000)) ? UInt512.MaxValue : (actual <= Quad.Zero) ? UInt512.MinValue : (UInt512)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (actual < Decimal32.Zero) ? MinValue : Decimal32.IsPositiveInfinity(actual) ? MaxValue : (UInt256)actual, + Decimal64 actual => (actual < Decimal64.Zero) ? MinValue : (actual > Decimal64.DecodeBinary(4838206780588906964)) ? MaxValue : (UInt256)actual, + Decimal128 actual => (actual < Decimal128.Zero) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3132_421B_0865_A5F8, 0xB065_E76F_B915_2C29))) ? MaxValue : (UInt256)actual, +#endif decimal actual => (actual < 0) ? MinValue : (UInt512)actual, byte actual => actual, ushort actual => actual, @@ -155,6 +164,11 @@ private static bool TryConvertFromTruncating(TOther value, out UInt512 r float actual => (actual < 0) ? MinValue : (UInt512)actual, double actual => (actual < 0) ? MinValue : (UInt512)actual, NFloat actual => (actual < 0) ? MinValue : (UInt512)actual, +#if NET11_0_OR_GREATER + Decimal32 actual => (actual < Decimal32.Zero) ? MinValue : Decimal32.IsPositiveInfinity(actual) ? MaxValue : (UInt256)actual, + Decimal64 actual => (actual < Decimal64.Zero) ? MinValue : (actual > Decimal64.DecodeBinary(4838206780588906964)) ? MaxValue : (UInt256)actual, + Decimal128 actual => (actual < Decimal128.Zero) ? MinValue : (actual > Decimal128.DecodeBinary(new UInt128(0x3132_421B_0865_A5F8, 0xB065_E76F_B915_2C29))) ? MaxValue : (UInt256)actual, +#endif decimal actual => (actual < 0) ? MinValue : (UInt512)actual, byte actual => actual, ushort actual => actual, @@ -192,6 +206,11 @@ static bool INumberBase.TryConvertToChecked(UInt512 value, out Half => (TOther)(object)(Half)value, float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -228,6 +247,11 @@ static bool INumberBase.TryConvertToSaturating(UInt512 value, o Half => (TOther)(object)(Half)value, float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)((value >= 0xFF) ? byte.MaxValue : (byte)value), ushort => (TOther)(object)((value >= 0xFFFF) ? ushort.MaxValue : (ushort)value), @@ -273,6 +297,11 @@ static bool INumberBase.TryConvertToTruncating(UInt512 value, o Half => (TOther)(object)(Half)value, float => (TOther)(object)(float)value, double => (TOther)(object)(double)value, +#if NET11_0_OR_GREATER + Decimal32 => (TOther)(object)(Decimal32)value, + Decimal64 => (TOther)(object)(Decimal64)value, + Decimal128 => (TOther)(object)(Decimal128)value, +#endif decimal => (TOther)(object)(decimal)value, byte => (TOther)(object)(byte)value, ushort => (TOther)(object)(ushort)value, @@ -618,6 +647,34 @@ public static explicit operator decimal(in UInt512 value) return (decimal)value.Lower; } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal32(in UInt512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal64(in UInt512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator Decimal128(in UInt512 value) + { + return BitHelper.ConvertToDecimalN(in value); + } +#endif + /// /// Explicitly converts a value to a . /// @@ -1104,6 +1161,63 @@ public static explicit operator checked UInt512(double value) return ToUInt512(value); } + +#if NET11_0_OR_GREATER + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt512(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt512(Decimal32 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt512(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt512(Decimal64 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } + + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + public static explicit operator UInt512(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value); + } + /// + /// Explicitly converts a value to a . + /// + /// The value to convert. + /// is outside the range of . + public static explicit operator checked UInt512(Decimal128 value) + { + return BitHelper.ConvertFromDecimalN(value, true); + } +#endif + /// /// Explicitly converts a value to a . /// diff --git a/tests/MissingValues.Tests/Extensions/OctoExtensions.cs b/tests/MissingValues.Tests/Extensions/OctoExtensions.cs index fa7c327..2990d86 100644 --- a/tests/MissingValues.Tests/Extensions/OctoExtensions.cs +++ b/tests/MissingValues.Tests/Extensions/OctoExtensions.cs @@ -65,6 +65,13 @@ public static class OctoExtensions public static Octo NFloatMinValue => NFloat.Size == 8 ? Octo.DoubleMinValue : Octo.SingleMinValue; public static Octo QuadMaxValue => Values.CreateFloat(0x43FF_EFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF, 0xF000_0000_0000_0000, 0x0000_0000_0000_0000); public static Octo QuadMinValue => Values.CreateFloat(0xC3FF_EFFF_FFFF_FFFF, 0xFFFF_FFFF_FFFF_FFFF, 0xF000_0000_0000_0000, 0x0000_0000_0000_0000); + + public static Octo Decimal32MaxValue => Values.CreateFloat(0x4017_65C0_1040_09E0, 0x12E0_0300_08A0_0380, 0x1AED_6792_CCAD_29A9, 0xD27D_9160_3B50_BF5D); + public static Octo Decimal32MinValue => Values.CreateFloat(0xC017_65C0_1040_09E0, 0x12E0_0300_08A0_0380, 0x1AED_6792_CCAD_29A9, 0xD27D_9160_3B50_BF5D); + public static Octo Decimal64MaxValue => Values.CreateFloat(0x404F_DEBE_EB7A_9B56, 0xD9B6_0E91_DC03_AB30, 0xAFC7_EA72_4341_EA33, 0x2994_DBDE_1B58_8CA4); + public static Octo Decimal64MinValue => Values.CreateFloat(0xC04F_DEBE_EB7A_9B56, 0xD9B6_0E91_DC03_AB30, 0xAFC7_EA72_4341_EA33, 0x2994_DBDE_1B58_8CA4); + public static Octo Decimal128MaxValue => Values.CreateFloat(0x44FF_4300_0080_3A00, 0x1200_2900_0880_6B80, 0x4490_2FF5_3A96_BC5, 0xC2D6A_4594_3117_1A7); + public static Octo Decimal128MinValue => Values.CreateFloat(0xC4FF_4300_0080_3A00, 0x1200_2900_0880_6B80, 0x4490_2FF5_3A96_BC5, 0xC2D6A_4594_3117_1A7); public static Octo Delta => Values.CreateFloat(0x400E_B000_0000_0000, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000); } diff --git a/tests/MissingValues.Tests/Extensions/QuadExtensions.cs b/tests/MissingValues.Tests/Extensions/QuadExtensions.cs index bc46840..9b0047f 100644 --- a/tests/MissingValues.Tests/Extensions/QuadExtensions.cs +++ b/tests/MissingValues.Tests/Extensions/QuadExtensions.cs @@ -64,6 +64,11 @@ public static class QuadExtensions public static Quad DoubleMinValue => Values.CreateFloat(0xC3FE_FFFF_FFFF_FFFF, 0xF000_0000_0000_0000); public static Quad NFloatMaxValue => NFloat.Size == 8 ? Quad.DoubleMaxValue : Quad.SingleMaxValue; public static Quad NFloatMinValue => NFloat.Size == 8 ? Quad.DoubleMinValue : Quad.SingleMinValue; + + public static Quad Decimal32MaxValue => Values.CreateFloat(0x4141_2BA0_93E5_C611, 0x4735_DACF_2599_5A53); + public static Quad Decimal32MinValue => Values.CreateFloat(0xC141_2BA0_93E5_C611, 0x4735_DACF_2599_5A53); + public static Quad Decimal64MaxValue => Values.CreateFloat(0x44FD_EBEE_B7A9_B56D, 0x9B60_E91D_C03A_B30B); + public static Quad Decimal64MinValue => Values.CreateFloat(0xC4FD_EBEE_B7A9_B56D, 0x9B60_E91D_C03A_B30B); public static Quad Delta => Values.CreateFloat(0x406F_0000_0000_0000, 0x0000_0000_0000_0000); }