Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/MissingValues/Int256.Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,34 @@ public static explicit operator decimal(in Int256 value)
}
return (decimal)(double)(UInt256)(value);
}

#if NET11_0_OR_GREATER
/// <summary>
/// Explicitly converts a <see cref="Int256" /> value to a <see cref="Decimal32"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal32(in Int256 value)
{
return BitHelper.ConvertToDecimalN<Decimal32, Int256>(in value);
}
/// <summary>
/// Explicitly converts a <see cref="Int256" /> value to a <see cref="Decimal64"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal64(in Int256 value)
{
return BitHelper.ConvertToDecimalN<Decimal64, Int256>(in value);
}
/// <summary>
/// Explicitly converts a <see cref="Int256" /> value to a <see cref="Decimal128"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal128(in Int256 value)
{
return BitHelper.ConvertToDecimalN<Decimal128, Int256>(in value);
}
#endif

/// <summary>
/// Explicitly converts a <see cref="Int256" /> value to a <see cref="Octo"/>.
/// </summary>
Expand Down Expand Up @@ -872,6 +900,63 @@ public static explicit operator checked Int256(BigInteger value)
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int256"/>.</exception>
public static explicit operator checked Int256(decimal value) => checked((Int256)(double)value);

#if NET11_0_OR_GREATER
/// <summary>
/// Explicitly converts a <see cref="Decimal32" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int256(Decimal32 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal32>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal32" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int256"/>.</exception>
public static explicit operator checked Int256(Decimal32 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal32>(value, true);
}

/// <summary>
/// Explicitly converts a <see cref="Decimal64" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int256(Decimal64 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal64>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal64" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int256"/>.</exception>
public static explicit operator checked Int256(Decimal64 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal64>(value, true);
}

/// <summary>
/// Explicitly converts a <see cref="Decimal128" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int256(Decimal128 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal128>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal128" /> value to a <see cref="Int256"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int256"/>.</exception>
public static explicit operator checked Int256(Decimal128 value)
{
return BitHelper.ConvertFromDecimalN<Int256, Decimal128>(value, true);
}
#endif

/// <summary>
/// Explicitly converts a <see cref="double" /> value to a <see cref="Int256"/>.
/// </summary>
Expand Down
85 changes: 85 additions & 0 deletions src/MissingValues/Int512.Conversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,34 @@ public static explicit operator decimal(in Int512 value)
}
return (decimal)(UInt512)(value);
}

#if NET11_0_OR_GREATER
/// <summary>
/// Explicitly converts a <see cref="Int512" /> value to a <see cref="Decimal32"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal32(in Int512 value)
{
return BitHelper.ConvertToDecimalN<Decimal32, Int512>(in value);
}
/// <summary>
/// Explicitly converts a <see cref="Int512" /> value to a <see cref="Decimal64"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal64(in Int512 value)
{
return BitHelper.ConvertToDecimalN<Decimal64, Int512>(in value);
}
/// <summary>
/// Explicitly converts a <see cref="Int512" /> value to a <see cref="Decimal128"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Decimal128(in Int512 value)
{
return BitHelper.ConvertToDecimalN<Decimal128, Int512>(in value);
}
#endif

/// <summary>
/// Explicitly converts a <see cref="Int512" /> value to a <see cref="Octo"/>.
/// </summary>
Expand Down Expand Up @@ -894,6 +922,63 @@ public static explicit operator checked Int512(BigInteger value)
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int512"/>.</exception>
public static explicit operator checked Int512(decimal value) => checked((Int512)(double)value);

#if NET11_0_OR_GREATER
/// <summary>
/// Explicitly converts a <see cref="Decimal32" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int512(Decimal32 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal32>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal32" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int512"/>.</exception>
public static explicit operator checked Int512(Decimal32 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal32>(value, true);
}

/// <summary>
/// Explicitly converts a <see cref="Decimal64" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int512(Decimal64 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal64>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal64" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int512"/>.</exception>
public static explicit operator checked Int512(Decimal64 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal64>(value, true);
}

/// <summary>
/// Explicitly converts a <see cref="Decimal128" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static explicit operator Int512(Decimal128 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal128>(value);
}
/// <summary>
/// Explicitly converts a <see cref="Decimal128" /> value to a <see cref="Int512"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
/// <exception cref="OverflowException"><paramref name="value"/> is outside the range of <see cref="Int512"/>.</exception>
public static explicit operator checked Int512(Decimal128 value)
{
return BitHelper.ConvertFromDecimalN<Int512, Decimal128>(value, true);
}
#endif

/// <summary>
/// Explicitly converts a <see cref="double" /> value to a <see cref="Int512"/>.
/// </summary>
Expand Down
138 changes: 137 additions & 1 deletion src/MissingValues/Internals/BitHelper.Ieee.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Buffers.Binary;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using MissingValues.Primitives;
Expand Down Expand Up @@ -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>(T value, out int exponent, out UInt512 significand)
where T : IDecimalFloatingPointIeee754<T>
{
Span<byte> exponentBuffer = stackalloc byte[8];
Span<byte> 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<TInteger, TDecimal>(TDecimal value, bool isChecked = false)
where TInteger : IBigInteger<TInteger>, IMinMaxValue<TInteger>
where TDecimal : IDecimalFloatingPointIeee754<TDecimal>
{
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<TDecimal, TInteger>(in TInteger value)
where TDecimal : IDecimalFloatingPointIeee754<TDecimal>
where TInteger : IBigInteger<TInteger>, IMinMaxValue<TInteger>
{
throw new NotImplementedException();
}
#endif

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static UInt128 AddQuadBits(UInt128 uiA, UInt128 uiB, bool signZ)
{
Expand Down
Loading