在.NET中,十进制、浮点和双精度之间有什么区别?

什么时候有人会用这些?


当前回答

这对我来说是一个有趣的线索,因为今天,我们刚刚遇到了一个令人讨厌的小错误,关于十进制比浮点精度低。

在我们的C#代码中,我们从Excel电子表格中读取数字值,将其转换为十进制,然后将该十进制发送回服务以保存到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.00006317592Decimal.TryParse(cellValue.ToString(),out值);//将返回0

奇怪的是,解决方案是先将Excel值转换为双精度值,然后再转换为十进制值:

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的精度低于十进制,这实际上确保了小数字仍然可以被识别。由于某种原因,double.TryParse实际上能够检索这样的小数字,而decimal.TryPars将它们设置为零。

古怪的非常奇怪。

其他回答

精度是主要区别。

浮点-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

这对我来说是一个有趣的线索,因为今天,我们刚刚遇到了一个令人讨厌的小错误,关于十进制比浮点精度低。

在我们的C#代码中,我们从Excel电子表格中读取数字值,将其转换为十进制,然后将该十进制发送回服务以保存到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.00006317592Decimal.TryParse(cellValue.ToString(),out值);//将返回0

奇怪的是,解决方案是先将Excel值转换为双精度值,然后再转换为十进制值:

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的精度低于十进制,这实际上确保了小数字仍然可以被识别。由于某种原因,double.TryParse实际上能够检索这样的小数字,而decimal.TryPars将它们设置为零。

古怪的非常奇怪。

在.Net(c#)中定义十进制、浮点和双精度

您必须将值提到为:

Decimal dec = 12M/6;
Double dbl = 11D/6;
float fl = 15F/6;

并检查结果。

每个占用的字节为

Float - 4
Double - 8
Decimal - 12
+---------+----------------+---------+----------+---------------------------------------------------------+
| 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                                           |
+---------+----------------+---------+----------+---------------------------------------------------------+

请参阅此处了解更多信息。

float(System.Single的C#别名)和double(System.double的C#别名。float为32位;double是64位。换句话说,它们表示如下数字:

10001.10010110011

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

decimal(System.decimal的C#别名)是浮点小数点类型。换句话说,它们表示如下数字:

12345.65789

同样,小数点的数字和位置都编码在值中——这使得小数点仍然是浮点类型而不是定点类型。

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

至于在以下情况下使用什么:

对于“自然精确小数”的值,最好使用小数。这通常适用于人类发明的任何概念:财务价值是最明显的例子,但也有其他例子。例如,考虑给潜水员或滑冰运动员的分数。对于那些本质上更为人为的、无论如何都无法精确测量的值,浮点/双精度更为合适。例如,科学数据通常以这种形式表示。在这里,原始值从一开始就不是“小数精度”的,因此对于预期结果来说,保持“小数精度精度”并不重要。浮点二进制点类型比小数更快。