【问题标题】:Different Result from ToString - Method for small negative double (net Framework vs. net 6.0)与 ToString 不同的结果 - 小负双精度的方法(net Framework 与 net 6.0)
【发布时间】:2022-08-18 20:52:03
【问题描述】:

给定以下程序 C#

using System;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine((-2.8E-15).ToString(\"P2\"));
        }
    }
}
  1. 使用 .net Framework 4.8 运行会产生 \"0.00%\"
  2. 使用 .net 6.0 运行会产生 \"-0.00%\"

    我如何在全球范围内确保 .net 6.0 也会导致:

    \"0.00%\"
    

    无需更改 (-2.8E-15).ToString(\"P2\") 例如在这里四舍五入。

    我们的问题是 WPF 绑定有一个 StringFormat 也显示 \"-0.00%\" 值,给定以下绑定\"{Binding DoubleValue, StringFormat=P2}\"

    我不喜欢在这里引入 Converter 或对 ViewModel 中的值进行四舍五入。如果有其他方法。 Binding 的一个子类可能是我今天早上想到的一个想法。但我宁愿不这样做...

  • Math.Abs(-2.8E-15).ToString(\"P2\") 将删除该标志。

标签: c# wpf .net-6.0 .net-4.8


【解决方案1】:

.NET Core 在 IEEE 浮点合规性方面引入了大量浮点解析和格式改进。其中之一是 IEEE 754-2008 格式合规性。

这就是为什么您现在看到接近负数的结果导致负 0。但是,由于 -0 和 0 基本相同,IEEE 754 标准规定正零和负零是两个独立的数字,但这可能会导致问题,如果你无法处理它。此更改已在 .net core 3 中进行,您可以在此处阅读更多信息:https://devblogs.microsoft.com/dotnet/floating-point-parsing-and-formatting-improvements-in-net-core-3-0/

对于整数,没有二进制表示可以在 0 和 -0 之间产生差异,因此它们在定义上是相等的。

对于 IEEE 浮点数,有负零和正零之分。有人做了一些测试(.NET Framework 2.0 的 CLR,C# 3),似乎它们被认为是相等的,这实际上是根据 IEEE 754 标准预期的行为。

这里是测试:

   double minusOne = -1.0;
    double positiveZero = 0.0;
    double negativeZero = minusOne*positiveZero;
    Console.WriteLine("{0} == {1} -> {2}", positiveZero, negativeZero, positiveZero == negativeZero);
    Console.WriteLine("Binary representation is equal: {0}", BitConverter.DoubleToInt64Bits(positiveZero) == BitConverter.DoubleToInt64Bits(negativeZero));

结果是:

0 == 0 -> True
Binary representation is equal: False

长话短说,如果您想确保永远不会返回“-0.00%”,那么如果您要继续使用浮点数,则需要对其进行检查。您可以创建一个扩展方法来检查这个或像这样简单的东西

void Main()
{
    var num = (-2.8E-15).ToString("P2");
    
    if(num == "-0.00%" || num == "-0.0%" || num == "-0%")
    {
        num = "0.00%";
    }
    
    Console.WriteLine(num);
    //result is: 0.00%
}

【讨论】:

  • 谢谢你的解释!实际上扩展方法不是一种选择。因为它不会在 WPF 绑定中进行评估,例如{Binding DoubleValue, StringFormat=P2} 在这里我可以使用转换器,但我想知道是否还有其他选择。我将更新我的问题以指向 WPF 方向。
【解决方案2】:

在 WPF XAML 中,我使用此绑定:

"{Binding DoubleValue, Converter={x:Static converters:DoubleToRoundedDoubleConverter.Instance},
                       ConverterParameter=4,
                       StringFormat=P2}"

使用以下转换器:

public class DoubleToRoundedDoubleConverter : IValueConverter
{
    public static readonly IValueConverter Instance = new DoubleToRoundedDoubleConverter();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double doubleValue
            && (parameter is int digits || (parameter is string paramStr && int.TryParse(paramStr, out digits)))
            && digits >= 0)
        {
            double roundedDouble = Math.Round(doubleValue, digits);
            double bound = 5.0 * Math.Pow(0.1, digits + 1.0);
            return Math.Abs(roundedDouble) < bound ? 0.0 : roundedDouble;
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2022-07-08
    • 1970-01-01
    • 1970-01-01
    • 2010-10-08
    • 1970-01-01
    相关资源
    最近更新 更多