modf возвращает 1 как дробное: - PullRequest
1 голос
/ 07 октября 2010

У меня есть этот статический метод, он получает двойное число и «режет» свой дробный хвост, оставляя две цифры после точки. работает почти все время. Я заметил, что когда он получает 2,3, он превращает его в 2,29. Этого не происходит для 0.3, 1.3, 3.3, 4.3 и 102.3. Код в основном умножает число на 100, использует modf, делит целочисленное значение на 100 и возвращает его. Здесь код перехватывает это конкретное число и печатает:

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

распечатывает:

число * = коэффициент: 230

дробный: 1

целое число: 229

Кто-нибудь знает, почему это происходит и как я могу это исправить? Спасибо, и хороших выходных.

Ответы [ 2 ]

6 голосов
/ 07 октября 2010

Помните, что число с плавающей запятой не может точно представлять десятичные числа. 2,3 * 100 на самом деле дает 229,9999999999997. Таким образом, modf возвращает 229 и 0,99999999999999716.

Однако формат cout по умолчанию будет отображать только числа с плавающей запятой до 6 десятичных знаков. Таким образом, 0.9999999999999716 отображается как 1.


Вы можете использовать (приблизительно) верхний предел ошибки, который представляет значение в плавающей точке, чтобы избежать ошибки 2.3:

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

Результат: http://www.ideone.com/ywmua

0 голосов
/ 07 октября 2010

Вот способ без округления:

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

Даже если вы хотите округлить в соответствии с 3-й цифрой после десятичной точки, вот решение:

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

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

    return x / 1000.0;
}
...