可能这是一个非常基本的问题,但我真的很想知道究竟发生了什么。
例如,如果我们在c#中执行以下操作:
object obj = "330.1500249000119";
var val = Convert.ToDouble(obj);
val成为:330.15002490001189
问题是为什么最后9个被89替换?我们可以阻止它以这种方式发生吗?这精确度取决于当前的文化吗?
答案 0 :(得分:4)
这与文化无关。有些数字不能用base-2数字来表示,就像在base-10中一样,1/3不能用.3333333完全表示
请注意,在您的特定情况下,您输入的数字比数据类型允许的数字更多:Double的有效数字是15-16(取决于范围),您的数字超出了这个数字。
在这种情况下,您可以使用Double
代替Decimal
:
object obj = "330.1500249000119";
var val = Convert.ToDecimal(obj);
答案 1 :(得分:2)
decimal
会保留精确度。
object obj = "330.1500249000119";
var val = Convert.ToDecimal(obj);
您遇到的“问题”是浮点表示。
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
答案 2 :(得分:0)
不,你不能阻止它发生。您正在解析具有数据类型可以表示的更多数字的值。
精确度不依赖于文化。 double
始终具有相同的精度。
所以,如果你不想让它发生,那就干脆不去做。如果您不想要浮点数限制精度的影响,请不要使用浮点数。如果您使用固定点数(十进制),它可以准确地表示该值。
答案 3 :(得分:-1)
CPU表示8个字节的双精度数。其分为1个符号位,11个指针用于指数(“范围”),52个用于尾数(“精度”)。 你的范围和精度都有限。
<float.h>
中的C常量 DBL_DIG 告诉您,这样的双精度数字只能精确地表示 15位,而不是更多。但是这个数字完全取决于你的c库和CPU。
330.1500249000119包含18位数字,因此将四舍五入为330.150024900012。 330.15002490001189只有一个,这很好。通常你应该期望1.189对1.2。
对于背后的确切数学,尝试阅读David Goldberg,“每个计算机科学家应该知道的关于浮点算术的内容”,ACM Computing Surveys 23,1(1991-03),5-48。如果您对细节感兴趣,这是值得一读的,但它确实需要计算机科学的背景。 http://www.validlab.com/goldberg/paper.pdf
你可以通过使用更好的浮点类型来阻止这种情况发生,例如long double或__float128,或者使用更好的cpu,比如Sparc64或s390,它们在HW中本身使用41位数字(__float128)作为long double。
是的,使用UltraSparc / Niagara或IBM S390就是文化。
通常的答案是:使用 long double ,老兄。这为英特尔(18位)增加了两个字节,还有几个powerpc(31位),sparc64 / s390为41。