从 float 创建有理数会给出不精确的结果

标签 c codeblocks math.h

我正在训练我的 C 技能。我正在做一个接收 float 的函数,并且应该返回我用结构所做的分数。当我试图将数字四舍五入时,我开始看到一些奇怪的结果。我怀疑这是 floor() 函数中的一些错误。

我使用 Code::Blocks 并且我读到 pow() 函数在使用它时会出现一些错误,所以我认为应该是这样。

我阅读了很多关于 floor() 函数如何工作的资料,但我不知道如何修复它并防止再次产生错误的数字。

我的职能是:

Fraction ftof (float f)
/* Transforms a float in a struct type fraction. */
{
    Fraction frac;
    int i, decimalPlaces; 
    float decimalPart, numerator;

    decimalPlaces = 0;
    printf("Number of decimal places: %d\n", decimalPlaces);

    decimalPart = f - floor(f);
    printf("Decimal part: %f\n\n", decimalPart);

    while (decimalPart != 0)
    {
        decimalPlaces++;

        printf("Houses number updated: %d\n", decimalPlaces);

        decimalPart = decimalPart * 10;

        decimalPart = decimalPart - floor(decimalPart);

        printf("Decimal part updated: %f\n", decimalPart);
    }

    numerator = f;
    frac.denominator = 1;

    for (i = 0; i < decimalPlaces; i++)
    {
        numerator = numerator * 10;

        frac.denominator = frac.denominator * 10;
    }

    frac.numerator = (int) floor(numerator);

    writes(frac);
    printf("\n");

    simplification(&frac);

    return frac;
}

作为“写入”和“简化”我编写的另外两个函数,它们写入格式化的分数并进行简化,但它们经过了很好的测试并且可以正常工作。

我的主要是:

int main()
{
    float decimal;

    while (1) {
    printf("Type a decimal number: ");
    scanf("%f", &decimal);
    printf("Typed number: %f\n", decimal);
    writes(ftof(decimal));
    printf("\n\n");
    }
}

通过我放在函数中间的“printf”,它告诉我它正在计算的数字(我从来没有正确理解如何在 CodeBlocks 中调试),所以当我输入 0.25 时,它会产生1/4。但是,如果我输入一些更难的数字,比如 0.74,结果会是:

Type a decimal number: 0,74
Typed number: 0,740000
Number of decimal places: 0
Decimal part: 0,740000

Houses number updated: 1
Decimal part updated: 0,400000
Houses number updated: 2
Decimal part updated: 0,000001
Houses number updated: 3
Decimal part updated: 0,000010
Houses number updated: 4
Decimal part updated: 0,000095
Houses number updated: 5
Decimal part updated: 0,000954
Houses number updated: 6
Decimal part updated: 0,009537
Houses number updated: 7
Decimal part updated: 0,095367
Houses number updated: 8
Decimal part updated: 0,953674
Houses number updated: 9
Decimal part updated: 0,536743
Houses number updated: 10
Decimal part updated: 0,367432
Houses number updated: 11
Decimal part updated: 0,674316
Houses number updated: 12
Decimal part updated: 0,743164
Houses number updated: 13
Decimal part updated: 0,431641
Houses number updated: 14
Decimal part updated: 0,316406
Houses number updated: 15
Decimal part updated: 0,164063
Houses number updated: 16
Decimal part updated: 0,640625
Houses number updated: 17
Decimal part updated: 0,406250
Houses number updated: 18
Decimal part updated: 0,062500
Houses number updated: 19
Decimal part updated: 0,625000
Houses number updated: 20
Decimal part updated: 0,250000
Houses number updated: 21
Decimal part updated: 0,500000
Houses number updated: 22
Decimal part updated: 0,000000
0/0
512/311

我的意思是,当只有一位小数时,它是 0.4 * 10 = 4,但随后是 4 - floor(4) = 0.000001。

我能做什么?

最佳答案

浮点类型通常使用二进制尾数,这意味着可以完全以 10 为基数表示的数字不能完全以 2 为底数表示。像 0.25 这样的数字在二进制中有精确的表示,但 0.4 没有。所以你无法得到准确的答案。

解决这个问题的方法不是将数字作为 float 读取,而是作为字符串读取,然后自己执行到有理数的转换。

Fraction stof(char *s)
{
    Fraction f;
    long ipart, fpart;
    char *p, *p2;
    int i;

    p = strchr(s, '.');                     // look for the decimal point
    ipart = strtol(s, NULL, 10);            // get the integer part
    if (p) {
        fpart = strtol(p+1, &p2, 10);       // get the fractional part, saving the end pointer
                                            // to count digits in case of leading zeros
    } else {
        fpart = 0;                          // no . found, fractional part is 0
    }
    printf("ipart=%ld, fpart=%ld\n", ipart, fpart);

    f.numerator = ipart;                    // start with just the integer part
    f.denominator = 1;
    for (i=0; i<(p2-p-1); i++) {            // loop for each digit in the fractional part
        f.numerator *= 10;                  // scale up the numerator and denominator
        f.denominator *= 10;
    }
    f.numerator += fpart;                   // add in the fractional part
    printf("fraction = %ld / %ld\n", f.numerator, f.denominator);
    return f;
}

关于从 float 创建有理数会给出不精确的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55427471/

相关文章:

c - SHGetFolderPath 无论如何都会返回 "C"?

c++ - 可以链接具有不同名称的函数

c - 使用 CodeBlocks IDE 在 C 中出现 undefined reference 错误

c++ - 无法使用 <math.h> 中的 C/C++ nextafter/nexttoward 函数获取下一个 32 位浮点值

c++ - 来自 math.h 库的 pow() - 如何使用函数应用

c - 为什么 fabs() 在使用 GCC 编译时不需要 -lm 选项

c - 晶体管的C/数学模型

c - X,Y轴斜线如何上/下/侧

ubuntu - 有没有办法将winsock lib从windows移动到ubuntu?

C - 对链接文件的函数错误的 undefined reference