Skip to content
Merged
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
252 changes: 238 additions & 14 deletions src/libraries/System.Private.CoreLib/src/System/Number.DecimalIeee754.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers.Binary;
using System.Buffers.Text;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
Expand All @@ -12,7 +13,7 @@ public readonly struct Decimal128
: IComparable,
IComparable<Decimal128>,
IEquatable<Decimal128>,
INumberBase<Decimal128>,
IFloatingPoint<Decimal128>,
ISpanFormattable,
ISpanParsable<Decimal128>,
IMinMaxValue<Decimal128>,
Expand Down Expand Up @@ -338,6 +339,16 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringS
return new Decimal128(result);
}

/// <summary>Divides two values together to compute their remainder.</summary>
/// <param name="left">The value which <paramref name="right" /> divides.</param>
/// <param name="right">The value which divides <paramref name="left" />.</param>
/// <returns>The remainder of <paramref name="left" /> divided by <paramref name="right" />.</returns>
public static Decimal128 operator %(Decimal128 left, Decimal128 right)
{
UInt128 result = Number.RemainderDecimalIeee754<Decimal128, UInt128>(new UInt128(left._upper, left._lower), new UInt128(right._upper, right._lower));
return new Decimal128(result);
}

//
// Explicit conversions to Decimal128
//
Expand Down Expand Up @@ -732,6 +743,115 @@ public static Decimal128 Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style =
/// <summary>Gets the mathematical constant <c>tau</c>.</summary>
public static Decimal128 Tau => new Decimal128(TauValue);

//
// IFloatingPoint
//

/// <inheritdoc cref="IFloatingPoint{TSelf}.Ceiling(TSelf)" />
public static Decimal128 Ceiling(Decimal128 x) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), 0, MidpointRounding.ToPositiveInfinity));

/// <inheritdoc cref="IFloatingPoint{TSelf}.ConvertToInteger{TInteger}(TSelf)" />
public static TInteger ConvertToInteger<TInteger>(Decimal128 value)
where TInteger : IBinaryInteger<TInteger> => TInteger.CreateSaturating(value);

/// <inheritdoc cref="IFloatingPoint{TSelf}.ConvertToIntegerNative{TInteger}(TSelf)" />
public static TInteger ConvertToIntegerNative<TInteger>(Decimal128 value)
where TInteger : IBinaryInteger<TInteger> => TInteger.CreateSaturating(value);

/// <inheritdoc cref="IFloatingPoint{TSelf}.Floor(TSelf)" />
public static Decimal128 Floor(Decimal128 x) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), 0, MidpointRounding.ToNegativeInfinity));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf)" />
public static Decimal128 Round(Decimal128 x) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), 0, MidpointRounding.ToEven));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int)" />
public static Decimal128 Round(Decimal128 x, int digits) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), digits, MidpointRounding.ToEven));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, MidpointRounding)" />
public static Decimal128 Round(Decimal128 x, MidpointRounding mode) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), 0, mode));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int, MidpointRounding)" />
public static Decimal128 Round(Decimal128 x, int digits, MidpointRounding mode) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), digits, mode));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Truncate(TSelf)" />
public static Decimal128 Truncate(Decimal128 x) => new Decimal128(Number.RoundDecimalIeee754<Decimal128, UInt128>(new UInt128(x._upper, x._lower), 0, MidpointRounding.ToZero));

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentByteCount()" />
int IFloatingPoint<Decimal128>.GetExponentByteCount() => sizeof(int);

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentShortestBitLength()" />
int IFloatingPoint<Decimal128>.GetExponentShortestBitLength()
{
int exponent = Number.UnpackDecimalIeee754<Decimal128, UInt128>(new UInt128(_upper, _lower)).UnbiasedExponent;

if (exponent >= 0)
{
return (sizeof(int) * 8) - int.LeadingZeroCount(exponent);
}
else
{
return (sizeof(int) * 8) + 1 - int.LeadingZeroCount(~exponent);
}
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetSignificandBitLength()" />
int IFloatingPoint<Decimal128>.GetSignificandBitLength() => 113;

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetSignificandByteCount()" />
int IFloatingPoint<Decimal128>.GetSignificandByteCount() => Unsafe.SizeOf<UInt128>();

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteExponentBigEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal128>.TryWriteExponentBigEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteInt32BigEndian(destination, Number.UnpackDecimalIeee754<Decimal128, UInt128>(new UInt128(_upper, _lower)).UnbiasedExponent))
{
bytesWritten = sizeof(int);
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteExponentLittleEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal128>.TryWriteExponentLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteInt32LittleEndian(destination, Number.UnpackDecimalIeee754<Decimal128, UInt128>(new UInt128(_upper, _lower)).UnbiasedExponent))
{
bytesWritten = sizeof(int);
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteSignificandBigEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal128>.TryWriteSignificandBigEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUInt128BigEndian(destination, Number.UnpackDecimalIeee754<Decimal128, UInt128>(new UInt128(_upper, _lower)).Significand))
{
bytesWritten = Unsafe.SizeOf<UInt128>();
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteSignificandLittleEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal128>.TryWriteSignificandLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUInt128LittleEndian(destination, Number.UnpackDecimalIeee754<Decimal128, UInt128>(new UInt128(_upper, _lower)).Significand))
{
bytesWritten = Unsafe.SizeOf<UInt128>();
return true;
}

bytesWritten = 0;
return false;
}

/// <summary>Computes the absolute of a value.</summary>
/// <param name="value">The value for which to get its absolute.</param>
/// <returns>The absolute of <paramref name="value" />.</returns>
Expand Down
121 changes: 120 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/Numerics/Decimal32.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers.Binary;
using System.Buffers.Text;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
Expand All @@ -14,7 +15,7 @@ public readonly struct Decimal32
: IComparable,
IComparable<Decimal32>,
IEquatable<Decimal32>,
INumberBase<Decimal32>,
IFloatingPoint<Decimal32>,
ISpanFormattable,
ISpanParsable<Decimal32>,
IMinMaxValue<Decimal32>,
Expand Down Expand Up @@ -338,6 +339,15 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringS
return new Decimal32(Number.DivideDecimalIeee754<Decimal32, uint>(left._value, right._value));
}

/// <summary>Divides two values together to compute their remainder.</summary>
/// <param name="left">The value which <paramref name="right" /> divides.</param>
/// <param name="right">The value which divides <paramref name="left" />.</param>
/// <returns>The remainder of <paramref name="left" /> divided by <paramref name="right" />.</returns>
public static Decimal32 operator %(Decimal32 left, Decimal32 right)
{
return new Decimal32(Number.RemainderDecimalIeee754<Decimal32, uint>(left._value, right._value));
}

//
// Explicit conversions to Decimal32
//
Expand Down Expand Up @@ -756,6 +766,115 @@ public static Decimal32 Parse(ReadOnlySpan<byte> utf8Text, NumberStyles style =
/// <summary>Gets the mathematical constant <c>tau</c>.</summary>
public static Decimal32 Tau => new Decimal32(TauValue);

//
// IFloatingPoint
//

/// <inheritdoc cref="IFloatingPoint{TSelf}.Ceiling(TSelf)" />
public static Decimal32 Ceiling(Decimal32 x) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, 0, MidpointRounding.ToPositiveInfinity));

/// <inheritdoc cref="IFloatingPoint{TSelf}.ConvertToInteger{TInteger}(TSelf)" />
public static TInteger ConvertToInteger<TInteger>(Decimal32 value)
where TInteger : IBinaryInteger<TInteger> => TInteger.CreateSaturating(value);

/// <inheritdoc cref="IFloatingPoint{TSelf}.ConvertToIntegerNative{TInteger}(TSelf)" />
public static TInteger ConvertToIntegerNative<TInteger>(Decimal32 value)
where TInteger : IBinaryInteger<TInteger> => TInteger.CreateSaturating(value);

/// <inheritdoc cref="IFloatingPoint{TSelf}.Floor(TSelf)" />
public static Decimal32 Floor(Decimal32 x) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, 0, MidpointRounding.ToNegativeInfinity));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf)" />
public static Decimal32 Round(Decimal32 x) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, 0, MidpointRounding.ToEven));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int)" />
public static Decimal32 Round(Decimal32 x, int digits) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, digits, MidpointRounding.ToEven));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, MidpointRounding)" />
public static Decimal32 Round(Decimal32 x, MidpointRounding mode) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, 0, mode));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Round(TSelf, int, MidpointRounding)" />
public static Decimal32 Round(Decimal32 x, int digits, MidpointRounding mode) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, digits, mode));

/// <inheritdoc cref="IFloatingPoint{TSelf}.Truncate(TSelf)" />
public static Decimal32 Truncate(Decimal32 x) => new Decimal32(Number.RoundDecimalIeee754<Decimal32, uint>(x._value, 0, MidpointRounding.ToZero));

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentByteCount()" />
int IFloatingPoint<Decimal32>.GetExponentByteCount() => sizeof(int);

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetExponentShortestBitLength()" />
int IFloatingPoint<Decimal32>.GetExponentShortestBitLength()
{
int exponent = Number.UnpackDecimalIeee754<Decimal32, uint>(_value).UnbiasedExponent;

if (exponent >= 0)
{
return (sizeof(int) * 8) - int.LeadingZeroCount(exponent);
}
else
{
return (sizeof(int) * 8) + 1 - int.LeadingZeroCount(~exponent);
}
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetSignificandBitLength()" />
int IFloatingPoint<Decimal32>.GetSignificandBitLength() => 24;

/// <inheritdoc cref="IFloatingPoint{TSelf}.GetSignificandByteCount()" />
int IFloatingPoint<Decimal32>.GetSignificandByteCount() => sizeof(uint);

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteExponentBigEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal32>.TryWriteExponentBigEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteInt32BigEndian(destination, Number.UnpackDecimalIeee754<Decimal32, uint>(_value).UnbiasedExponent))
{
bytesWritten = sizeof(int);
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteExponentLittleEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal32>.TryWriteExponentLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteInt32LittleEndian(destination, Number.UnpackDecimalIeee754<Decimal32, uint>(_value).UnbiasedExponent))
{
bytesWritten = sizeof(int);
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteSignificandBigEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal32>.TryWriteSignificandBigEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUInt32BigEndian(destination, Number.UnpackDecimalIeee754<Decimal32, uint>(_value).Significand))
{
bytesWritten = sizeof(uint);
return true;
}

bytesWritten = 0;
return false;
}

/// <inheritdoc cref="IFloatingPoint{TSelf}.TryWriteSignificandLittleEndian(Span{byte}, out int)" />
bool IFloatingPoint<Decimal32>.TryWriteSignificandLittleEndian(Span<byte> destination, out int bytesWritten)
{
if (BinaryPrimitives.TryWriteUInt32LittleEndian(destination, Number.UnpackDecimalIeee754<Decimal32, uint>(_value).Significand))
{
bytesWritten = sizeof(uint);
return true;
}

bytesWritten = 0;
return false;
}

/// <summary>Computes the absolute of a value.</summary>
/// <param name="value">The value for which to get its absolute.</param>
/// <returns>The absolute of <paramref name="value" />.</returns>
Expand Down
Loading
Loading