我什么时候应该使用double而不是decimal?

时间:2022-09-10 22:54:20

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

我可以使用double(或float)而不是decimal来命名三个优点:

  1. Uses less memory.
  2. 使用较少的内存。

  3. Faster because floating point math operations are natively supported by processors.
  4. 更快,因为处理器本身支持浮点数学运算。

  5. Can represent a larger range of numbers.
  6. 可以代表更大范围的数字。

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 decimal in "normal" applications?

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

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?

还有一个问题:一些人认为双打可以更精确地代表实数。宣布时,我认为他们通常也会更准确地代表他们。但是,当执行浮点运算时,准确度可能会降低(有时是显着的)吗?

12 个解决方案

#1


I think you've summarised the advantages quite well. You are however missing one point. The decimal type is only more accurate at representing base 10 numbers (e.g. those used in currency/financial calculations). In general, the double type 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 double unless you need the base 10 accuracy that decimal offers.

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

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. 事实上某些数字(最明显的小数)不能以浮点形式真正表示

  3. 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.
  4. 发生舍入错误,就像您手动执行计算一样。它在很大程度上取决于上下文(您正在执行的操作数量),这些错误是否足够重要,无论如何都要多加考虑。

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.

有关可以引入精度误差的特定情况的更详细概述,请参阅Wikipedia文章的“准确性”部分。最后,如果您想在机器级别对浮点数/运算进行认真深入(和数学)的讨论,请尝试阅读经常引用的文章“每个计算机科学家应该知道的关于浮点算术的内容”。

#2


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. 您正在聚合浮点值(在这种情况下,精度错误复合)

  3. You build values based on the floating point value (for example in a recursive algorithm)
  4. 您可以根据浮点值构建值(例如,在递归算法中)

  5. You are doing math with a very wide number of significant digits (for example, 123456789.1 * .000000000000000987654321)
  6. 您正在使用大量有效数字进行数学运算(例如,123456789.1 * .000000000000000987654321)

EDIT

According to the reference documentation on C# decimals:

根据C#小数的参考文档:

The decimal keyword 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.

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

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).

我只在小数有利的行业工作过。如果你正在研究phsyics或图形引擎,那么设计浮点类型(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 = 28-29 significant digits
  • decimal = 28-29有效数字

  • double = 15-16 significant digits
  • double = 15-16有效数字

  • float = 7 significant digits
  • float = 7位有效数字

EDIT 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.

正如您所看到的,即使我们从相同的源常量中添加,double的结果也不太精确(尽管可能会正确地舍入),并且float的精确度要低得多,直到它只减少到只有两位有效数字。

#3


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(市场价值))通常更好地表示为双倍。

#4


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.

当你不需要精确度时,使用double或float,例如,在我写的平台游戏中,我使用浮动来存储玩家的速度。显然我在这里不需要超精确,因为我最终会绕过Int来绘制屏幕。

#5


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.

在某些会计中,请考虑使用整数类型或结合使用整数类型的可能性。例如,假设您运行的规则要求每个计算结果至少带有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.

虽然这个简短的例子不会产生使用double或decimal的累积误差,但是很容易显示简单地计算double或decimal并且继续前进会累积重大错误的情况。如果您在其下运行的规则需要有限的小数位数,则将每个值存储为整数乘以10 ^(所需的小数位数),然后除以10 ^(所需的小数位数)以获得实际值值将避免任何累积错误。

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.

在没有发生几分钱的情况下(例如,自动售货机),根本没有理由使用非整数类型。简单地把它想象成便士,而不是美元。我看过代码,其中每个计算只涉及整个便士,但使用双重导致错误!仅整数数学删除了该问题。所以我的非常规答案是,如果可能的话,放弃双倍和小数。

#6


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。

#7


Note: this post is based on information of the decimal type's capabilities from http://csharpindepth.com/Articles/General/Decimal.aspx and my own interpretation of what that means. I will assume Double is normal IEEE double precision.

注意:这篇文章基于http://csharpindepth.com/Articles/General/Decimal.aspx中十进制类型功能的信息以及我对这意味着什么的解释。我将假设Double是正常的IEEE双精度。

Note2: smallest and largest in this post reffer to the magnitude of the number.

注2:这个帖子中最小和最大的数量是这个数字的大小。

Pros of "decimal".

“十进制”的优点。

  • "decimal" can represent exactly numbers that can be written as (sufficiently short) decimal fractions, double cannot. This is important in financial ledgers and similar where it is important that the results exactly match what a human doing the calculations would give.
  • “十进制”可以表示可写为(足够短)小数分数的精确数字,双重不能。这在财务分类账中非常重要,类似的是,结果与计算人员所做的完全匹配非常重要。

  • "decimal" has a much larger mantissa than "double". That means that for values within it's normalised range "decimal" will have a much higher precision than double.
  • “十进制”的尾数比“双”大得多。这意味着对于其范围内的值,标准化范围“十进制”将具有比双精度高得多的精度。

Cons of decimal

小数的缺点

  • It will be Much slower (I don't have benchmarks but I would guess at least an order of magnitude maybe more), decimal will not benefit from any hardware acceleration and arithmetic on it will require relatively expensive multiplication/division by powers of 10 (which is far more expensive than multiplication and dividion by powers of 2) to match the exponent before addition/subtraction and to bring the exponent back into range after multiplication/division.
  • 它会慢得多(我没有基准,但我猜测至少可能有一个数量级),十进制不会受益于任何硬件加速和算术就需要相对昂贵的乘法/除法乘以10(这比2乘法的乘法和乘法要贵得多,以便在加/减之前匹配指数,并在乘法/除法后使指数回到范围内。

  • decimal will overflow earlier tha double will. decimal can only represent numbers up to ±296-1 . By comparision double can represent numbers up to nearly ±21024
  • 十进制将提前溢出双重意志。十进制只能表示高达±296-1的数字。通过比较,double可以表示高达近±21024的数字

  • decimal will underflow earlier. The smallest numbers representable in decimal are ±10-28 . By comparision double can represent values down to 2-149 (approx 10-45) if subnromal numbers are supported and 2-126 (approx 10-38) if they are not.
  • 十进制将提前下溢。以十进制表示的最小数字是±10-28。通过比较,如果支持次要数字,则double可以表示低至2-149(约10-45)的值,如果不支持,则可以表示2-126(约10-38)。

  • decimal takes up twice as much memory as double.
  • decimal占用的内存是double的两倍。

My opinion is that you should default to using "decimal" for money work and other cases where matching human calculation exactly is important and that you should use use double as your default choice the rest of the time.

我的意见是你应该默认使用“十进制”进行金钱工作和其他情况,其中匹配人类计算确实很重要,并且你应该在其余时间使用double作为默认选择。

#8


Use floating points if you value performance over correctness.

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

#9


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.

选择应用程序的功能类型。如果您需要财务分析中的精确度,您已回答了您的问题。但是如果你的应用程序可以通过估算你的确定加倍。

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 :)

图形饿了吗?漂浮或双倍就足够了。财务数据分析,流星撞击行星的那种精确度?那些需要一点精度:)

#10


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有更宽的字节,CPU本身支持double。十进制是基数为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 Framework 4

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

#11


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)十进制值永远不会序列化为科学记数法。当序列化供外部用户使用时,这可能是一个考虑因素。

#12


Depends on what you need it for.

Because float and double are binary data types you have some diifculties and errrors in the way in rounds numbers, so for instance double would round 0.1 to 0.100000001490116, double would also round 1 / 3 to 0.33333334326441. Simply put not all real numbers have accurate representation in double types

因为float和double是二进制数据类型,所以在舍入数字中有一些diifculties和错误,所以例如double将舍入0.1到0.100000001490116,double也会舍入1/3到0.33333334326441。简单地说,并非所有实数都具有双重类型的准确表示

Luckily C# also supports the so-called decimal floating-point arithmetic, where numbers are represented via the decimal numeric system rather than the binary system. Thus, the decimal floating point-arithmetic does not lose accuracy when storing and processing floating-point numbers. This makes it immensely suited to calculations where a high level of accuracy is needed.

幸运的是,C#还支持所谓的十进制浮点运算,其中数字通过十进制数字系统而不是二进制系统表示。因此,在存储和处理浮点数时,十进制浮点运算不会失去准确性。这使得它非常适合需要高精度的计算。

#1


I think you've summarised the advantages quite well. You are however missing one point. The decimal type is only more accurate at representing base 10 numbers (e.g. those used in currency/financial calculations). In general, the double type 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 double unless you need the base 10 accuracy that decimal offers.

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

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. 事实上某些数字(最明显的小数)不能以浮点形式真正表示

  3. 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.
  4. 发生舍入错误,就像您手动执行计算一样。它在很大程度上取决于上下文(您正在执行的操作数量),这些错误是否足够重要,无论如何都要多加考虑。

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.

有关可以引入精度误差的特定情况的更详细概述,请参阅Wikipedia文章的“准确性”部分。最后,如果您想在机器级别对浮点数/运算进行认真深入(和数学)的讨论,请尝试阅读经常引用的文章“每个计算机科学家应该知道的关于浮点算术的内容”。

#2


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. 您正在聚合浮点值(在这种情况下,精度错误复合)

  3. You build values based on the floating point value (for example in a recursive algorithm)
  4. 您可以根据浮点值构建值(例如,在递归算法中)

  5. You are doing math with a very wide number of significant digits (for example, 123456789.1 * .000000000000000987654321)
  6. 您正在使用大量有效数字进行数学运算(例如,123456789.1 * .000000000000000987654321)

EDIT

According to the reference documentation on C# decimals:

根据C#小数的参考文档:

The decimal keyword 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.

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

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).

我只在小数有利的行业工作过。如果你正在研究phsyics或图形引擎,那么设计浮点类型(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 = 28-29 significant digits
  • decimal = 28-29有效数字

  • double = 15-16 significant digits
  • double = 15-16有效数字

  • float = 7 significant digits
  • float = 7位有效数字

EDIT 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.

正如您所看到的,即使我们从相同的源常量中添加,double的结果也不太精确(尽管可能会正确地舍入),并且float的精确度要低得多,直到它只减少到只有两位有效数字。

#3


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(市场价值))通常更好地表示为双倍。

#4


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.

当你不需要精确度时,使用double或float,例如,在我写的平台游戏中,我使用浮动来存储玩家的速度。显然我在这里不需要超精确,因为我最终会绕过Int来绘制屏幕。

#5


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.

在某些会计中,请考虑使用整数类型或结合使用整数类型的可能性。例如,假设您运行的规则要求每个计算结果至少带有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.

虽然这个简短的例子不会产生使用double或decimal的累积误差,但是很容易显示简单地计算double或decimal并且继续前进会累积重大错误的情况。如果您在其下运行的规则需要有限的小数位数,则将每个值存储为整数乘以10 ^(所需的小数位数),然后除以10 ^(所需的小数位数)以获得实际值值将避免任何累积错误。

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.

在没有发生几分钱的情况下(例如,自动售货机),根本没有理由使用非整数类型。简单地把它想象成便士,而不是美元。我看过代码,其中每个计算只涉及整个便士,但使用双重导致错误!仅整数数学删除了该问题。所以我的非常规答案是,如果可能的话,放弃双倍和小数。

#6


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。

#7


Note: this post is based on information of the decimal type's capabilities from http://csharpindepth.com/Articles/General/Decimal.aspx and my own interpretation of what that means. I will assume Double is normal IEEE double precision.

注意:这篇文章基于http://csharpindepth.com/Articles/General/Decimal.aspx中十进制类型功能的信息以及我对这意味着什么的解释。我将假设Double是正常的IEEE双精度。

Note2: smallest and largest in this post reffer to the magnitude of the number.

注2:这个帖子中最小和最大的数量是这个数字的大小。

Pros of "decimal".

“十进制”的优点。

  • "decimal" can represent exactly numbers that can be written as (sufficiently short) decimal fractions, double cannot. This is important in financial ledgers and similar where it is important that the results exactly match what a human doing the calculations would give.
  • “十进制”可以表示可写为(足够短)小数分数的精确数字,双重不能。这在财务分类账中非常重要,类似的是,结果与计算人员所做的完全匹配非常重要。

  • "decimal" has a much larger mantissa than "double". That means that for values within it's normalised range "decimal" will have a much higher precision than double.
  • “十进制”的尾数比“双”大得多。这意味着对于其范围内的值,标准化范围“十进制”将具有比双精度高得多的精度。

Cons of decimal

小数的缺点

  • It will be Much slower (I don't have benchmarks but I would guess at least an order of magnitude maybe more), decimal will not benefit from any hardware acceleration and arithmetic on it will require relatively expensive multiplication/division by powers of 10 (which is far more expensive than multiplication and dividion by powers of 2) to match the exponent before addition/subtraction and to bring the exponent back into range after multiplication/division.
  • 它会慢得多(我没有基准,但我猜测至少可能有一个数量级),十进制不会受益于任何硬件加速和算术就需要相对昂贵的乘法/除法乘以10(这比2乘法的乘法和乘法要贵得多,以便在加/减之前匹配指数,并在乘法/除法后使指数回到范围内。

  • decimal will overflow earlier tha double will. decimal can only represent numbers up to ±296-1 . By comparision double can represent numbers up to nearly ±21024
  • 十进制将提前溢出双重意志。十进制只能表示高达±296-1的数字。通过比较,double可以表示高达近±21024的数字

  • decimal will underflow earlier. The smallest numbers representable in decimal are ±10-28 . By comparision double can represent values down to 2-149 (approx 10-45) if subnromal numbers are supported and 2-126 (approx 10-38) if they are not.
  • 十进制将提前下溢。以十进制表示的最小数字是±10-28。通过比较,如果支持次要数字,则double可以表示低至2-149(约10-45)的值,如果不支持,则可以表示2-126(约10-38)。

  • decimal takes up twice as much memory as double.
  • decimal占用的内存是double的两倍。

My opinion is that you should default to using "decimal" for money work and other cases where matching human calculation exactly is important and that you should use use double as your default choice the rest of the time.

我的意见是你应该默认使用“十进制”进行金钱工作和其他情况,其中匹配人类计算确实很重要,并且你应该在其余时间使用double作为默认选择。

#8


Use floating points if you value performance over correctness.

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

#9


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.

选择应用程序的功能类型。如果您需要财务分析中的精确度,您已回答了您的问题。但是如果你的应用程序可以通过估算你的确定加倍。

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 :)

图形饿了吗?漂浮或双倍就足够了。财务数据分析,流星撞击行星的那种精确度?那些需要一点精度:)

#10


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有更宽的字节,CPU本身支持double。十进制是基数为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 Framework 4

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

#11


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)十进制值永远不会序列化为科学记数法。当序列化供外部用户使用时,这可能是一个考虑因素。

#12


Depends on what you need it for.

Because float and double are binary data types you have some diifculties and errrors in the way in rounds numbers, so for instance double would round 0.1 to 0.100000001490116, double would also round 1 / 3 to 0.33333334326441. Simply put not all real numbers have accurate representation in double types

因为float和double是二进制数据类型,所以在舍入数字中有一些diifculties和错误,所以例如double将舍入0.1到0.100000001490116,double也会舍入1/3到0.33333334326441。简单地说,并非所有实数都具有双重类型的准确表示

Luckily C# also supports the so-called decimal floating-point arithmetic, where numbers are represented via the decimal numeric system rather than the binary system. Thus, the decimal floating point-arithmetic does not lose accuracy when storing and processing floating-point numbers. This makes it immensely suited to calculations where a high level of accuracy is needed.

幸运的是,C#还支持所谓的十进制浮点运算,其中数字通过十进制数字系统而不是二进制系统表示。因此,在存储和处理浮点数时,十进制浮点运算不会失去准确性。这使得它非常适合需要高精度的计算。