可能重复:
处理浮点数的准确性问题
我很惊讶为什么我试图在 C 中乘以一个浮点数(使用 GCC 3.2)并且它没有按我预期的那样做。作为示例:
int main() {
float nb = 3.11f;
nb *= 10;
printf("%f\n", nb);
}
显示:31.099998
我很好奇浮动的实现方式以及为什么会产生这种意外行为?
可能重复:
处理浮点数的准确性问题
我很惊讶为什么我试图在 C 中乘以一个浮点数(使用 GCC 3.2)并且它没有按我预期的那样做。作为示例:
int main() {
float nb = 3.11f;
nb *= 10;
printf("%f\n", nb);
}
显示:31.099998
我很好奇浮动的实现方式以及为什么会产生这种意外行为?
首先,您可以乘以浮点数。您遇到的问题不是乘法本身,而是您使用的原始数字。乘法可能会丢失一些精度,但在这里,您相乘的原始数字会丢失精度。
这实际上是一种预期的行为。float
s 是使用二进制表示来实现的,这意味着它们不能准确地表示十进制值。
有关详细信息,请参阅MSDN。
您还可以在float 的描述中看到它具有 6-7 位有效数字精度。在您的示例中,如果您四舍五入31.099998
到 7 个有效数字,您将得到31.1
,所以它仍然可以按预期工作。
double
type 当然会更准确,但由于它是二进制表示,而你写的数字是十进制,仍然存在舍入误差。
如果您想要十进制数的完全准确性,您应该使用十进制类型。这种类型存在于 C# 等语言中。http://msdn.microsoft.com/en-us/library/system.decimal.aspx
您还可以使用有理数表示。只要您可以将数字表示为两个整数的除法,使用两个整数即可获得完全的准确性。
数字 3.11 不能用二进制表示。最接近 24 位有效位的是 11.0001110000101000111101,即十进制的 3.1099998950958251953125。
如果您的数字 3.11 应该代表货币金额,那么您需要使用十进制表示。
来自维基百科文章:
浮点数不能精确地表示所有实数,浮点运算也不能精确地表示真正的算术运算,这一事实导致了许多令人惊讶的情况。这与计算机通常表示数字的有限精度有关。
浮点数不精确,因为它们使用基数 2(因为它是二进制:0 或 1)而不是基数 10。正如许多人之前所说,将基数 2 转换为基数 10 会导致舍入精度问题。