从浮点数创建有理数会得出不精确的结果

时间:2019-03-30 01:58:44

标签: c codeblocks math.h

我正在训练我的C语言技能。我正在做一个接收浮点数的函数,应该返回一个与struct相同的分数。当我试图降低数字时,我开始看到一些奇怪的结果。我怀疑这是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。

我该怎么办?

1 个答案:

答案 0 :(得分:2)

浮点类型通常使用二进制尾数,这意味着可以以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;
}
相关问题