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
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,10 @@ internal void ReadWriteXmlTestInternal(string xml,
//[Category ("MobileNotWorking")]
public void ReadWriteXmlTest()
{
string xml1 = "<?xml version=\"1.0\" encoding=\"utf-16\"?><decimal>4556.89756</decimal>";
string xml2 = "<?xml version=\"1.0\" encoding=\"utf-16\"?><decimal>-6445.9999</decimal>";
// These reflect the exact decimal representation of the double values below. Converting a
// double to decimal is correctly rounded, so it preserves the full value rather than truncating.
string xml1 = "<?xml version=\"1.0\" encoding=\"utf-16\"?><decimal>4556.8975600000003396417014301</decimal>";
string xml2 = "<?xml version=\"1.0\" encoding=\"utf-16\"?><decimal>-6445.9998999999997977283783257</decimal>";
string xml3 = "<?xml version=\"1.0\" encoding=\"utf-16\"?><decimal>0x455687AB3E4D56F</decimal>";
decimal test1 = new decimal(4556.89756);
// This one fails because of a possible conversion bug
Expand Down
519 changes: 235 additions & 284 deletions src/libraries/System.Private.CoreLib/src/System/Decimal.DecCalc.cs

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion src/libraries/System.Private.CoreLib/src/System/Half.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,10 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringS
/// <summary>Explicitly converts a <see cref="decimal" /> value to its nearest representable half-precision floating-point value.</summary>
/// <param name="value">The value to convert.</param>
/// <returns><paramref name="value" /> converted to its nearest representable half-precision floating-point value.</returns>
public static explicit operator Half(decimal value) => (Half)(float)value;
// Round through double, not float: decimal -> double is correctly rounded and double (53-bit significand)
// -> Half is an innocuous double rounding (53 >= 2 * 11 + 2), so the result is correctly rounded. Going
// through float (24-bit significand) is not, because 24 only meets the 2 * 11 + 2 bound with no margin.
public static explicit operator Half(decimal value) => (Half)(double)value;

/// <summary>Explicitly converts a <see cref="double" /> value to its nearest representable half-precision floating-point value.</summary>
/// <param name="value">The value to convert.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace System
{
internal unsafe partial class Number
{
private static ReadOnlySpan<double> Pow10DoubleTable =>
internal static ReadOnlySpan<double> Pow10DoubleTable =>
[
1e0, // 10^0
1e1, // 10^1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,9 @@ public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, [StringS
/// <summary>Explicitly converts a <see cref="decimal" /> value to its nearest representable <see cref="BFloat16"/> value.</summary>
/// <param name="value">The value to convert.</param>
/// <returns><paramref name="value" /> converted to its nearest representable <see cref="BFloat16"/> value.</returns>
public static explicit operator BFloat16(decimal value) => (BFloat16)(float)value;
// Round through double, not float: decimal -> double is correctly rounded and double (53-bit significand)
// -> BFloat16 is an innocuous double rounding (53 >= 2 * 8 + 2), so the result is correctly rounded.
public static explicit operator BFloat16(decimal value) => (BFloat16)(double)value;

/// <summary>Explicitly converts a <see cref="double" /> value to its nearest representable <see cref="BFloat16"/> value.</summary>
/// <param name="value">The value to convert.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2235,12 +2235,12 @@ public static void TryConvertToCheckedCharTest()
[Fact]
public static void TryConvertToCheckedDecimalTest()
{
Assert.Equal(-79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(-79228162514264333195497439231.0));
Assert.Equal(-79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(-79228162514264333195497439231.0));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(-1.0));
Assert.Equal(-0.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(-0.0));
Assert.Equal(+0.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(+0.0));
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(+1.0));
Assert.Equal(+79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(+79228162514264333195497439231.0));
Assert.Equal(+79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateChecked<Complex>(+79228162514264333195497439231.0));
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,12 @@ public static void TestWriteMisc()
sw.Write((uint)uint.MaxValue);
sw.Write((ulong)ulong.MaxValue);

Assert.Equal("Truea1234.013452342.0123456-92233720368547758081234.5429496729518446744073709551615", sw.ToString());
// The expected string is the concatenation of every value above with no separators, so
// adjacent values run together (e.g. "1234.00..." from the decimal is immediately followed
// by "3452342.01" from the double). The decimal segment is the full value of new decimal(1234.01):
// the double nearest 1234.01 is actually 1234.009999999999990905052982270717620849609375, and
// double -> decimal is correctly rounded, so it preserves that value rather than truncating to "1234.01".
Assert.Equal("Truea1234.00999999999999090505298233452342.0123456-92233720368547758081234.5429496729518446744073709551615", sw.ToString());
}
}

Expand Down
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.Globalization;
using Xunit;

namespace System.Tests
Expand Down Expand Up @@ -34,14 +35,19 @@ public void FromDecimal()
[Fact]
public void FromDouble()
{
// 0.001 is inexact as a double, so the expected value is derived from parsing its full base-10
// expansion to exercise the correctly-rounded (double -> decimal) conversion.
double[] testValues = { 1000.0, 100.0, 0.0, 0.001, -1000.0, -100.0, };
decimal[] expectedValues = { 1000.0m, 100.0m, 0.0m, 0.001m, -1000.0m, -100.0m };
decimal[] expectedValues = { 1000.0m, 100.0m, 0.0m, ParseDecimalExpansion(0.001), -1000.0m, -100.0m };
Verify(Convert.ToDecimal, testValues, expectedValues);
Comment thread
tannergooding marked this conversation as resolved.

double[] overflowValues = { double.MaxValue, double.MinValue };
VerifyThrows<OverflowException, double>(Convert.ToDecimal, overflowValues);
}

private static decimal ParseDecimalExpansion(double value) =>
decimal.Parse(value.ToString("G99", CultureInfo.InvariantCulture), NumberStyles.Float, CultureInfo.InvariantCulture);

[Fact]
public void FromInt16()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,32 @@ public static void Round_Double_Digits_ByMidpointRounding(MidpointRounding mode)
Assert.Equal(double.NegativeInfinity, Math.Round(double.NegativeInfinity, 3, mode));
}

public static IEnumerable<object[]> Round_Digits_Decimal_TestData
{
get
{
yield return new object[] {0m, 0m, 3, MidpointRounding.ToEven};
yield return new object[] {3.42156m, 3.422m, 3, MidpointRounding.ToEven};
yield return new object[] {-3.42156m, -3.422m, 3, MidpointRounding.ToEven};

yield return new object[] {0m, 0m, 3, MidpointRounding.AwayFromZero};
yield return new object[] {3.42156m, 3.422m, 3, MidpointRounding.AwayFromZero};
yield return new object[] {-3.42156m, -3.422m, 3, MidpointRounding.AwayFromZero};

yield return new object[] {0m, 0m, 3, MidpointRounding.ToZero};
yield return new object[] {3.42156m, 3.421m, 3, MidpointRounding.ToZero};
yield return new object[] {-3.42156m, -3.421m, 3, MidpointRounding.ToZero};

yield return new object[] {0m, 0m, 3, MidpointRounding.ToNegativeInfinity};
yield return new object[] {3.42156m, 3.421m, 3, MidpointRounding.ToNegativeInfinity};
yield return new object[] {-3.42156m, -3.422m, 3, MidpointRounding.ToNegativeInfinity};

yield return new object[] {0m, 0m, 3, MidpointRounding.ToPositiveInfinity};
yield return new object[] {3.42156m, 3.422m, 3, MidpointRounding.ToPositiveInfinity};
yield return new object[] {-3.42156m, -3.421m, 3, MidpointRounding.ToPositiveInfinity};
}
}

[Theory]
[MemberData(nameof(Round_Digits_TestData))]
public static void Round_Double_Digits(double x, double expected, int digits, MidpointRounding mode)
Expand All @@ -2485,7 +2511,7 @@ public static void Round_Double_Digits(double x, double expected, int digits, Mi
}

[Theory]
[MemberData(nameof(Round_Digits_TestData))]
[MemberData(nameof(Round_Digits_Decimal_TestData))]
public static void Round_Decimal_Digits(decimal x, decimal expected, int digits, MidpointRounding mode)
{
Assert.Equal(expected, Math.Round(x, digits, mode));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,8 @@ public static void CreateCheckedFromDoubleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateChecked<double>(+1.0));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateChecked<double>(-1.0));

Assert.Equal(+79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<double>(-79228162514264333195497439231.0));
Assert.Equal(+79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateChecked<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateChecked<double>(-79228162514264333195497439231.0));

Assert.Throws<OverflowException>(() => NumberBaseHelper<decimal>.CreateChecked<double>(+79228162514264337593543950335.0));
Assert.Throws<OverflowException>(() => NumberBaseHelper<decimal>.CreateChecked<double>(-79228162514264337593543950335.0));
Expand All @@ -629,8 +629,8 @@ public static void CreateCheckedFromHalfTest()
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateChecked<Half>(Half.Zero));
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateChecked<Half>(Half.NegativeZero));

Assert.Equal(+0.00000005960464m, NumberBaseHelper<decimal>.CreateChecked<Half>(+Half.Epsilon));
Assert.Equal(-0.00000005960464m, NumberBaseHelper<decimal>.CreateChecked<Half>(-Half.Epsilon));
Assert.Equal(+0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateChecked<Half>(+Half.Epsilon));
Assert.Equal(-0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateChecked<Half>(-Half.Epsilon));

Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateChecked<Half>(Half.One));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateChecked<Half>(Half.NegativeOne));
Expand Down Expand Up @@ -749,8 +749,8 @@ public static void CreateCheckedFromSingleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateChecked<float>(+1.0f));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateChecked<float>(-1.0f));

Assert.Equal(+79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateChecked<float>(-79228160000000000000000000000.0f));
Assert.Equal(+79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateChecked<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateChecked<float>(-79228160000000000000000000000.0f));

Assert.Throws<OverflowException>(() => NumberBaseHelper<decimal>.CreateChecked<float>(+79228162514264337593543950335.0f));
Assert.Throws<OverflowException>(() => NumberBaseHelper<decimal>.CreateChecked<float>(-79228162514264337593543950335.0f));
Expand Down Expand Up @@ -869,8 +869,8 @@ public static void CreateSaturatingFromDoubleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(+1.0));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(-1.0));

Assert.Equal(+79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(-79228162514264333195497439231.0));
Assert.Equal(+79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateSaturating<double>(-79228162514264333195497439231.0));

Assert.Equal(decimal.MaxValue, NumberBaseHelper<decimal>.CreateSaturating<double>(+79228162514264337593543950335.0));
Assert.Equal(decimal.MinValue, NumberBaseHelper<decimal>.CreateSaturating<double>(-79228162514264337593543950335.0));
Expand All @@ -890,8 +890,8 @@ public static void CreateSaturatingFromHalfTest()
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateSaturating<Half>(Half.Zero));
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateSaturating<Half>(Half.NegativeZero));

Assert.Equal(+0.00000005960464m, NumberBaseHelper<decimal>.CreateSaturating<Half>(+Half.Epsilon));
Assert.Equal(-0.00000005960464m, NumberBaseHelper<decimal>.CreateSaturating<Half>(-Half.Epsilon));
Assert.Equal(+0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateSaturating<Half>(+Half.Epsilon));
Assert.Equal(-0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateSaturating<Half>(-Half.Epsilon));

Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateSaturating<Half>(Half.One));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateSaturating<Half>(Half.NegativeOne));
Expand Down Expand Up @@ -1011,8 +1011,8 @@ public static void CreateSaturatingFromSingleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(+1.0f));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(-1.0f));

Assert.Equal(+79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(-79228160000000000000000000000.0f));
Assert.Equal(+79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateSaturating<float>(-79228160000000000000000000000.0f));

Assert.Equal(decimal.MaxValue, NumberBaseHelper<decimal>.CreateSaturating<float>(+79228162514264337593543950335.0f));
Assert.Equal(decimal.MinValue, NumberBaseHelper<decimal>.CreateSaturating<float>(-79228162514264337593543950335.0f));
Expand Down Expand Up @@ -1132,8 +1132,8 @@ public static void CreateTruncatingFromDoubleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(+1.0));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(-1.0));

Assert.Equal(+79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264300000000000000.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(-79228162514264333195497439231.0));
Assert.Equal(+79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(+79228162514264333195497439231.0));
Assert.Equal(-79228162514264328797450928128.0m, NumberBaseHelper<decimal>.CreateTruncating<double>(-79228162514264333195497439231.0));

Assert.Equal(decimal.MaxValue, NumberBaseHelper<decimal>.CreateTruncating<double>(+79228162514264337593543950335.0));
Assert.Equal(decimal.MinValue, NumberBaseHelper<decimal>.CreateTruncating<double>(-79228162514264337593543950335.0));
Expand All @@ -1153,8 +1153,8 @@ public static void CreateTruncatingFromHalfTest()
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateTruncating<Half>(Half.Zero));
Assert.Equal(0.0m, NumberBaseHelper<decimal>.CreateTruncating<Half>(Half.NegativeZero));

Assert.Equal(+0.00000005960464m, NumberBaseHelper<decimal>.CreateTruncating<Half>(+Half.Epsilon));
Assert.Equal(-0.00000005960464m, NumberBaseHelper<decimal>.CreateTruncating<Half>(-Half.Epsilon));
Assert.Equal(+0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateTruncating<Half>(+Half.Epsilon));
Assert.Equal(-0.000000059604644775390625m, NumberBaseHelper<decimal>.CreateTruncating<Half>(-Half.Epsilon));

Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateTruncating<Half>(Half.One));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateTruncating<Half>(Half.NegativeOne));
Expand Down Expand Up @@ -1274,8 +1274,8 @@ public static void CreateTruncatingFromSingleTest()
Assert.Equal(+1.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(+1.0f));
Assert.Equal(-1.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(-1.0f));

Assert.Equal(+79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228160000000000000000000000.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(-79228160000000000000000000000.0f));
Assert.Equal(+79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(+79228160000000000000000000000.0f));
Assert.Equal(-79228157791897854723898736640.0m, NumberBaseHelper<decimal>.CreateTruncating<float>(-79228160000000000000000000000.0f));

Assert.Equal(decimal.MaxValue, NumberBaseHelper<decimal>.CreateTruncating<float>(+79228162514264337593543950335.0f));
Assert.Equal(decimal.MinValue, NumberBaseHelper<decimal>.CreateTruncating<float>(-79228162514264337593543950335.0f));
Expand Down
Loading
Loading