我想打印精度高于默认值的浮点数。
例如,当我从浮点数打印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
输入PIPI的二进制浮点表示为0b01000000010010010000111111011011
所以该值为:2 * 0b1.10010010000111111011011 = 2 * 1.57079637050628662109375 = 3.1415927410125732421875
因此输出的小数点更多。如何让C#输出这个整数值?
答案 0 :(得分:5)
浮动中没有精度。当您将其转换为double
时,精度更差,即使精度(位数)增加 - 基本上,您在双打印中看到的所有额外数字都是转换工件 - 它们是错误的,只是你可以获得双倍的给定浮点数的最佳表示。这与二进制浮点数的工作方式有关。
让我们看一下float的二进制表示:
01000000010010010000111111011100
第一位是符号,接下来的八位是指数,其余是尾数。当我们把它变成双倍时我们会得到什么?指数保持不变,但尾数用零填充。但实际上这会改变数字 - 你得到3.1415929794311523
(舍入,一如二进制浮点数),而不是pi的正确3.14159265358979
倍值。你会得到更高精度的幻觉,但这只是一种幻觉 - 数字不再像以前那么准确,你只需用噪声替换零。
浮动和双打之间没有1:1的映射。相同的浮点值可以用许多不同的double值表示,并且数字的十进制表示可以相应地改变。如果您关心小数精度,则float
到double
的每个演员都应该进行舍入操作。请考虑使用此代码:
double.Parse(((float)Math.PI).ToString())
我没有将float转换为double,而是首先将其更改为十进制表示(在字符串中),然后从中创建double。现在不是有一个“截断”的双重,而是有一个合适的双重,而不是额外的精度;当你打印出来时,你得到3.1415930000
。当然,它仍然是四舍五入的,因为它仍然是二进制 - >十进制转换,但不再假装比实际存在更精确 - 舍入发生在后一个数字而不是浮点版本,零是真的零,除了最后一个(只有大约零)。
如果您想要实际的小数精度,可能需要使用小数类型(例如int
或decimal
)。 float
和double
都是二进制数字,并且只有二进制精度。有限的十进制数不一定是二进制有限的,就像有限的三进制数不一定是十进制有限的(例如1/3没有有限的十进制表示)。
答案 1 :(得分:3)
c#中的float具有7位数的精度,不再有。这意味着小数点前1位数,后6位数。
如果输出中有更多数字,则可能完全错误。
如果确实需要更多数字,则必须使用精度为15-16位的双精度数或精度为28-29位的十进制数。
您可以轻松验证PI的数字与输出略有不同。正确的前40位数字为:3.14159 26535 89793 23846 26433 83279 50288 4197
答案 2 :(得分:0)
打印小数点后6位的值。
Console.WriteLine("{0:N6}", (double)2/3);
输出:
0.666667