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

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

假设我们有以下简单的代码

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

转换后,numberAsDouble变量的值为93389.43。我该怎么做才能使这个变量保持整数不变而不取整呢?我发现Convert.ToDecimal的行为方式不同,但我需要将值设为double。

————————————————————————————————小更新---

在上面代码的第2行中放置一个断点表明,numberasDouble变量在控制台中显示之前具有舍入值93389.43。


93389.429999999993不能精确表示为64位浮点数。double只能容纳15或16位数字,而您只有17位数字。如果您需要这样的精度,请使用decimal

(我知道你说你需要双份的,但如果你能解释原因,可能还有其他的解决办法)


这是预期行为。

双精度数不能精确表示每个数字。这与字符串转换无关。

您可以自己检查:

1
Console.WriteLine(93389.429999999993);

这将打印93389.43

下面还显示了这一点:

1
Console.WriteLine(93389.429999999993 == 93389.43);

它打印了True


记住这里有两个转换。首先将字符串转换为双精度数,然后将该双精度数转换回字符串以显示它。

您还需要考虑到double没有无限的精度;根据字符串的不同,某些数据可能会由于double没有存储能力而丢失。

当转换为双精度时,它不会比必须的更"圆"。它将创建最接近所提供数字的double,前提是double的功能。当将该双精度数转换为字符串时,很可能会保留一些信息。


请参阅以下内容(尤其是迈克尔·博格华特回答的第一部分):

十进制与双精度!-我应该用哪一个?什么时候用?

double并不总是根据要转换的数字保持精度。

如果你需要精确,你需要使用decimal


您可以将小数点截断到所需的位数,但不能超过双精度。

例如,这将截断到5个小数位,得到93389.42999。只需将100000替换为所需值

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

double类型具有64位的有限精度,因此当实数存储在numberasDouble变量中时,会发生舍入错误。

对于您的示例,一个可行的解决方案是使用decimal类型,而不是128位精度的类型。然而,同样的问题也出现了,差别较小。

对于任意大的数字,.NET Framework 4.0中的System.Numerics.BigInteger对象支持整数的任意精度。但是,您需要第三方库来使用任意大的实数。


这是double可以存储的精度限制。你自己也可以通过转换3389.429999999993来看到这一点。