c#以更高的精度打印浮点值

时间:2017-03-07 11:06:43

标签: c#

我想打印精度高于默认值的浮点数。

例如,当我从浮点数打印PI的值时,我得到6位小数。但是如果我将浮点数中的相同值复制到一个双精度数并打印出来,我会得到14位小数。

为什么在打印相同的值时会获得更高的精度,但作为双倍?

如何在打印浮点数时让Console.WriteLine()输出更多小数,而不需要先将其复制到双精度数中?

我也尝试了0.0000000000,但它没有更精确地写入,它只是添加了更多的零。 : - /

我的测试代码:

float x = (float)Math.PI;
double xx = x;
Console.WriteLine(x);
Console.WriteLine(xx);

Console.WriteLine($"{x,18:0.0000000000}"); // Try to force more precision 
Console.WriteLine($"{xx,18:0.0000000000}");

输出:

3,141593
3,14159274101257
      3,1415930000  <-- The program just added more zeroes :-(
      3,1415927410

我还尝试在https://www.h-schmidt.net/FloatConverter/IEEE754.html

输入PI

PI的二进制浮点表示为0b01000000010010010000111111011011

所以该值为:2 * 0b1.10010010000111111011011 = 2 * 1.57079637050628662109375 = 3.1415927410125732421875

因此输出的小数点更多。如何让C#输出这个整数值?

3 个答案:

答案 0 :(得分:5)

浮动中没有精度。当您将其转换为double时,精度更差,即使精度(位数)增加 - 基本上,您在双打印中看到的所有额外数字都是转换工件 - 它们是错误的,只是你可以获得双倍的给定浮点数的最佳表示。这与二进制浮点数的工作方式有关。

让我们看一下float的二进制表示:

01000000010010010000111111011100

第一位是符号,接下来的八位是指数,其余是尾数。当我们把它变成双倍时我们会得到什么?指数保持不变,但尾数用零填充。但实际上这会改变数字 - 你得到3.1415929794311523(舍入,一如二进制浮点数),而不是pi的正确3.14159265358979倍值。你会得到更高精度的幻觉,但这只是一种幻觉 - 数字不再像以前那么准确,你只需用噪声替换零。

浮动和双打之间没有1:1的映射。相同的浮点值可以用许多不同的double值表示,并且数字的十进制表示可以相应地改变。如果您关心小数精度,则floatdouble的每个演员都应该进行舍入操作。请考虑使用此代码:

double.Parse(((float)Math.PI).ToString())

我没有将float转换为double,而是首先将其更改为十进制表示(在字符串中),然后从中创建double。现在不是有一个“截断”的双重,而是有一个合适的双重,而不是额外的精度;当你打印出来时,你得到3.1415930000。当然,它仍然是四舍五入的,因为它仍然是二进制 - >十进制转换,但不再假装比实际存在更精确 - 舍入发生在后一个数字而不是浮点版本,零是真的零,除了最后一个(只有大约零)。

如果您想要实际的小数精度,可能需要使用小数类型(例如intdecimal)。 floatdouble都是二进制数字,并且只有二进制精度。有限的十进制数不一定是二进制有限的,就像有限的三进制数不一定是十进制有限的(例如1/3没有有限的十进制表示)。

答案 1 :(得分:3)

c#中的float具有7位数的精度,不再有。这意味着小数点前1位数,后6位数。

如果输出中有更多数字,则可能完全错误。

如果确实需要更多数字,则必须使用精度为15-16位的双精度数或精度为28-29位的十进制数。

See MSDN for reference.

您可以轻松验证PI的数字与输出略有不同。正确的前40位数字为:3.14159 26535 89793 23846 26433 83279 50288 4197

答案 2 :(得分:0)

打印小数点后6位的值。

Console.WriteLine("{0:N6}", (double)2/3);

输出:

0.666667