.NET中的decimalfloatdouble有什么区别?

何时有人使用其中之一?

评论

有趣的文章zetcode.com/lang/csharp/datatypes

相关:sandbox.mc.edu/~bennet/cs110/flt/dtof.html

#1 楼

floatdouble是浮点二进制点类型。换句话说,它们表示这样的数字:

10001.10010110011


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

decimal是浮点小数点类型。换句话说,它们代表这样的数字:

12345.65789


再次,数字和小数点的位置都编码在该值内–这就是使decimal

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

关于何时使用的内容:


对于“自然精确的小数”值,最好使用decimal。这通常适用于人类发明的任何概念:财务价值是最明显的例子,但也有其他一些例子。例如,考虑给潜水员或溜冰者的分数。
对于那些更多的自然制品,无论如何也无法真正进行精确测量,float / double更合适。例如,科学数据通常以这种形式表示。在此,原始值一开始就不会是“十进制精度”,因此对于预期结果而言,保持“十进制精度”并不重要。浮点二进制点类型比十进制小得多。


评论


浮点数/双精度数通常不表示为101.101110,通常表示为1101010 * 2 ^(01010010)-指数

–明威塞缪尔
14年8月13日在21:50

@Hazzard:这就是答案的“和二进制点的位置”部分的意思。

–乔恩·斯基特(Jon Skeet)
14年8月13日在21:57

令我惊讶的是,float是C#别名关键字,而不是.Net类型。它是System.Single .. single和double是浮点二进制点类型。

–布雷特·卡斯威尔(Brett Caswell)
15年2月3日在15:48

@BKSpurgeon:嗯,只能以与您可以说一切都是二进制类型的方式相同,在这种情况下,它变成一个相当无用的定义。小数是十进制类型,因为它是一个以整数有效位数和小数位数表示的数字,因此结果为有效位数* 10 ^小数位数,而float和double是有效位数* 2 ^小数位数。取一个用十进制表示的数字,然后将小数点向右移动足够远,以得到一个整数以计算出有效位数和小数位数。对于浮点/双精度,您将从以二进制形式写的数字开始。

–乔恩·斯基特(Jon Skeet)
15年11月26日在7:20

另一个区别:float 32位;双64位;和十进制128位。

–大卫
16年8月29日在15:08

#2 楼

精度是主要区别。

浮点数-7位数字(32位)

双15-16位数字(64位)

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

小数位数具有更高的精度,通常在要求高度准确性的金融应用程序中使用。小数要比double / float慢得多(在某些测试中,多达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


评论


@Thecrocodilehunter:对不起,但是没有。十进制可以表示所有可以用十进制表示法表示的数字,但不能表示1/3。 1.0m / 3.0m的取值为0.33333333 ...,但末尾有3s,但数量有限。将其乘以3将不会返回精确的1.0。

– Erik P.
11年11月29日在21:14

@Thecrocodilehunter:我认为您混淆了准确性和精确性。在这种情况下,它们是不同的事物。精度是可用来表示数字的位数。精度越高,您需要舍入的次数就越少。没有数据类型具有无限的精度。

–伊比·拉格曼(Igby Largeman)
2012年1月6日17:42



@Thecrocodilehunter:您假设要测量的值正好是0.1,这在现实世界中很少见!任何有限的存储格式都会将无限数量的可能值与有限数量的位模式混合。例如,float将混淆0.1和0.1 + 1e-8,而十进制将混淆0.1和0.1 + 1e-29。当然,在给定范围内,某些值可以以零精度损失的任何格式表示(例如,float可以以零精度损失存储高达1.6e7的任何整数)-但这仍然不是无限精度。

–丹尼尔·普赖登(Daniel Pryden)
2012年1月10日的1:49

@Thecrocodilehunter:你错过了我的观点。 0.1不是一个特殊的值!使0.1比0.10000001“更好”的唯一原因是,人类像base10。即使使用float值,如果以相同的方式用0.1初始化两个值,则它们都将是相同的值。只是该值不会正好为0.1-它是最接近0.1的值,可以精确地表示为浮点数。当然,二进制浮点数为(1.0 / 10)* 10!= 1.0,但十进制浮点数为(1.0 / 3)* 3!= 1.0。两者都不是完全精确的。

–丹尼尔·普赖登(Daniel Pryden)
2012年1月10日18:27

@Thecrocodilehunter:你还是不明白。我不知道该怎么说:在C中,如果您将a = 0.1加倍;双b = 0.1;那么a == b将为真。只是a和b都不会完全等于0.1。在C#中,如果您进行十进制运算,则a = 1.0m / 3.0m;十进制b = 1.0m / 3.0m;那么a == b也将成立。但是在那种情况下,a和b都不会完全等于1/3,它们都等于0.3333...。在两种情况下,由于表示的原因,都会失去一些准确性。您固执地说,十进制具有“无限”的精度,这是错误的。

–丹尼尔·普赖登(Daniel Pryden)
2012年1月10日19:29



#3 楼

十进制结构严格适合需要准确性的财务计算,而这些准确性相对不能四舍五入。小数不足以用于科学应用,但是由于以下几个原因:


由于物理问题或被测量工件的实际限制,在许多科学计算中都可以接受一定程度的精度损失。在金融中,精度损失是不可接受的。
对于大多数操作,小数比浮点和双精度慢很多(很多),主要是因为浮点运算是用二进制完成的,而十进制的填充是用基数10完成的(即浮点和double由FPU硬件(例如MMX / SSE)处理,而十进制是在软件中计算的。
十进制的数值范围比double小得多,这是不可接受的,尽管事实是它支持更多位数的精度。因此,十进制不能用来表示许多科学价值。


评论


如果您要进行财务计算,则绝对必须使用自己的数据类型或找到符合您确切需求的良好库。财务环境中的准确性由(人类)标准机构定义,并且它们具有关于如何进行计算的非常特定的本地化规则(时间和地理位置)。 .Net中的简单数字数据类型未捕获诸如正确舍入之类的内容。进行计算的能力只是难题的一小部分。

–詹姆斯·摩尔
16年4月6日在16:59

#4 楼

+---------+----------------+---------+----------+---------------------------------------------+
| C#      | .Net Framework | Signed? | Bytes    | Possible Values                             |
| Type    | (System) type  |         | Occupied |                                             |
+---------+----------------+---------+----------+---------------------------------------------+
| sbyte   | System.Sbyte   | Yes     | 1        | -128 to 127                                 |
| short   | System.Int16   | Yes     | 2        | -32768 to 32767                             |
| int     | System.Int32   | Yes     | 4        | -2147483648 to 2147483647                   |
| long    | System.Int64   | Yes     | 8        | -9223372036854775808 to 9223372036854775807 |
| byte    | System.Byte    | No      | 1        | 0 to 255                                    |
| ushort  | System.Uint16  | No      | 2        | 0 to 65535                                  |
| uint    | System.UInt32  | No      | 4        | 0 to 4294967295                             |
| ulong   | System.Uint64  | No      | 8        | 0 to 18446744073709551615                   |
| float   | System.Single  | Yes     | 4        | Approximately ±1.5 x 10-45 to ±3.4 x 1038   |
|         |                |         |          |  with 7 significant figures                 |
| double  | System.Double  | Yes     | 8        | Approximately ±5.0 x 10-324 to ±1.7 x 10308 |
|         |                |         |          |  with 15 or 16 significant figures          |
| decimal | System.Decimal | Yes     | 12       | Approximately ±1.0 x 10-28 to ±7.9 x 1028   |
|         |                |         |          |  with 28 or 29 significant figures          |
| char    | System.Char    | N/A     | 2        | Any Unicode character (16 bit)              |
| bool    | System.Boolean | N/A     | 1 / 2    | true or false                               |
+---------+----------------+---------+----------+---------------------------------------------+


有关更多信息,请参见此处。

评论


您没有留出最大的差异,该差异是十进制类型使用的基数(十进制存储为10的底数,列出的所有其他数字类型均为2的底数)。

– BrainSlugs83
15年3月14日在22:55

上图或源论坛帖子中未正确显示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
2015年6月22日19:18

十进制为128位...表示它占用16个字节而不是12个字节

–user1477332
18-10-23在3:29

#5 楼

我不会重申在其他答案和评论中已经回答过的大量好(和坏)信息,但是我将用提示提示您的后续问题:


何时使用一个其中的什么?


使用小数表示计数值

使用浮点数/双精度表示测量值

一些示例:


金钱(我们是数钱还是测量钱?)
距离(我们是数数还是测量距离?*)
得分(我们是数分数还是度量分数?)

我们总是数钱,永远不要衡量。我们通常测量距离。我们经常计算分数。

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

评论


我真的很喜欢这个答案,尤其是“我们数钱还是数钱?”这个问题。但是,除了金钱,我想不出任何“计数”的东西,而不仅仅是整数。我看到一些使用十进制的应用程序仅仅是因为double的有效位数太少了。换句话说,可以使用十进制,因为C#没有四重类型en.wikipedia.org/wiki/Quadruple-precision_floating-point_format

–约翰·亨克尔(John Henckel)
19年4月4日在18:55

#6 楼

float具有7位精度

double具有约15位精度

decimal具有约28位精度

如果需要更好的精度,请使用用double代替float。
在现代CPU中,两种数据类型的性能几乎相同。使用float的唯一好处是它们占用的空间更少。实际上只有当您有很多时,它们才有意义。

我发现这很有趣。每位计算机科学家都应了解的浮点算法

评论


@RogerLipscombe:在没有大于32位的整数类型可用的情况下(并且基本上仅在那些情况下),并且在使用double时,就好像它是53位整数类型(例如,持有一便士的总数,或百分之一的总数)。如今,此类语言用途不大,但是许多语言早在获得64位(甚至在某些情况下甚至是32位!)整数数学之前就已经能够使用双精度浮点值。

–超级猫
2014年5月29日17:57

您的答案暗示精度是这些数据类型之间的唯一区别。给定二进制浮点算法通常是在硬件FPU中实现的,因此性能会有很大差异。这对于某些应用程序可能无关紧要,但对于其他应用程序则至关重要。

–saille
2015年1月15日在3:16



@supercat double在会计应用程序中永远是不合适的。因为Double只能近似十进制值(即使在其自身精度范围内)。这是因为double以以2为基(二进制)为中心的格式存储值。

– BrainSlugs83
15年3月14日在22:50

@ BrainSlugs83:使用浮点类型来保存非整数数量是不适当的,但是从历史上看,语言具有浮点类型可以精确表示比整数类型更大的整数值是很常见的。也许最极端的例子是Turbo-87,其唯一的整数类型限制为-32768到+32767,但其Real可以IIRC表示的精度高达1.8E + 19,单位精度。我认为,对于会计应用程序来说,使用Real来代表全部便士要比...更明智。

–超级猫
2015年3月15日19:45



...以便它尝试使用一堆16位值执行多精度数学运算。对于大多数其他语言,这种差异并不是那么严重,但是很长一段时间以来,对于语言而言,不具有超出4E9的任何整数类型而是具有单位精度高达9E15的双精度类型是非常普遍的。如果需要存储大于最大可用整数类型的整数,则使用double会比尝试进行多精度数学运算更简单,更高效,尤其是考虑到处理器具有执行16x16-> 32或...

–超级猫
2015年3月15日19:47



#7 楼

没有人提到


在默认设置下,浮点数(System.Single)和双精度数(System.Double)在十进制(System.Decimal)时将永远不会使用
溢出检查。将始终使用
溢出检查。


我的意思是

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


抛出OverflowException。 />但是这些却不行:

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




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


评论


float.MaxValue + 1 == float.MaxValue,就像十进制.MaxValue + 0.1D ==十进制.MaxValue。也许您的意思是float.MaxValue * 2之类的?

–超级猫
2015年1月14日,0:21



@supercar但是,并非十进制.MaxValue + 1 ==十进制.MaxValue

– GorkemHalulu
2015年1月14日在6:12



@supercar十进制.MaxValue + 0.1m ==十进制.MaxValue好的

– GorkemHalulu
15年1月14日在6:19

System.Decimal在无法区分整个单元之前会抛出一个异常,但是如果应用程序应该处理例如美元和美分,可能为时已晚。

–超级猫
15年1月14日在16:15

#8 楼

如前所述,整数是整数。他们无法存储点,例如.7,.42和.007。如果需要存储不是整数的数字,则需要另一种类型的变量。您可以使用double类型或float类型。您可以通过完全相同的方式设置这些类型的变量:键入intdouble,而不使用单词float。像这样:

float myFloat;
double myDouble;


float是“浮点数”的缩写,仅表示末尾带有数字的数字。)

两者之间的区别在于它们可以容纳的数字大小。对于float,您的电话号码最多可以包含7位数字。对于double,最多可以包含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#将再次向上或向下取整。道义是如果您要准确性,请四舍五入!

评论


您提到的“指向某物”通常称为数字的“小数部分”。 “浮点数”并不表示“末尾带有数字的数字”;但是相反,“浮点数”区分数字的类型,而不是“定点数”(也可以存储小数)。区别在于精度是固定的还是浮动的。 -浮点数为您提供更大的动态范围值(最小值和最大值),而以精度为代价,而定点数为您提供了恒定的精度,而代价是范围。

– BrainSlugs83
17-09-16在1:09



#9 楼


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


评论


他们肯定可以!它们还具有几个“魔术”值,例如Infinity,Negative Infinity和NaN(非数字),这对于在计算坡度时检测垂直线非常有用...此外,如果需要在调用float之间进行选择.TryParse,double.TryParse和decimal.TryParse(例如,检测字符串是否为数字),我建议使用double或float,因为它们会正确解析“ Infinity”,“-Infinity”和“ NaN” ,而十进制则不会。

– BrainSlugs83
2011年6月23日19:29



仅当您尝试将文字十进制数除以零(CS0020)时,编译才会失败,并且整数文字也是如此。但是,如果运行时十进制值除以零,则会得到异常而不是编译错误。

–德鲁·诺克斯(Drew Noakes)
16年11月18日在0:24

@ BrainSlugs83但是,根据上下文,您可能不想解析“ Infinity”或“ NaN”。如果开发人员不够严谨,似乎可以很好地利用它来进行用户输入。

–冬天
17年5月17日在1:00

#10 楼


浮动:±1.5 x 10 ^ -45至±3.4 x 10 ^ 38(〜7位有效数字
双精度:±5.0 x 10 ^ -324至±1.7 x 10 ^ 308(15-16位有效数字)
小数:±1.0 x 10 ^ -28至±7.9 x 10 ^ 28(28-29有效数字)


评论


区别不只是精度。 -十进制实际上是以十进制格式存储的(相对于基数2;因此不会由于两个数字系统之间的转换而丢失或舍入数字);另外,十进制没有特殊值的概念,例如NaN,-0,∞或-∞。

– BrainSlugs83
17/09/16在1:19



#11 楼

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

浮点数-32位(7位数字)

双精度-64位(15-16位数字)

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

更多有关...小数,浮点数和双精度之间的区别

#12 楼

这对我来说是一个有趣的线程,因为今天,我们遇到了一个讨厌的小错误,涉及到decimal的精度低于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(),出值); //将返回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的精度比decimal的精度低,但这实际上确保了仍然可以识别出少量数字。由于某种原因,double.TryParse实际上能够检索到如此小的数字,而decimal.TryParse会将它们设置为零。

奇怪。很奇怪。

评论


出于好奇,cellValue.ToString()的原始值是什么? Decimal.TryParse(“ 0.00006317592”,val)似乎可以工作...

–米卡丹
2012年8月27日23:57

-1不要误会我的意思,如果是真的,这很有趣,但这是一个单独的问题,它肯定不是该问题的答案。

–weston
13年5月22日在14:19

可能是因为Excel单元格返回了double,并且ToString()的值为“ 6.31759E-05”,因此decimal.Parse()不喜欢这种表示法。我敢打赌,如果您检查了Decimal.TryParse()的返回值,那将是错误的。

– SergioL
14-10-15在20:44

@weston答案通常通过填写他们错过的细微差别来补充其他答案。该答案突出说明了解析方面的差异。这是对这个问题的答案!

–罗比诺
15年5月20日在15:52

呃... decimal.Parse(“ 0.00006317592”)起作用了–您还有其他事情在进行。 -可能是科学记数法吗?

– BrainSlugs83
17/09/16在1:15



#13 楼

对于内存和性能都至关重要的游戏和嵌入式系统之类的应用程序,浮点数通常是首选的数字类型,因为它速度更快,是两倍大小的一半。整数曾经是首选武器,但浮点性能已超过现代处理器中的整数。十进制就正确了!

评论


几乎所有现代系统,甚至包括手机,都具有两倍的硬件支持。如果您的游戏甚至具有简单的物理原理,您也会注意到double和float的巨大区别。 (例如,在一个简单的Asteroids克隆中计算速度/摩擦力,加倍允许加速度比浮动更流畅地流动。-似乎无关紧要,但完全可以。)

– BrainSlugs83
17/09/16在1:22



双精度也是浮点数的两倍,这意味着您需要读取两倍的数据,这会损害您的缓存性能。与往常一样,进行测量并相应地进行。

– yoyo
17年9月22日在17:53

#14 楼

所有这些类型的问题都是存在一定的不准确性
,并且使用小十进制数可能会出现此问题,如以下示例中所示。

Dim fMean as Double = 1.18
Dim fDelta as Double = 0.08
Dim fLimit as Double = 1.1

If fMean - fDelta < fLimit Then
    bLower = True
Else
    bLower = False
End If


问题: bLower变量包含哪个值?

答案:在32位计算机上,bLower包含TRUE !!!

如果我将Double替换为Decimal,则bLower包含FALSE,这很好答案。

双重,问题是fMean-fDelta = 1.09999999999,它比1.1低。小数只是精度更高的双精度数,精度总是有极限的。

实际上,双精度,浮点数和小数对应于COBOL中的BINARY十进制!

很遗憾.Net中不存在在COBOL中实现的其他数字类型。对于不了解COBOL的用户,COBOL中存在以下数字类型

BINARY or COMP like float or double or decimal
PACKED-DECIMAL or COMP-3 (2 digit in 1 byte)
ZONED-DECIMAL (1 digit in 1 byte) 


#15 楼

用简单的话来说:


Decimal,Double和Float变量类型在存储值的方式上是不同的。
精度是主要区别(注意这不是唯一的区别),其中float是单精度(32位)浮点数据类型,double是双精度(64位)浮点数据类型,而十进制是一个128位浮点数据类型。
汇总表:


/==========================================================================================
    Type       Bits    Have up to                   Approximate Range 
/==========================================================================================
    float      32      7 digits                     -3.4 × 10 ^ (38)   to +3.4 × 10 ^ (38)
    double     64      15-16 digits                 ±5.0 × 10 ^ (-324) to ±1.7 × 10 ^ (308)
    decimal    128     28-29 significant digits     ±7.9 x 10 ^ (28) or (1 to 10 ^ (28)
/==========================================================================================

您可以在此处阅读更多信息,浮点,双精度和十进制。

评论


现有答案尚未涵盖的答案是什么?顺便说一句,您在“十进制”行中的“或”是不正确的:您要从中复制的网页中的斜杠表示分隔而不是替代。

–马克·迪金森(Mark Dickinson)
18年2月10日在12:15

我强烈认为精度是主要区别。主要区别在于基数:十进制浮点数与二进制浮点数。这种差异是使Decimal适用于金融应用程序的原因,并且是在Decimal和Double之间做出选择时要使用的主要标准。例如,很少有Double精度不足以用于科学应用(由于Decimal的范围有限,因此通常不适合科学应用)。

–马克·迪金森(Mark Dickinson)
18年2月10日在12:28

#16 楼

两者之间的主要区别在于精度。

float32-bit编号,double64-bit编号,decimal128-bit编号。

#17 楼


十进制128位(28-29位有效数字)
对于金融应用程序,最好使用
十进制类型,因为它可以提供较高的准确性,并且易于避免舍入错误
将十进制用于需要精度的非整数数学(例如货币和货币)
双64位(15-16位数字)
双精度类型可能是实数值最常用的数据类型,除了处理金钱。
在不需要最精确答案的非整数数学中使用double。
浮点数32位(7位数字)
它主要用于图形库中,因为对处理能力的要求很高,
还经常使用会导致舍入误差的情况。

Decimalsdouble/float慢得多。

如果没有强制转换,则无法比较DecimalsFloats/Doubles,而FloatsDoubles可以。

Decimals还允许编码或尾随零。

#18 楼

要在.Net(c#)中定义小数,浮点和双精度,必须将值提及为:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;

并检查结果。
每个字节占用的字节数是
Float - 4
Double - 8
Decimal - 12