modf returns 1 as the fractional:

2019-02-27 22:10发布

I have this static method, it receives a double and "cuts" its fractional tail leaving two digits after the dot. works almost all the time. I have noticed that when it receives 2.3 it turns it to 2.29. This does not happen for 0.3, 1.3, 3.3, 4.3 and 102.3. Code basically multiplies the number by 100 uses modf divides the integer value by 100 and returns it. Here the code catches this one specific number and prints out:

static double dRound(double number) {

    bool c = false;
    if (number == 2.3)
        c = true;


    int factor = pow(10, 2);
    number *= factor;


    if (c) {
        cout << " number *= factor : " << number << endl;
        //number = 230;// When this is not marked as comment the code works well.
    }


    double returnVal;
    if (c){
        cout << " fractional : " << modf(number, &returnVal) << endl;
        cout << " integer : " <<returnVal << endl;
    }


    modf(number, &returnVal);
    return returnVal / factor;
}

it prints out:

number *= factor : 230

fractional : 1

integer : 229

Does anybody know why this is happening and how can i fix this? Thank you, and have a great weekend.

2条回答
别忘想泡老子
2楼-- · 2019-02-27 22:53

Remember floating point number cannot represent decimal numbers exactly. 2.3 * 100 actually gives 229.99999999999997. Thus modf returns 229 and 0.9999999999999716.

However, cout's format will only display floating point numbers to 6 decimal places by default. So the 0.9999999999999716 is shown as 1.


You could use (roughly) the upper error limit that a value represents in floating point to avoid the 2.3 error:

#include <cmath>
#include <limits>
static double dRound(double d) {
   double inf = copysign(std::numeric_limits<double>::infinity(), d);
   double theNumberAfter = nextafter(d, inf);
   double epsilon = theNumberAfter - d;

   int factor = 100;
   d *= factor;
   epsilon *= factor/2;
   d += epsilon;

   double returnVal;
   modf(number, &returnVal);
   return returnVal / factor;
}

Result: http://www.ideone.com/ywmua

查看更多
够拽才男人
3楼-- · 2019-02-27 23:05

Here is a way without rounding:

double double_cut(double d)
{
    long long x = d * 100;
    return x/100.0;
}

Even if you want rounding according to 3rd digit after decimal point, here is a solution:

double double_cut_round(double d)
{
    long long x = d * 1000;

    if (x > 0)
        x += 5;
    else
        x -= 5;

    return x / 1000.0;
}
查看更多
登录 后发表回答