简体   繁体   English

C#Convert.ToDouble()在将字符串转换为double时丢失小数点

[英]C# Convert.ToDouble() loses decimal points when converting string to double

Let's say we have the following simple code 假设我们有以下简单代码

        string number = "93389.429999999993";
        double numberAsDouble = Convert.ToDouble(number);
        Console.WriteLine(numberAsDouble);

after that conversion numberAsDouble variable has the value 93389.43. 该转换后numberAsDouble变量的值为93389.43。 What can i do to make this variable keep the full number as is without rounding it? 我该怎么做才能使这个变量保持完整的数字而不是四舍五入呢? I have found that Convert.ToDecimal does not behave the same way but i need to have the value as double. 我发现Convert.ToDecimal行为方式不同,但我需要将值设为double。

-------------------small update--------------------- -------------------小更新---------------------

putting a breakpoint in line 2 of the above code shows that the numberAsDouble variable has the rounded value 93389.43 before displayed in the console. 在上面代码的第2行中放置一个断点,表明numberAsDouble变量在控制台中显示之前具有舍入值93389.43。

93389.429999999993 cannot be represented exactly as a 64-bit floating point number. 93389.429999999993不能被精确为64位浮点数来表示。 A double can only hold 15 or 16 digits, while you have 17 digits. double只能容纳15或16位数,而你有17位数。 If you need that level of precision use a decimal instead. 如果您需要该级别的精度,请使用decimal

(I know you say you need it as a double, but if you could explain why, there may be alternate solutions) (我知道你说你需要它作为双倍,但如果你能解释原因,可能有其他解决方案)

This is expected behavior. 这是预期的行为。

A double can't represent every number exactly. 双精度不能完全代表每个数字。 This has nothing to do with the string conversion. 这与字符串转换无关。

You can check it yourself: 你可以自己检查一下:

Console.WriteLine(93389.429999999993);

This will print 93389.43 . 这将打印93389.43

The following also shows this: 以下还说明了这一点:

Console.WriteLine(93389.429999999993 == 93389.43);

This prints True . 这打印为True

Keep in mind that there are two conversions going on here. 请注意,此处有两次转化。 First you're converting the string to a double, and then you're converting that double back into a string to display it. 首先,您将字符串转换为double,然后将该double转换回字符串以显示它。

You also need to consider that a double doesn't have infinite precision; 你还需要考虑double没有无限精度; depending on the string, some data may be lost due to the fact that a double doesn't have the capacity to store it. 根据字符串的不同,某些数据可能会丢失,因为double不具备存储它的能力。

When converting to a double it's not going to "round" any more than it has to. 当转换为双倍时,它不会比它更“圆”。 It will create the double that is closest to the number provided, given the capabilities of a double. 考虑到double的功能,它将创建最接近所提供数字的双精度。 When converting that double to a string it's much more likely that some information isn't kept. 将该double转换为字符串时,更有可能不保留某些信息。

See the following (in particular the first part of Michael Borgwardt's answer): 请参阅以下内容(特别是Michael Borgwardt答案的第一部分):

decimal vs double! 十进制vs双! - Which one should I use and when? - 我应该使用哪一个?何时使用?

A double will not always keep the precision depending on the number you are trying to convert 双精度并不总是保持精度,具体取决于您尝试转换的数字

If you need to be precise you will need to use decimal 如果您需要精确,则需要使用decimal

This is a limit on the precision that a double can store. 这是double精度可以存储的精度限制。 You can see this yourself by trying to convert 3389.429999999993 instead. 您可以尝试转换3389.429999999993来自己查看。

The double type has a finite precision of 64 bits, so a rounding error occurs when the real number is stored in the numberAsDouble variable. double类型具有64位的有限精度,因此当实数存储在numberAsDouble变量中时会发生舍入错误。

A solution that would work for your example is to use the decimal type instead, which has 128 bit precision. 适用于您的示例的解决方案是使用decimal类型,它具有128位精度。 However, the same problem arises with a smaller difference. 然而,同样的问题出现了较小的差异。

For arbitrary large numbers, the System.Numerics.BigInteger object from the .NET Framework 4.0 supports arbitrary precision for integers. 对于任意大数字,.NET Framework 4.0中的System.Numerics.BigInteger对象支持整数的任意精度。 However you will need a 3rd party library to use arbitrary large real numbers. 但是,您需要第三方库来使用任意大的实数。

You could truncate the decimal places to the amount of digits you need, not exceeding double precision. 您可以将小数位截断为所需的位数,而不是超过双精度。

For instance, this will truncate to 5 decimal places, getting 93389.42999. 例如,这将截断到5位小数,得到93389.42999。 Just replace 100000 for the needed value 只需将100000替换为所需的值即可

string number = "93389.429999999993";
decimal numberAsDecimal = Convert.ToDecimal(number);
var numberAsDouble = ((double)((long)(numberAsDecimal * 100000.0m))) / 100000.0;

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

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