简体   繁体   English

Convert.ToDouble(object)中的小数精度是否取决于区域性?

[英]Is the decimal precision in Convert.ToDouble(object) dependent on culture?

May be this is a very basic question, but I am really interested to know what really happens. 可能这是一个非常基本的问题,但是我真的很想知道真正发生了什么。

For example if we do the following in c#: 例如,如果我们在c#中执行以下操作:

object obj = "330.1500249000119";
var val = Convert.ToDouble(obj);

The val becomes: 330.15002490001189 值变成:330.15002490001189

The question is that why the last 9 is replace by 89? 问题是,为什么最后9个被89代替? Can we stop it from happening this way? 我们可以阻止这种情况发生吗? And is this precision dependent on the Current Culture? 这种精度是否取决于当前的文化?

This has nothing to do with culture. 这与文化无关。 Some numbers can not be exactly represented by a base-2 number, just like in base-10 1/3rd can't be exactly represented by .3333333 有些数字不能以2为底的数字来精确表示,就像以10为底的1 / 3rd不能以.3333333来精确表示一样

Note that in your specific case you are putting in more digits than the data type allows: the significant digits available with a Double is 15-16 (depending on range), which your number goes beyond. 请注意,在您的特定情况下,您输入的位数超出了数据类型所允许的位数:Double可用的有效位数为15-16(取决于范围),您的数字超出了该位数。

Instead of a Double , you can use a Decimal in this case: 在这种情况下,可以使用Decimal代替Double

object obj = "330.1500249000119";
var val = Convert.ToDecimal(obj);

A decimal would retain the precision. decimal将保留精度。

object obj = "330.1500249000119";
var val = Convert.ToDecimal(obj);

The "issue" you are having is floating point representation. 您遇到的“问题”是浮点表示形式。

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

No, you can't stop it from happening. 不,您无法阻止它的发生。 You are parsing a value that has more digits that the data type can represent. 您正在解析的值具有该数据类型可以表示的更多数字。

The precision is not dependent of the culture. 精度不取决于文化。 A double always has the same precision. double精度始终具有相同的精度。

So, if you don't want it to happen, then simply don't do it. 因此,如果您不希望它发生,那就不要这样做。 If you don't want the effects of the limited precision of floating point numbers, don't use floating point numbers. 如果您不希望浮点数的精度受到限制,请不要使用浮点数。 If you would use a fixed point number (Decimal) instead, it could represent the value exactly. 如果改用定点数(十进制),则它可以精确表示该值。

A CPU represents doubles in 8 bytes. CPU在8字节中表示双精度。 Which is divided into 1 sign bit, 11 bits for the exponent ("the range") and 52 for the mantissa ("the precision"). 分为1个符号位,11个指数位(“范围”)和52个尾数位(“精度”)。 You have limited range and precision. 您的范围和精度有限。

The C constant DBL_DIG in <float.h> tells you that such a double can only represent 15 digits precisely, not more. <float.h>的C常量DBL_DIG告诉您,这样的双精度只能精确地表示15位数字 ,不能代表更多数字 But this number entirely dependent on your c library and CPU. 但是这个数字完全取决于您的c库和CPU。

330.1500249000119 contains 18 digits, so it will be rounded to 330.150024900012. 330.1500249000119包含18位数字,因此将四舍五入为330.150024900012。 330.15002490001189 is only one off, which is good. 330.15002490001189只能关闭一次,很好。 Normally you should expect 1.189 vs 1.2. 通常,您应该预期1.189与1.2。

For the exact mathematics behind try to read David Goldberg, “What Every Computer Scientist Should Know About Floating-point Arithmetic,” ACM Computing Surveys 23, 1 (1991-03), 5-48. 有关确切的数学知识,请尝试阅读David Goldberg的文章:“每位计算机科学家都应了解的浮点算法”,ACM Computing Surveys 23,1(1991-03),5-48。 This is worth reading if you are interested in the details, but it does require a background in computer science. 如果您对这些细节感兴趣,这值得一读,但是它确实需要计算机科学的背景知识。 http://www.validlab.com/goldberg/paper.pdf http://www.validlab.com/goldberg/paper.pdf

You can stop this from happening by using better floating point types, like long double or __float128, or using a better cpu, like a Sparc64 or s390 which use 41 digits (__float128) natively in HW as long double. 您可以通过使用更好的浮点类型(例如long double或__float128)或使用更好的cpu(例如Sparc64或s390)在HW中本地使用41位数字(__float128)作为long double来阻止这种情况的发生。

Yes, using an UltraSparc/Niagara or an IBM S390 is culture. 是的,使用UltraSparc / Niagara或IBM S390是一种文化。

The usual answer is: use long double , dude. 通常的答案是:使用long double ,dude。 Which gives you two more bytes on Intel (18 digits) and several more an powerpc (31 digits), and 41 on sparc64/s390. 在Intel(18位)上提供了两个字节,在Powerpc(31位)上提供了多个字节,在sparc64 / s390上提供了41个字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM