为什么这个十进制在ToString()上显示8位小数?

时间:2014-12-03 09:31:04

标签: c# sql-server entity-framework decimal

我有一个decimal类型的变量,其值为1.0。我将其保存到SQL Server 2012表中的一列中,该表的类型为decimal(10, 8)

检索该值后,我看到它为1,但是当我调用ToString()时,返回的值为"1.00000000"(见下文)。

我意识到8位小数对应于数据库中的数据类型。但是,Entity Framework生成的属性中没有任何属性或任何内容可以为其提供此类行为,因此我不知道这是如何发生的。

以下是我在即时窗口中进行的一些测试:

myDecimal
1
myDecimal.ToString()
"1.00000000"
myDecimal == 1
true
myDecimal == 1.0m
true

正如你在前两次测试中看到的那样,它也不是浮点错误的情况(不是因为十进制是定点而我没想到它,但是因为我用完了所以我不得不尝试它的想法)。

知道小数点ToString()如何产生一个包含8个小数位的字符串?

修改:为了进行比较,请查看下面的测试。

1m.ToString()
"1"

4 个答案:

答案 0 :(得分:8)

原因是十进制类型未规范化。对于相同的数字有多个表示,并且这些表示将表示为不同的字符串。

这不是数据库类型的特殊属性,这是十进制正常工作的方式。没有特殊的DataAnotation或任何附加到变量的内容。

(1m).ToString() == "1"
(1.00000000m).ToString() == "1.00000000"
((1m)==(1.00000000m)) == true

对于给定的double,只有一个有效的表示,即尾数* 2 指数的一个组合

对于十进制,有尾数* 10 指数 的多个有效表示。每个代表相同的数字,但是通过多个可能的表示可用的附加信息用于在将小数转换为字符串时选择默认的尾随数字数。确切的细节并没有很好地记录,我没有找到关于当添加或乘以小数时指数究竟发生了什么的信息。但它对ToString()的影响很容易验证。

缺点是Equals()和GetHashCode()操作比规范化数字格式更复杂,并且实现中存在细微的错误:C# Why can equal decimals produce unequal hash values?

This article by Jon Skeet goes into a bit more detail

  

小数以128位存储,即使严格只有102位   必要。将十进制视为三个32位是很方便的   表示尾数的整数,然后表示一个整数   标志和指数。最后一个整数的最高位是符号位   (以正常方式,对于负数设置位(1))   和16-23位(高16位字的低位)包含   指数。其他位必须全部清零(0)。这种表示是   decimal.GetBits(decimal)给出的返回数组4   整数。   [...]

     

十进制类型不会对其自身进行标准化 - 它会记住它有多少个十进制数字(通过尽可能保持指数),并且在格式化时,零可以计为有效十进制数字。

您可以通过比较decimal.GetBits()返回的值来验证您的两位小数是否相同,即:

decimal.GetBits(1m) == {int[4]}
    [0]: 1
    [1]: 0
    [2]: 0
    [3]: 0

decimal.GetBits(1.00000000m) == {int[4]}
    [0]: 100000000
    [1]: 0
    [2]: 0
    [3]: 524288

依靠此行为来格式化小数可能很诱人,但我建议在转换为字符串时始终明确选择精度,以避免混淆和无法预料的意外,例如,如果数字预先乘以某个因子。

答案 1 :(得分:5)

当Entity Framework从查询的返回结果中检索值时,它使用您的EDMX定义或数据注释来知道在小数上设置的精度。

由于您使用了十进制(10,8),因此实体框架会将您的小数设置为1.00000000的值。以小数形式实现ToString将尊重该精度并输出所有零,因为它们被认为是重要的。

使用的类型仍为decimal。您可以通过给出精确值来指定小数的精度:1.000m1.0m更精确。这就是小数如何工作,并在底部(简要地)提到here

ToString无法知道在你告诉之前你不认为零是重要的。零仍然是一个价值。

答案 2 :(得分:1)

如果您首先使用数据库EntityFramework将xml格式的edmx文件中的列保持为...

<Property Name="ColumnName" Type="Decimal" Precision="8" Scale="4" Nullable="false" />

edmx文件提供有关Property的信息,就像DataAnotation一样。在您的情况下,Column标有Precision =“8”。因此,当您在列中调用ToString()方法时,该字段将相应地进行格式化。

您可以使用任何标准数字格式字符串http://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx格式化结果字符串,也可以使用自定义数字格式字符串http://msdn.microsoft.com/en-us/library/0c899ak8(v=vs.110).aspx

例如。

myDecimal.ToString("N") //1

答案 3 :(得分:0)

你是对的,十进制(10,8)告诉DB发回8个小数点。

如果你将结果分配给一个数字类型,它只是一个数字,而不是自己填充它将是最小的表示。

当你对数据库对象执行ToString时,它正在输出从SQL服务器发回的内容,在这种情况下是1,有8个零。

您可以通过直接查询数据库服务器来确认这一点。