题 .NET中的decimal,float和double之间的区别?


有什么区别 decimalfloat 和 double 在.NET?

什么时候会有人使用其中一种?


1776
2018-03-06 11:31


起源


有趣的文章 zetcode.com/lang/csharp/datatypes - GibboK
@Bargitta那不是真的,有 float 在.NET中。只是 System 调用type(即不是关键字) Single。 - Balázs
有关: sandbox.mc.edu/~bennet/cs110/flt/dtof.html - Pacerier


答案:


float 和 double 是 漂浮的 二进制 点类型。换句话说,它们代表了这样的数字:

10001.10010110011

二进制数和二进制点的位置都在该值内编码。

decimal 是一个 漂浮的 十进制 点类型。换句话说,它们代表了这样的数字:

12345.65789

再次,数量和位置 十进制 point都是在值内编码的 - 这就是它的作用 decimal 仍然是浮点类型而不是固定点类型。

需要注意的重要一点是,人类习惯于以十进制形式表示非整数,并期望十进制表示中的精确结果;并非所有十进制数都可以在二进制浮点中精确表示 - 例如0.1 - 所以如果使用二进制浮点值,实际上会得到0.1的近似值。在使用浮动小数点时,您仍然可以获得近似值 - 例如,无法准确表示将1除以3​​的结果。

至于什么时候使用:

  • 对于“自然精确小数”的值,使用起来很好 decimal。这通常适用于人类发明的任何概念:财务价值是最明显的例子,但也有其他概念。例如,考虑给予潜水员或滑冰者的分数。

  • 对于不能真正测量的更多自然的人工制品的价值 究竟 无论如何, float/double 更合适。例如,科学数据通常以这种形式表示。在这里,原始值不会以“十进制精度”开头,因此保持“十进制精度”对于预期结果并不重要。使用浮点二进制点类型比使用小数要快得多。


1969
2018-03-06 11:56



float/double 通常不代表数字 101.101110,通常它表示为类似的东西 1101010 * 2^(01010010)  - 一个指数 - Mingwei Samuel
@Hazzard:这就是“二进制点的位置”和答案的一部分意味着什么。 - Jon Skeet
我很惊讶它还没有说过, float 是一个C#别名关键字,不是.Net类型。它的 System.Single.. single 和 double 是浮动二进制点类型。 - Brett Caswell
等待....最终不是以1和0表示的小数?我以为计算机只能以二进制形式工作。那么小数最终是二进制类型不是吗? - BKSpurgeon
@BKSpurgeon:嗯,只是以你能说的方式 一切 是一种二进制类型,在这一点上它变成了一个相当无用的定义。十进制是一种十进制类型,因为它是一个数字,表示为整数有效数和一个比例,因此结果是有效数* 10 ^ scale,而float和double是有效数* 2 ^ scale。你取一个用十进制写的数字,并将小数点移到右边,你有一个整数来计算有效数和比例。对于float / double,你可以用二进制写的数字开头。 - Jon Skeet


精度是主要的区别。

浮动  - 7位数(32位)

-15-16位(64位)

十进制 -28-29有效数字(128位)

小数具有更高的精度,通常用于需要高精度的金融应用程序中。小数比一个双/浮点慢得多(在某些测试中高达20倍)。

如果没有演员阵容,则无法比较小数和浮点数/双打,而浮点数和双打则可以。小数也允许编码或尾随零。

float flt = 1F/3;
double dbl = 1D/3;
decimal dcm = 1M/3;
Console.WriteLine("float: {0} double: {1} decimal: {2}", flt, dbl, dcm);

结果:

float: 0.3333333  
double: 0.333333333333333  
decimal: 0.3333333333333333333333333333

896
2018-03-06 11:33



@Thecrocodilehunter:抱歉,但没有。十进制可以表示可以用十进制表示法表示的所有数字,但不能表示例如1/3。 1.0m / 3.0m将评估为0.33333333 ...最后有3个大但有限数量的3s。将它乘以3将不会返回精确的1.0。 - Erik P.
@Thecrocodilehunter:我认为你的准确性和精确度令人困惑。在这种情况下,它们是不同的东西。精度是表示数字的可用位数。精度越高,您需要越少。没有数据类型具有无限精度。 - Igby Largeman
@Thecrocodilehunter:你假设正在测量的值是 究竟  0.1  - 这在现实世界中很少见! 任何 有限存储格式将无限数量的可能值与有限数量的位模式混合。例如, float 会混淆 0.1 和 0.1 + 1e-8,而 decimal 会混淆 0.1 和 0.1 + 1e-29。当然, 在给定范围内,某些值可以以任何格式表示,并且没有精度损失(例如, float 可以存储任何高达1.6e7的整数,但不会丢失精度) - 但这仍然不是 无穷 准确性。 - Daniel Pryden
@Thecrocodilehunter:你错过了我的观点。 0.1 是 不是特别的价值!唯一能做的就是 0.1 比“更好” 0.10000001 是因为 人类 像10号基地一样 float value,如果使用初始化两个值 0.1 一样的方法, 它们都是相同的价值。只是那个价值不会 究竟  0.1  - 这将是 最接近的值 0.1这可以完全表示为 float。当然,二进制花车, (1.0 / 10) * 10 != 1.0,但有十进制浮点数, (1.0 / 3) * 3 != 1.0 无论是。 也不 是 完美 精确。 - Daniel Pryden
@Thecrocodilehunter:你还是不明白。我不知道如何更明白地说这句话:在C中,如果你这样做 double a = 0.1; double b = 0.1; 然后 a == b  将是真的。就是这样 a 和 b 将 都 不完全相同 0.1。在C#中,如果你这样做 decimal a = 1.0m / 3.0m; decimal b = 1.0m / 3.0m; 然后 a == b 也是如此。但在那种情况下, 也不 的 a 也不 b 将 究竟 等于 1/3  - 他们都是平等的 0.3333...。在 都 由于代表性,一些准确性会丢失。你固执地说 decimal 具有“无限”精度,即 假。 - Daniel Pryden


十进制结构严格适用于要求准确性的财务计算,这对于舍入是相对不容忍的。然而,小数不足以用于科学应用,原因如下:

  • 由于物理问题或人工测量的实际限制,在许多科学计算中可以接受一定的精度损失。财务方面的精确度损失是不可接受的。
  • 对于大多数操作,十进制比浮动慢很多(很多),并且对于大多数操作都是双倍的,主要是因为浮点运算是以二进制完成的,而十进制的东西是在基数10中完成的(即浮点数和双精度由FPU硬件处理,例如MMX / SSE ,而小数是用软件计算的)。
  • 尽管它支持更多的精度数字,但Decimal的值范围比double小得多。因此,Decimal不能用于表示许多科学价值。

66
2018-04-13 13:55



如果您正在进行财务计算,您绝对必须滚动自己的数据类型或找到符合您确切需求的好库。金融环境中的准确性由(人类)标准机构定义,并且它们具有关于如何进行计算的非常具体的本地化(在时间和地理上)规则。在.Net中的简单数值数据类型中没有捕获正确舍入等内容。进行计算的能力只是这个难题的一小部分。 - James Moore


enter image description here

有关更多信息,您可以访问此图片的来源:

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/921a8ffc-9829-4145-bdc9-a96c1ec174a5


54
2018-06-07 12:50



-1表示小数是96位。 MSDN清楚地说128。 - Ben Voigt
如果你深入挖掘,则使用102位,存储128位。无法用12个字节来填充它。 - Ben Voigt
您遗漏了最大的差异,即用于十进制类型的基数(十进制存储为基数10,列出的所有其他数字类型都是基数2)。 - BrainSlugs83
在上面的图像或源论坛帖子中没有正确描述Single和Double的值范围。由于我们不能轻易上标文本,请使用插入字符:Single应为10 ^ -45和10 ^ 38,Double应为10 ^ -324和10 ^ 308。此外,MSDN的浮点范围为-3.4x10 ^ 38到+ 3.4x10 ^ 38。在链接更改的情况下,在MSDN上搜索System.Single和System.Double。单: msdn.microsoft.com/en-us/library/b1e65aza.aspx 双: msdn.microsoft.com/en-us/library/678hzkk9.aspx - deegee


float 7位精度

double 有大约15位数的精度

decimal 有大约28位数的精度

如果您需要更高的精确度,请使用double而不是float。 在现代CPU中,两种数据类型具有几乎相同的性能。使用浮动的唯一好处是它们占用的空间更少。只有当你有很多这样的事情时才真正重要。

我发现这很有趣。 每个计算机科学家应该知道的浮点运算


40
2017-08-29 00:06



@RogerLipscombe:我会考虑的 double 适用于那些没有大于32位整数类型的情况下的会计应用程序(基本上只有那些情况),以及 double 被用作好像它是一个53位整数类型(例如,持有一定数量的便士,或整数百分之一的分数)。现在对这类事情没什么用处,但是很多语言在获得64位(或者在某些情况下甚至是32位!)整数数学之前很久就能够使用双精度浮点值。 - supercat
您的答案意味着精度是这些数据类型之间的唯一区别。给定二进制浮点运算通常在中实现 硬件FPU,表现是一个显着的差异。对于某些应用来说,这可能是无关紧要的,但对其他应用来说则至关重要。 - saille
@supercat是 决不 适用于会计应用。因为Double只能近似十进制值(即使在它自己的精度范围内)。这是因为double将值存储为base-2(二进制)中心格式。 - BrainSlugs83
@ BrainSlugs83:使用浮点类型来保存 非全数 数量是不合适的,但历史上,语言的浮点类型可以精确地表示比它们的整数类型所代表的更大的整数值。也许最极端的例子是Turbo-87,其唯一的整数类型被限制在-32768到+32767,但其中 Real IIRC可以用单位精度表示高达1.8E + 19的值。我认为使用会计应用程序会更加合理 Real 代表整数便士而不是...... - supercat
...它尝试使用一堆16位值执行多精度数学运算。对于大多数其他语言而言,差异并不是那么极端,但很长一段时间,语言不常有超过4E9的任何整数类型但是有一个 double 单位精度高达9E15的类型。如果需要存储大于最大可用整数类型的整数,请使用 double 比试图捏造多精度数学更容易更简单,更有效,特别是考虑到处理器有指令执行16x16-> 32或... - supercat


没有人提到这一点

在默认设置中,Floats(System.Single)和double(System.Double)将永远不会使用   溢出检查,而Decimal(System.Decimal)将始终使用   溢出检查。

我的意思是

decimal myNumber = decimal.MaxValue;
myNumber += 1;

发生OverflowException

但这些不是:

float myNumber = float.MaxValue;
myNumber += 1;

double myNumber = double.MaxValue;
myNumber += 1;

29
2018-01-02 13:12



float.MaxValue+1 == float.MaxValue, 就像 decimal.MaxValue+0.1D == decimal.MaxValue。也许你的意思是 float.MaxValue*2? - supercat
@supercar但是decimal.MaxValue + 1 == decimal.MaxValue不是这样 - GorkemHalulu
@supercar decimal.MaxValue + 0.1m == decimal.MaxValue ok - GorkemHalulu
该 System.Decimal 在它变得无法区分整个单元之前抛出异常,但是如果应用程序应该处理例如美元和美分,这可能为时已晚。 - supercat


  1. Double和float可以除以整数零,在编译和运行时都没有异常。
  2. 十进制不能除以整数零。如果这样做,编译将始终失败。

25
2017-07-29 07:21



他们肯定可以!它们还有一些“神奇”值,如无穷大,负无穷大和NaN(不是数字),这使得它在计算斜率时非常有用于检测垂直线......此外,如果你需要在调用浮点数之间做出决定.TryParse,double.TryParse和decimal.TryParse(例如,检测字符串是否为数字),我建议使用double或float,因为它们将正确解析“Infinity”,“ - Infinity”和“NaN” ,而小数则不会。 - BrainSlugs83
汇编 只有在尝试划分文字时才会失败 decimal 零(CS0020),积分文字也是如此。但是,如果运行时十进制值除以零,则会出现异常而不是编译错误。 - Drew Noakes
@ BrainSlugs83但是,您可能不想根据上下文解析“Infinity”或“NaN”。如果开发人员不够严谨,似乎是对用户输入的良好利用。 - Winter


我不会重复已经在其他答案和评论中回答的大量好的(和一些坏的)信息,但我会用一个提示回答你的后续问题:

什么时候会有人使用其中一种?

使用小数表示  值

使用float / double 测量 值

一些例子:

  • 钱(我们数钱还是衡量钱?)

  • 距离(我们计算距离还是测量距离?*)

  • 分数(我们计算分数还是衡量分数?)

我们总是数钱,不应该衡量它。我们通常测量距离。我们经常算得分。

*在某些情况下,我会称之为 名义距离,我们可能确实想要“计算”距离。例如,也许我们正在处理显示到城市的距离的国家标志,我们知道那些距离永远不会超过一个十进制数字(xxx.x km)。


25
2018-04-22 15:18





Decimal,Double和Float变量类型在存储值方面有所不同。精度是主要区别,其中float是单精度(32位)浮点数据类型,double是双精度(64位)浮点数据类型,decimal是128位浮点数据类型。

浮动 - 32位(7位)

双 - 64位(15-16位)

十进制 - 128位(28-29位有效数字)

主要区别是Floats和Doubles是二进制浮点类型,Decimal将值存储为浮点小数点类型。因此,小数具有更高的精度,通常用于需要高精度的货币(金融)或科学计算应用中。但在性能方面,Decimals比double和float类型慢。

十进制可以100%准确地表示十进制格式精度内的任何数字,而Float和Double则无法准确表示所有数字,甚至是各自格式精度的数字。

十进制

在财务应用或科学计算的情况下,最好使用十进制类型,因为它可以提供高水平的准确性并且易于避免舍入误差

除处理货币外,双类型可能是实际值最常用的数据类型。

浮动

它主要用于图形库,因为对处理能力的要求非常高,也使用了可以承受舍入误差的情况。


24
2018-06-19 04:34



哇小数是128位? TIL - Gaspa79


如前所述,整数是整数。他们无法存储点数,例如.7,.42和.007。如果您需要存储非整数的数字,则需要使用不同类型的变量。您可以使用double类型或float类型。您以完全相同的方式设置这些类型的变量:而不是使用单词 int,你输入 double 要么 float。喜欢这个:

float myFloat;
double myDouble;

float 是“浮点”的缩写,只是意味着最后有一点点的数字。)

两者之间的差异在于它们可以容纳的数字的大小。对于 float,您的号码最多可以包含7位数字。对于 doubles,最多可以有16位数字。更确切地说,这是官方规模:

float:  1.5 × 10^-45  to 3.4 × 10^38  
double: 5.0 × 10^-324 to 1.7 × 10^308

float 是一个32位数字,和 double 是一个64位数字。

双击新按钮以获取代码。将以下三行添加到按钮代码中:

double myDouble;
myDouble = 0.007;
MessageBox.Show(myDouble.ToString());

暂停程序并返回编码窗口。改变这一行:

myDouble = 0.007;
myDouble = 12345678.1234567;

运行程序并单击双击按钮。消息框正确显示数字。但是,最后添加另一个数字,C#将再次向上或向下舍入。道德是如果你想要准确,小心四舍五入!


23
2018-05-22 12:05



赞成在您的示例中使用.42和.007。 :D - PruitIgoe
你提到的“点东西”通常被称为数字的“小数部分”。 “浮点”并不意味着“一个有点意义的数字”;但相反,“浮点”区分数字的类型,而不是“固定点”数字(也可以存储小数值);不同之处在于精度是固定的还是浮动的。 - 浮点数为您提供了更大的动态范围值(最小值和最大值),但是以精度为代价,而固定点数则以范围为代价为您提供恒定的精度。 - BrainSlugs83


这对我来说是一个有趣的线索,因为今天,我们刚刚遇到了一个令人讨厌的小虫子 decimal 精度低于a float

在我们的C#代码中,我们从Excel电子表格中读取数值,并将它们转换为 decimal,然后发送 decimal 回到服务保存到 SQL Server 数据库。

Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
    decimal value = 0;
    Decimal.TryParse(cellValue.ToString(), out value);
}

现在,为 几乎全部 我们的Excel值,这非常有效。但对于一些非常小的Excel值,使用 decimal.TryParse 完全失去了价值。一个这样的例子是

  • cellValue = 0.00006317592

  • Decimal.TryParse(cellValue.ToString(),out value); //会回来 0

奇怪的是,解决方案是将Excel值转换为 double 首先,然后进入 decimal

Microsoft.Office.Interop.Excel.Range cell = …
object cellValue = cell.Value2;
if (cellValue != null)
{
    double valueDouble = 0;
    double.TryParse(cellValue.ToString(), out valueDouble);
    decimal value = (decimal) valueDouble;
    …
}

即使 double 精度低于a decimal,这实际上确保了小数字仍然可以被识别。因为某些原因, double.TryParse 实际上能够检索到这么小的数字,而 decimal.TryParse 将它们设置为零。

奇。很奇怪。


13
2018-04-16 09:23



出于好奇,cellValue.ToString()的原始值是多少? Decimal.TryParse(“0.00006317592”,out val)似乎有效...... - micahtan
-1不要误解我的意思,如果这是真的,那很有意思,但这是一个单独的问题,它肯定不是这个问题的答案。 - weston
也许是因为Excel单元格返回一个double,而ToString()值是“6.31759E-05”,因此decimal.Parse()不喜欢这种表示法。我敢打赌,如果你检查了Decimal.TryParse()的返回值,它将是假的。 - SergioL
@weston答案通常填补他们错过的细微差别来补充其他答案。这个答案强调了解析方面的差异。这是问题的答案! - Robino
呃...... decimal.Parse("0.00006317592") 工作 - 你还有别的东西在继续。 - 可能是科学记数法? - BrainSlugs83