3

我正在尝试截断小数点后的所有内容。(13.4396 将是 13.43)它不是总是或从不工作吗?

我有这个 99% 有效的公式:

    input = (( (double) ((int)(orgInput * 100)) )  / 100) ;

然后我有这个算术等价的公式序列:

    input = (orgInput * 100);
    input = (int) input;
    input = (double) (input);
    input = input / 100;

这些输入没有给出期望的结果(公式截断并向下舍入,而分解的步骤输出期望的结果):

12.33

99.99

22.22

44.32

56.78

11.11

然后对我来说更大的谜团是为什么 33.30 对它们中的任何一个都不起作用。下面是我的程序,它不断运行以演示我的问题。

    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
        double orgInput, input;
        while (4!=3)
        {
            printf("Please enter the dollar amount (up to $100)  => ");
           scanf("%lf", &orgInput);

            /* Truncates anything past hundredths place */
            input = (orgInput * 100) ;
            printf("\n1. input is %g \n ", input);

            input = (int) input ;
            printf("\n2. input is %g \n ", input);

            input = (double) (input)   ;
            printf("\n3. input is %g \n", input);

            input = input / 100 ;
            printf("\n4. input is %.2lf \n", input);

            input = (( (double) ((int)(orgInput * 100)) )  / 100) ;
            printf("\nUsing the formula the input is %.2lf \n \n\n", input);

        }
        system("PAUSE");
        return 0;
    }

先感谢您!!!!PS对不起我仍然习惯于stackoverflow的格式

关键词:Double to int 转换精度误差

4

3 回答 3

5

我认为您正遭受浮点精度错误的困扰。

您应该可以通过执行以下操作来解决此问题:

const double epsilon = 1e-10;  // Or some suitable small number
input = floor(orgInput * 100 + epsilon) / 100;

另一种方法是在输入时阻止这种情况发生。不是读取双精度,而是读取一个字符串,然后解析它以获取美元和美分金额(美分正好是小数点后的 2 位数字,如果有的话)。然后,您可以忽略其他所有内容。

一般来说,如果您使用截断为美分的货币,您最好将其保留为美分并使用整数。要么是那个,要么是舍入而不是截断(对于我上面的例子,这意味着 0.5 的 epsilon)。

于 2012-09-17T04:49:17.853 回答
3

您需要了解浮点数以二进制表示为:

2^(指数) * 尾数

指数是标准整数,但尾数(1 到 2 之间的值)是位数,其中每个位代表一个分数:1、1/2、1/4、1/8、1/16 等等。 . 因此,尾数不可能精确地表示某些值,它将具有+/-某个分数的精度。

例如,您提到 33.30。作为浮点数 33.30 只能是:2^5 * 尾数。

在这种情况下,尾数必须是 33.30/32 = 1.40625。但是通过从分数中得出最接近的分数是:1.0406249999999999111821580299874767661094。所以双精度的实际值不是 33.30,而是 33.2999999999999971578290569595992565155029296875,当您将类型转换为整数时,这当然会向下舍入为 33.29。

修复程序的正确方法是首先不要以浮点数进行扫描。您应该扫描两个以小数分隔的整数,如果 scanf 返回一个值,表明它没有扫描两个整数,那么对于仅美元值的情况,将其扫描为一个整数。

可悲的是,printf 通过将其转换为 int 来工作,并且不会正确打印任何超过 6 位小数的双精度浮点数,这就是为什么即使您要求 printf 打印双精度值,您仍将其视为 33.30 的原因。

于 2012-09-17T12:00:06.770 回答
1

大多数机器使用二进制而非十进制浮点。虽然二进制到十进制的转换总是给出精确的值(理论上),但是如果没有四舍五入就不可能从十进制转换为二进制(我没有考虑数字可以有无限位数的不切实际情况)。

因此,您所有的二进制浮点数都将与十进制的数字略有偏差。

唯一可以用二进制表示的 1 位十进制小数是:.0、.5。

同样,可以用二进制精确表示的 2 位十进制小数是:.00、.25、.50、.75(参见此处)。

如果你愿意,我怀疑,你可以四舍五入到最接近的分数。

于 2012-09-17T08:28:12.503 回答