开发者

modf returns 1 as the fractional:

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 spec开发者_JAVA技巧ific 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.


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


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;
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜