C# 我什么时候应该使用双精度而不是十进制?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/803225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:49:54  来源:igfitidea点击:

When should I use double instead of decimal?

c#typesfloating-pointdoubledecimal

提问by Jamie Ide

I can name three advantages to using double(or float) instead of decimal:

我可以说出使用double(or float) 而不是 的三个优点decimal

  1. Uses less memory.
  2. Faster because floating point math operations are natively supported by processors.
  3. Can represent a larger range of numbers.
  1. 使用更少的内存。
  2. 更快,因为处理器本身支持浮点数学运算。
  3. 可以表示更大范围的数字。

But these advantages seem to apply only to calculation intensive operations, such as those found in modeling software. Of course, doubles should not be used when precision is required, such as financial calculations. So are there any practical reasons to ever choose double(or float) instead of decimalin "normal" applications?

但这些优势似乎只适用于计算密集型操作,例如建模软件中的那些操作。当然,当需要精度时,例如财务计算,不应使用双精度数。那么在“正常”应用程序中是否有任何实际理由选择double(或float)而不是decimal

Edited to add: Thanks for all the great responses, I learned from them.

编辑补充:感谢所有伟大的回应,我向他们学习。

One further question: A few people made the point that doubles can more precisely represent real numbers. When declared I would think that they usually more accurately represent them as well. But is it a true statement that the accuracy may decrease (sometimes significantly) when floating point operations are performed?

另一个问题:有些人提出了 double 可以更精确地表示实数的观点。当声明时,我会认为它们通常也更准确地代表它们。但是,在执行浮点运算时精度可能会降低(有时会显着降低),这真的是真的吗?

采纳答案by Noldorin

I think you've summarised the advantages quite well. You are however missing one point. The decimaltype is only more accurate at representing base 10numbers (e.g. those used in currency/financial calculations). In general, the doubletype is going to offer at least as great precision (someone correct me if I'm wrong) and definitely greater speed for arbitrary real numbers. The simple conclusion is: when considering which to use, always use doubleunless you need the base 10accuracy that decimaloffers.

我认为你已经很好地总结了优点。然而,你错过了一分。该decimal类型仅在表示基数为 10 的数字时更准确(例如,用于货币/财务计算的数字)。一般来说,该 double类型至少会提供同样高的精度(如果我错了,有人会纠正我),并且对于任意实数肯定会提供更快的速度。简单的结论是:在考虑使用哪个时,double除非您需要提供的base 10准确性,否则始终使用decimal

Edit:

编辑:

Regarding your additional question about the decrease in accuracy of floating-point numbers after operations, this is a slightly more subtle issue. Indeed, precision (I use the term interchangeably for accuracy here) will steadily decrease after each operation is performed. This is due to two reasons:

关于您关于运算后浮点数精度降低的附加问题,这是一个稍微微妙的问题。事实上,每次操作执行后,精度(我在这里交替使用该术语来表示准确性)会稳步下降。这是由于两个原因:

  1. the fact that certain numbers (most obviously decimals) can't be truly represented in floating point form
  2. rounding errors occur, just as if you were doing the calculation by hand. It depends greatly on the context (how many operations you're performing) whether these errors are significant enough to warrant much thought however.
  1. 某些数字(最明显的是小数)不能真正以浮点形式表示的事实
  2. 出现舍入错误,就像您手动进行计算一样。然而,这在很大程度上取决于上下文(您正在执行多少操作)这些错误是否足够重要以值得深思。

In all cases, if you want to compare two floating-point numbers that should in theory be equivalent (but were arrived at using different calculations), you need to allow a certain degree of tolerance (how much varies, but is typically very small).

在所有情况下,如果要比较理论上应该相等的两个浮点数(但使用不同的计算得出),则需要允许一定程度的容差(变化多少,但通常非常小) .

For a more detailed overview of the particular cases where errors in accuracies can be introduced, see the Accuracy section of the Wikipedia article. Finally, if you want a seriously in-depth (and mathematical) discussion of floating-point numbers/operations at machine level, try reading the oft-quoted article What Every Computer Scientist Should Know About Floating-Point Arithmetic.

有关可以引入精度错误的特定情况的更详细概述,请参阅维基百科文章的精度部分。最后,如果您想在机器级别对浮点数/运算进行深入(和数学)的讨论,请尝试阅读经常被引用的文章每个计算机科学家应该知道的关于浮点运算的知识

回答by FlySwat

Use a double or a float when you don't need precision, for example, in a platformer game I wrote, I used a float to store the player velocities. Obviously I don't need super precision here because I eventually round to an Int for drawing on the screen.

当您不需要精度时使用双精度或浮点数,例如,在我编写的平台游戏中,我使用浮点数来存储玩家速度。显然,我在这里不需要超精度,因为我最终会舍入到 Int 以在屏幕上绘制。

回答by Michael Meadows

You seem spot on with the benefits of using a floating point type. I tend to design for decimals in all cases, and rely on a profiler to let me know if operations on decimal is causing bottlenecks or slow-downs. In those cases, I will "down cast" to double or float, but only do it internally, and carefully try to manage precision loss by limiting the number of significant digits in the mathematical operation being performed.

您似乎很了解使用浮点类型的好处。我倾向于在所有情况下设计小数,并依靠分析器让我知道小数操作是否导致瓶颈或减速。在这些情况下,我将“向下转换”为 double 或 float,但仅在内部进行,并通过限制正在执行的数学运算中的有效数字的数量来小心地尝试管理精度损失。

In general, if your value is transient (not reused), you're safe to use a floating point type. The real problem with floating point types is the following three scenarios.

通常,如果您的值是瞬态的(未重用),则可以安全地使用浮点类型。浮点类型的真正问题在于以下三种情况。

  1. You are aggregating floating point values (in which case the precision errors compound)
  2. You build values based on the floating point value (for example in a recursive algorithm)
  3. You are doing math with a very wide number of significant digits (for example, 123456789.1 * .000000000000000987654321)
  1. 您正在聚合浮点值(在这种情况下,精度误差会复合)
  2. 您基于浮点值构建值(例如在递归算法中)
  3. 您正在使用大量有效数字(例如,123456789.1 * .000000000000000987654321)进行数学运算

EDIT

编辑

According to the reference documentation on C# decimals:

根据C# 小数参考文档

The decimalkeyword denotes a 128-bit data type. Compared to floating-point types, the decimal type has a greater precision and a smaller range, which makes it suitable for financial and monetary calculations.

所述的十进制关键字表示128位的数据类型。与浮点类型相比,decimal 类型具有更高的精度和更小的范围,这使其适用于金融和货币计算。

So to clarify my above statement:

所以为了澄清我的上述声明:

I tend to design for decimals in all cases, and rely on a profiler to let me know if operations on decimal is causing bottlenecks or slow-downs.

我倾向于在所有情况下设计小数,并依靠分析器让我知道小数操作是否导致瓶颈或减速。

I have only ever worked in industries where decimals are favorable. If you're working on phsyics or graphics engines, it's probably much more beneficial to design for a floating point type (float or double).

我只在小数有利的行业工作过。如果您正在研究物理或图形引擎,则为浮点类型(float 或 double)设计可能更有益。

Decimal is not infinitely precise (it is impossible to represent infinite precision for non-integral in a primitive data type), but it is far more precise than double:

Decimal 不是无限精确(对于原始数据类型中的非整数不可能表示无限精度),但它比 double 精确得多:

  • decimal = 28-29 significant digits
  • double = 15-16 significant digits
  • float = 7 significant digits
  • 十进制 = 28-29 位有效数字
  • double = 15-16 位有效数字
  • 浮点数 = 7 位有效数字

EDIT 2

编辑 2

In response to Konrad Rudolph's comment, item # 1 (above) is definitely correct. Aggregation of imprecision does indeed compound. See the below code for an example:

针对Konrad Rudolph的评论,第 1 项(以上)绝对正确。不精确的聚合确实是复合的。有关示例,请参阅以下代码:

private const float THREE_FIFTHS = 3f / 5f;
private const int ONE_MILLION = 1000000;

public static void Main(string[] args)
{
    Console.WriteLine("Three Fifths: {0}", THREE_FIFTHS.ToString("F10"));
    float asSingle = 0f;
    double asDouble = 0d;
    decimal asDecimal = 0M;

    for (int i = 0; i < ONE_MILLION; i++)
    {
        asSingle += THREE_FIFTHS;
        asDouble += THREE_FIFTHS;
        asDecimal += (decimal) THREE_FIFTHS;
    }
    Console.WriteLine("Six Hundred Thousand: {0:F10}", THREE_FIFTHS * ONE_MILLION);
    Console.WriteLine("Single: {0}", asSingle.ToString("F10"));
    Console.WriteLine("Double: {0}", asDouble.ToString("F10"));
    Console.WriteLine("Decimal: {0}", asDecimal.ToString("F10"));
    Console.ReadLine();
}

This outputs the following:

这将输出以下内容:

Three Fifths: 0.6000000000
Six Hundred Thousand: 600000.0000000000
Single: 599093.4000000000
Double: 599999.9999886850
Decimal: 600000.0000000000

As you can see, even though we are adding from the same source constant, the results of the double is less precise (although probably will round correctly), and the float is far less precise, to the point where it has been reduced to only two significant digits.

如您所见,即使我们从相同的源常量添加,双精度的结果也不那么精确(尽管可能会正确舍入),并且浮点数的精度要低得多,以至于它已经减少到只有两位有效数字。

回答by Will Dean

If you need to binary interrop with other languages or platforms, then you might need to use float or double, which are standardized.

如果您需要与其他语言或平台进行二进制互操作,那么您可能需要使用标准化的 float 或 double。

回答by Mark Brackett

Use floating points if you value performance over correctness.

如果您重视性能而不是正确性,请使用浮点数。

回答by Khan

Choose the type in function of your application. If you need precision like in financial analysis, you have answered your question. But if your application can settle with an estimate your ok with double.

选择您的应用程序的功能类型。如果您需要像财务分析一样的精确度,那么您已经回答了您的问题。但是,如果您的应用程序可以通过估算来解决,那么您就可以使用 double 了。

Is your application in need of a fast calculation or will he have all the time in the world to give you an answer? It really depends on the type of application.

您的应用程序需要快速计算还是他会一直在世界上给您答案?这实际上取决于应用程序的类型。

Graphic hungry? float or double is enough. Financial data analysis, meteor striking a planet kind of precision ? Those would need a bit of precision :)

图形饿了?float 或 double 就足够了。财务数据分析,流星撞击行星的精度如何?那些需要一点精度:)

回答by Joe

Use decimal for base 10 values, e.g. financial calculations, as others have suggested.

正如其他人所建议的那样,对基数为 10 的值使用小数,例如财务计算。

But double is generally more accurate for arbitrary calculated values.

但是对于任意计算值,double 通常更准确。

For example if you want to calculate the weight of each line in a portfolio, use double as the result will more nearly add up to 100%.

例如,如果您想计算投资组合中每一行的权重,请使用 double,因为结果加起来更接近 100%。

In the following example, doubleResult is closer to 1 than decimalResult:

在以下示例中,doubleResult 比 decimalResult 更接近 1:

// Add one third + one third + one third with decimal
decimal decimalValue = 1M / 3M;
decimal decimalResult = decimalValue + decimalValue + decimalValue;
// Add one third + one third + one third with double
double doubleValue = 1D / 3D;
double doubleResult = doubleValue + doubleValue + doubleValue;

So again taking the example of a portfolio:

所以再次以投资组合为例:

  • The market value of each line in the portfolio is a monetary value and would probably be best represented as decimal.

  • The weight of each line in the portfolio (= Market Value / SUM(Market Value)) is usually better represented as double.

  • 投资组合中每一行的市场价值都是一个货币价值,最好用小数表示。

  • 投资组合中每条线的权重(= 市场价值 / SUM(市场价值))通常更好地表示为双倍。

回答by Jeson Martajaya

Decimal has wider bytes, double is natively supported by CPU. Decimal is base-10, so a decimal-to-double conversion is happening while a decimal is computed.

Decimal 具有更宽的字节,double 由 CPU 本身支持。小数是以 10 为基数的,因此在计算小数时会发生小数到双精度的转换。

For accounting - decimal
For finance - double
For heavy computation - double

Keep in mind .NET CLR only supports Math.Pow(double,double). Decimal is not supported.

请记住,.NET CLR 仅支持 Math.Pow(double,double)。不支持十进制。

.NET Framework 4

.NET 框架 4

[SecuritySafeCritical]
public static extern double Pow(double x, double y);

回答by chris klassen

A double values will serialize to scientific notation by default if that notation is shorter than the decimal display. (e.g. .00000003 will be 3e-8) Decimal values will never serialize to scientific notation. When serializing for consumption by an external party, this may be a consideration.

如果科学记数法短于十进制显示,则双精度值将默认序列化为科学记数法。(例如 .00000003 将是 3e-8)十进制值永远不会序列化为科学记数法。当序列化供外部方消费时,这可能是一个考虑因素。

回答by G DeMasters

In some Accounting, consider the possibility of using integral types instead or in conjunction. For example, let say that the rules you operate under require every calculation result carry forward with at least 6 decimal places and the final result will be rounded to the nearest penny.

在某些 Accounting 中,考虑替代或结合使用整数类型的可能性。例如,假设您操作的规则要求每个计算结果至少保留 6 位小数,最终结果将四舍五入到最接近的一分钱。

A calculation of 1/6th of $100 yields $16.66666666666666..., so the value carried forth in a worksheet will be $16.666667. Both double and decimal should yield that result accurately to 6 decimal places. However, we can avoid any cumulative error by carrying the result forward as an integer 16666667. Each subsequent calculation can be made with the same precision and carried forward similarly. Continuing the example, I calculate Texas sales tax on that amount (16666667 * .0825 = 1375000). Adding the two (it's a short worksheet) 1666667 + 1375000 = 18041667. Moving the decimal point back in gives us 18.041667, or $18.04.

计算 100 美元的 1/6 产生 16.66666666666666...,因此工作表中的值将是 16.666667 美元。double 和 decimal 都应将结果精确到小数点后 6 位。但是,我们可以通过将结果作为整数 16666667 向前推进来避免任何累积误差。随后的每个计算都可以以相同的精度进行,并以类似的方式向前推进。继续这个例子,我计算了该金额的德克萨斯州销售税 (16666667 * .0825 = 1375000)。将两者相加(这是一个简短的工作表)1666667 + 1375000 = 18041667。将小数点移回后得到 18.041667,即 18.04 美元。

While this short example wouldn't yield a cumulative error using double or decimal, it's fairly easy to show cases where simply calculating the double or decimal and carrying forward would accumulate significant error. If the rules you operate under require a limited number of decimal places, storing each value as an integer by multiplying by 10^(required # of decimal place), and then dividing by 10^(required # of decimal places) to get the actual value will avoid any cumulative error.

虽然这个简短的例子不会产生使用双精度或十进制的累积误差,但很容易展示简单计算双精度或十进制并结转会累积显着误差的情况。如果您操作的规则要求小数位数有限,则将每个值乘以 10^(要求的小数位数),然后除以 10^(要求的小数位数)将每个值存储为一个整数以获得实际value 将避免任何累积错误。

In situations where fractions of pennies do not occur (for example, a vending machine), there is no reason to use non-integral types at all. Simply think of it as counting pennies, not dollars. I have seen code where every calculation involved only whole pennies, yet use of double led to errors! Integer only math removed the issue. So my unconventional answer is, when possible, forgo both double and decimal.

在不出现小数部分的情况下(例如,自动售货机),根本没有理由使用非整数类型。简单地把它想象成计算便士,而不是美元。我见过每次计算只涉及一分钱的代码,但使用 double 会导致错误!仅整数数学消除了这个问题。所以我的非常规答案是,如果可能,放弃双精度和小数。