十进制在 C# 中存储解析字符串的精度?有什么影响

本文关键字:精度 影响 什么 字符串 存储 十进制 | 更新日期: 2023-09-27 18:19:11

在IRC上的一次对话中,有人指出了以下内容:

decimal.Parse("1.0000").ToString() // 1.0000
decimal.Parse("1.00").ToString() // 1.00

decimal类型如何/为什么保持这样的精度(或者更确切地说,有效数字(?我的印象是这两个值是相等的,而不是不同的。

这也引发了进一步的问题:

  • 在数学运算过程中如何确定有效数字的数量?
  • 在序列化过程中是否保留有效数字的数量?
  • 当前的文化是否会影响处理此问题的方式?

十进制在 C# 中存储解析字符串的精度?有什么影响

在数学运算过程中如何确定有效数字的数量?

这在 ECMA-334 C# 4 规范 11.1.7 p.112 中指定

小数表示为按 10 的幂缩放的整数。为 绝对值小于 1.0m 的小数,该值精确到 至少小数点后 28 位。对于具有绝对值的小数 大于等于1.0m,该值精确到至少28 数字。

在序列化过程中是否保留有效数字的数量?

是的,确实如此,通过序列化,值及其精度不会改变

[Serializable]
public class Foo
{
    public decimal Value;
}
class Program
{
    static void Main(string[] args)
    {
        decimal d1 = decimal.Parse("1.0000");
        decimal d2 = decimal.Parse("1.00");
        Debug.Assert(d1 ==d2);
        var foo1 = new Foo() {Value = d1};
        var foo2 = new Foo() {Value = d2};
        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("data.bin", FileMode.Create, FileAccess.Write, FileShare.None);
        formatter.Serialize(stream, d1);
        stream.Close();
        formatter = new BinaryFormatter();
        stream = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
        decimal deserializedD1 = (decimal)formatter.Deserialize(stream);
        stream.Close();
        Debug.Assert(d1 == deserializedD1);
        Console.WriteLine(d1); //1.0000
        Console.WriteLine(d2); //1.00
        Console.WriteLine(deserializedD1); //1.0000
        Console.Read();
    }
}

当前的文化是否会影响处理此问题的方式?

当前区域性仅影响从字符串解析小数的方式,例如,它可以将"."或",">作为区域性特定的小数点符号或货币符号进行处理,如果您提供它,例如"£123.4500"。区域性不会更改对象在内部的存储方式,也不会影响其精度。

在内部,十进制有一个尾数、一个指数和一个符号,所以没有空间容纳其他任何东西。

十进制由 96 位整数和比例因子(小数点后的位数(组成,范围为 0 到 28。 因此:

  • 比例因子为 3 时,1.000 变为 1000。

除了我在这里看到的帖子之外,我个人还会添加一个旁注:

在使用浮点/小数/双精度数的持久性操作期间,始终考虑您所在culture,否则您将要保存。像这里编写的代码是第一个,但最终传递到完全混乱和非文化独立的架构。

使用 Decimal.Parse(字符串,IFormatProvider(。

在我看来,必须从库中删除缺少Culture参数的方法(Parse From/To(,以迫使开发人员考虑这个非常重要的方面。