浮点变量不符合条件(C)

时间:2013-11-09 00:56:12

标签: c variables floating-point while-loop

我试图让用户输入介于1.00000到0.00001之间的数字,而边缘不包含在浮点变量中。我可以假设用户在点后面没有输入超过5个数字。 现在,这是我写的:

printf("Enter required Leibniz gap.(Between 0.00001 to 1.00000)\n");
scanf("%f", &gap);
while ((gap < 0.00002) || (gap > 0.99999))
{
printf("Enter required Leibniz gap.(Between 0.00001 to 1.00000)\n");
scanf("%f", &gap);
}

现在,当我输入尽可能少的数字时:0.00002卡在while循环中。 当我运行调试器时,我看到0.00002与float变量中的值一起存储:1.99999995e-005 任何人都可以为我澄清我做错了什么?为什么0.00002不满足条件?什么是“1.99999995e-005”的事情。

4 个答案:

答案 0 :(得分:3)

此处的问题是您使用的是float变量(gap),但您将其与double常量(0.00002)进行比较。常量为double,因为除非另有说明,否则C中的浮点常量为double。

根本问题是,0.00002float无法表示数字double。 (它在二进制浮点中根本无法表示,因为它的二进制扩展是无限长的,就像decimal的十进制扩展一样。)因此,当您在程序中编写0.00002时,C编译器会用{{1}替换它}值非常接近double。同样,当0.00002将数字scanf读入0.00002变量时,它会替换非常接近float的{​​{1}}值。由于float个数字的位数多于0.00002,因此double值比floats值更接近double

当您比较具有不同精度的两个浮点值时,编译器会将精度较低的值转换为具有更高精度的完全相同的值。 (可表示为0.00002的值集是可表示为float的值集的超集,因此始终可以找到其值与值相同的double一个float。)这就是执行double时会发生什么:float被转换为相同值的gap < 0.00002,并与双倍进行比较(接近于)gap。由于这两个值实际上都略低于0.00002,并且double更接近,0.00002小于double

您可以通过多种方式解决此问题。首先,您可以通过将float设为double并将gap格式更改为double,或将scanf与{{{1}进行比较,从而避免转化1}}:

%lf

但由于几个原因,这并不正确。首先,实际上不能保证C编译器完成的浮点转换与标准库(gap)完成的转换相同,并且标准允许编译器使用“最接近的可表示值” ,或者以最接近的可表示值紧邻的较大或较小的可表示值,以实现定义的方式选择。“ (它没有详细说明哪个值float产生,但建议它是最接近的可表示值。)碰巧,while (gap < 0.00002F || gap > 0.99999F) { scanf(C编译器和标准在Linux上使用的库)都产生最接近的可表示值,但其他实现没有。

无论如何,根据您的错误消息,您希望值介于scanfgcc之间。所以你的测试应该是:

glibc

(假设您将0.00001保留为1.00000。)

上述任何解决方案都可行。就个人而言,我要while (gap <= 0.00001F || gap >= 1.0000F) { ... 一个gap以使比较更直观,并将比较更改为与floatgap进行比较。

顺便说一下,double后缀表示“时间十到-5的幂”(0.00001代表1.0000)。你会看到很多;它是编写浮点常量的标准方法。

答案 1 :(得分:2)

float s无法为每个可能的数字存储精确值(0-1之间的无限数字因此是不可能的)。将0.00002分配给浮点数将具有不同但非常接近的数字,因为您正在实现该实现。随着数量的增加,精度会下降。

因此,您无法直接比较两个紧密的浮点数并获得健康的结果。

有关浮点的更多信息,请参见on this Wikipedia page

你可以做的是模拟定点数学。让int n = 100000;在内部代表1.00000(1000 - > 0.001等)并相应地进行计算或使用定点数学库。

答案 2 :(得分:2)

单精度浮点数的分数部分可以表示从-2到2-2 ^ -23的数字,并且具有最小量化步长为2 ^ -23的分数部分。因此,如果某个值无法使用此类步骤表示,则根据IEEE 754 rounding rules使用最接近的值表示:

0.00002*32768 = 0.655360043     // floating point exponent is chosen.
0.655360043/(2^-23) = 5497558.5 // is not an integer multiplier 
                                // of quantization step, so the 
5497558*(2^-23) = 0.655359983   // nearest value is chosen
5497559*(2^-23) = 0.655360103   // from these two variants

第一个变量等于1.999969797×10 -6的十进制格式,第二个变量等于1.999999948×10 -6(只是为了比较 - 如果我们选择5497560,我们得到2.000000677×10 -6)。因此可以选择第二个变量,其值不等于0.00002。
浮点数的总精度也取决于指数值(取-128到127的值):它可以通过分数部分量化步长和指数值的乘法来计算。在0.00002的情况下,总精度为(2 ^ -23)×(2 ^ -15)= 3.6×(10 ^ -12)。这意味着如果我们向0.00002添加一个小于该值一半的值,则0.00002保持不变。一般来说,这意味着有意义的浮点数的数量是从1×指数到2×(10 ^ -23)×指数。 这就是为什么一种非常流行的方法是使用一些大于量化步长的ε值来比较两个浮点数。

答案 3 :(得分:0)

就像一些评论所说,由于浮点数的表示方式,你会看到这样的错误。 解决方法是将其转换为

gap + 1e-8 < 0.0002 

这为您提供了一个小容差窗口,足以让您想要传递大多数情况,而且大多数情况下您不想失败