.NET 中的 decimal
、float
和 double
有什么区别?
什么时候有人会使用其中之一?
float
和 double
是 floating binary point types(float
是 32 位;double
是 64 位)。换句话说,它们代表这样的数字:
10001.10010110011
二进制数和二进制点的位置都在值内编码。
decimal
是一个 floating decimal point type。换句话说,它们代表这样的数字:
12345.65789
同样,decimal 点的数字和位置都被编码在值中——这就是使 decimal
仍然是浮点类型而不是定点类型的原因。
需要注意的重要一点是,人类习惯于以十进制形式表示非整数,并期望以十进制表示的精确结果;并非所有十进制数都可以用二进制浮点数精确表示——例如 0.1——因此,如果您使用二进制浮点值,您实际上会得到 0.1 的近似值。当使用浮点小数点时,您仍然会得到近似值——例如,无法精确表示 1 除以 3 的结果。
至于什么时候用:
对于“自然精确小数”的值,最好使用小数。这通常适用于人类发明的任何概念:财务价值是最明显的例子,但也有其他例子。例如,考虑给潜水员或溜冰者的分数。
对于更多的自然产物,无论如何都无法准确测量的值,float/double 更合适。例如,科学数据通常会以这种形式表示。在这里,原始值一开始就不是“十进制精度”,因此保持“十进制精度”对于预期结果并不重要。浮点二进制点类型比小数要快得多。
精度是主要区别。
Float - 7 位(32 位)
Double-15-16 位(64 位)
Decimal -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
0.1
- 这在现实世界中很少见! 任何 有限存储格式会将无限数量的可能值合并为有限数量的位模式。例如,float
将合并 0.1
和 0.1 + 1e-8
,而 decimal
将合并 0.1
和 0.1 + 1e-29
。当然,在给定的范围内,某些值可以以任何格式表示,精度为零(例如,float
可以存储高达 1.6e7 的任何整数,精度为零)——但这就是仍然不是无限准确度。
0.1
不是特殊值!使 0.1
比 0.10000001
“更好”的唯一原因是,人类喜欢以 10 为底数。即使使用 float
值,如果用 0.1
初始化两个值相同方式,它们都将是相同的值。只是该值不会完全 0.1
——它将是最接近可以精确表示为 float
的 0.1
的值。当然,对于二进制浮点数,(1.0 / 10) * 10 != 1.0
,但对于十进制浮点数,(1.0 / 3) * 3 != 1.0
也是。 两者都没有是完全精确的。
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
具有“无限”精度,这是 false。
+---------+----------------+---------+----------+---------------------------------------------------------+
| C# | .Net Framework | Signed? | Bytes | Possible Values |
| Type | (System) type | | Occupied | |
+---------+----------------+---------+----------+---------------------------------------------------------+
| sbyte | System.Sbyte | Yes | 1 | -128 to 127 |
| short | System.Int16 | Yes | 2 | -32,768 to 32,767 |
| int | System.Int32 | Yes | 4 | -2,147,483,648 to 2,147,483,647 |
| long | System.Int64 | Yes | 8 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
| byte | System.Byte | No | 1 | 0 to 255 |
| ushort | System.Uint16 | No | 2 | 0 to 65,535 |
| uint | System.UInt32 | No | 4 | 0 to 4,294,967,295 |
| ulong | System.Uint64 | No | 8 | 0 to 18,446,744,073,709,551,615 |
| float | System.Single | Yes | 4 | Approximately ±1.5e-45 to ±3.4e38 |
| | | | | with ~6-9 significant figures |
| double | System.Double | Yes | 8 | Approximately ±5.0e-324 to ±1.7e308 |
| | | | | with ~15-17 significant figures |
| decimal | System.Decimal | Yes | 16 | Approximately ±1.0e-28 to ±7.9e28 |
| | | | | with 28-29 significant figures |
| char | System.Char | N/A | 2 | Any Unicode character (16 bit) |
| bool | System.Boolean | N/A | 1 / 2 | true or false |
+---------+----------------+---------+----------+---------------------------------------------------------+
See here for more information。
Decimal 结构严格适用于需要精确度的金融计算,相对不能容忍四舍五入。然而,小数对于科学应用来说是不够的,原因如下:
由于被测量的物理问题或人工制品的实际限制,在许多科学计算中,一定程度的精度损失是可以接受的。在金融领域,精度损失是不可接受的。
对于大多数操作来说,十进制比浮点和双精度要慢得多(很多),主要是因为浮点运算是以二进制完成的,而十进制的东西是以 10 为底完成的(即浮点和双精度由 FPU 硬件处理,例如 MMX/SSE ,而小数是在软件中计算的)。
尽管 Decimal 支持更多位数的精度,但 Decimal 的值范围比 double 小得令人无法接受。因此,Decimal 不能用于表示许多科学值。
我不会重复其他答案和评论中已经回答的大量好的(和一些坏的)信息,但我会用提示回答您的后续问题:
什么时候有人会使用其中之一?
对计数值使用小数
对测量值使用浮点数/双精度值
一些例子:
钱(我们是数钱还是量钱?)
距离(我们计算距离还是测量距离?*)
分数(我们计算分数还是衡量分数?)
我们总是数钱,永远不应该衡量它。我们通常测量距离。我们经常计算分数。
* 在某些情况下,我称之为标称距离,我们可能确实想要“计算”距离。例如,也许我们正在处理显示到城市距离的国家标志,我们知道这些距离永远不会超过一位十进制数字(xxx.x km)。
float
7 位精度
double
的精度约为 15 位
decimal
的精度约为 28 位
如果您需要更高的精度,请使用 double 而不是 float。在现代 CPU 中,两种数据类型的性能几乎相同。使用浮动的唯一好处是它们占用的空间更少。只有当你有很多时,实际上才重要。
我发现这很有趣。 What Every Computer Scientist Should Know About Floating-Point Arithmetic
double
被用作 53 位的情况下(基本上只有那些情况),我会认为 double
适合会计应用程序整数类型(例如,存放整数个便士,或整数个百分之一美分)。现在这些东西用处不大,但许多语言早在获得 64 位(或者在某些情况下甚至是 32 位!)整数数学之前就获得了使用双精度浮点值的能力。
Real
可以 IIRC 以单位精度表示高达 1.8E+19 的值。我认为对于会计应用程序来说,使用 Real
来表示整数比...
double
类型的语言非常普遍。如果需要存储大于可用的最大整数类型的整数,使用 double
往往比试图捏造多精度数学更简单、更有效,特别是考虑到处理器有执行 16x16-> 的指令;32 或...
没有人提到过
在默认设置中,浮点数 (System.Single) 和双精度数 (System.Double) 永远不会使用溢出检查,而十进制 (System.Decimal) 将始终使用溢出检查。
我是说
decimal myNumber = decimal.MaxValue;
myNumber += 1;
抛出溢出异常。
但这些不会:
float myNumber = float.MaxValue;
myNumber += 1;
&
double myNumber = double.MaxValue;
myNumber += 1;
float.MaxValue+1 == float.MaxValue
,就像 decimal.MaxValue+0.1D == decimal.MaxValue
。也许您的意思是 float.MaxValue*2
?
System.Decimal
在它变得无法区分整个单位之前抛出异常,但如果应用程序应该处理美元和美分,那可能为时已晚。
如前所述,整数是整数。他们无法存储点,例如 .7、.42 和 .007。如果您需要存储不是整数的数字,则需要不同类型的变量。您可以使用双精度型或浮点型。您以完全相同的方式设置这些类型的变量:键入 double
或 float
,而不是使用单词 int
。像这样:
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# 将再次向上或向下舍入。道德是如果你想要准确,小心四舍五入!
在编译和运行时,双精度和浮点数都可以被整数零除而无一例外。小数不能除以整数零。如果你这样做,编译总是会失败。
decimal
除以零 (CS0020) 时才会失败,整数文字也是如此。但是,如果运行时十进制值除以零,您将得到异常而不是编译错误。
浮动:±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 位有效数字)
decimal
实际上是以十进制格式存储的(与以 2 为底的格式相反;因此它不会因为两个数字系统之间的转换而丢失或舍入数字);此外,decimal
没有特殊值的概念,例如 NaN、-0、∞ 或 -∞。
Decimal、Double 和 Float 变量类型在存储值的方式上有所不同。精度是主要区别,其中 float 是单精度(32 位)浮点数据类型,double 是双精度(64 位)浮点数据类型,decimal 是 128 位浮点数据类型。
浮点数 - 32 位(7 位)
双 - 64 位(15-16 位)
十进制 - 128 位(28-29 位有效数字)
更多关于...the difference between Decimal, Float and Double
这对我来说是一个有趣的话题,因为今天,我们刚刚遇到了一个令人讨厌的小错误,涉及 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
会完全失去该值。一个这样的例子是
单元格值 = 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
的精度低于 decimal
,但这实际上确保了仍然可以识别小数字。出于某种原因,double.TryParse
实际上能够检索到如此小的数字,而 decimal.TryParse
会将它们设置为零。
奇怪的。很奇怪。
decimal.Parse("0.00006317592")
有效 - 你还有其他事情要做。 -- 可能是科学记数法?
对于内存和性能都至关重要的游戏和嵌入式系统等应用程序,float 通常是首选的数字类型,因为它速度更快,大小只有 double 类型的一半。整数曾经是首选的武器,但浮点性能在现代处理器中已经超过了整数。十进制就出来了!
所有这些类型的问题是存在一定的不精确性,并且这个问题可能会出现在小十进制数上,如下例所示
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,bLower 包含 FALSE,这是一个很好的答案。
在 double 中,问题在于 fMean-fDelta = 1.09999999999 低于 1.1。
警告:我认为其他数字肯定存在同样的问题,因为 Decimal 只是精度更高的双精度数,并且精度总是有限制的。
实际上,Double、Float 和 Decimal 对应 COBOL 中的 BINARY 十进制!
令人遗憾的是,在 COBOL 中实现的其他数字类型在 .Net 中不存在。对于那些不知道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)
简单来说:
Decimal、Double 和 Float 变量类型在存储值的方式上有所不同。精度是主要区别(注意这不是单一的区别),其中 float 是单精度(32 位)浮点数据类型,double 是双精度(64 位)浮点数据类型,decimal 是 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)
/==========================================================================================
这里
漂浮
双倍的
十进制
Decimal
适用于金融应用程序,并且是在 Decimal
和 Double
之间做出决定时使用的主要标准。例如,Double
精度不足以满足科学应用的情况很少见(而 Decimal
由于范围有限,通常不适合用于科学应用)。
它们之间的主要区别在于精度。
float 是一个 32 位数字
double 是一个 64 位数字
十进制是一个 128 位的数字
在 .Net (c#) 中定义 Decimal、Float 和 Double
您必须将值提及为:
Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;
并检查结果。
并且每个占用的字节数是
Float - 4
Double - 8
Decimal - 12
float
/double
通常不将数字表示为101.101110
,通常它表示为1101010 * 2^(01010010)
- 一个指数float
是 C# 别名关键字,而不是 .Net 类型。它是System.Single
..single
和double
是浮点二进制点类型。