2016-10-10 8 views
3

Дано:выход функции Fmod C++

#include <iostream> 
#include <cmath> 
#include <limits> 
using namespace std; 

int main() { 
    // your code goes here 
    double h = .1; 
    double x = 1; 
    int nSteps = abs(x/h); 

    double rem = fmod(x, h); 
    cout<<"fmod output is "<<rem<<endl; 
    if(abs(rem)<std::numeric_limits<double>::epsilon()) 
     cout<<"fmod output is almost near 0"<<endl; 

    rem = remainder(x,h); 
    cout<<"remainder output is "<<rem<<endl; 
    if(abs(rem)<std::numeric_limits<double>::epsilon()) 
     cout<<"remainder output is almost near 0"<<endl; 

    return 0; 
} 

Учитывая int(x/h) == 10, я бы ожидал, что fmod() результат будет близок к 0, но то, что я получаю 0,0999999999. Это значительная разница. Результат остатка() по-прежнему представляется приемлемым. Код может быть опробован на http://ideone.com/9wBlva

Почему эта существенная разница для результата fmod()?

+0

C++ и C Arent тот же langauge – amanuel2

+0

Если это не отвечает на ваш вопрос самостоятельно, прочитайте документы. 'fmod' и' остаток' не делают то же самое, поэтому ожидаются разные результаты. –

+0

@ amanuel2 u получить аналогичные результаты http://ideone.com/rLyS2t – umbersar

ответ

3

Проблема вы видите, что версия fmod вы используете, как представляется, следить за выполнением определенного в cppreference:

double fmod(double x, double y) 
{ 
    double result = std::remainder(std::fabs(x), (y = std::fabs(y))); 
    if (std::signbit(result)) result += y; 
    return std::copysign(result, x); 
} 

std::remainder вычисляет очень очень маленький результат, почти равен нулю (-5.55112e -17 при использовании 1 и 0,1 для меня, -1.11022e-16 для 2 и 0,2). Однако важно то, что результат отрицательный, что означает, что std::signbit возвращает true, вызывая y, чтобы получить добавленный результат, эффективно делая результат равным y.

Обратите внимание, что документация std::fmod ничего не говорит об использовании std::remainder:

с плавающей точкой остаток от операции деления х/у, рассчитанной с помощью этой функции именно значение х - п * у , где n - это x/y, причем его дробная часть усечена.

Так что, если вы вычислить значение самостоятельно, вы в конечном итоге с нуля (даже если вы используете std::round на результат вместо чистого целого усечения)

Мы видим подобные проблемы при x 2 и y является 0,2

double x = 2; 
double y = .2; 

int n = static_cast<int>(x/y); 
double result = x - n*y; 
std::cout << "Manual: " << result << std::endl; 
std::cout << "fmod: " << std::fmod(x,y) << std::endl; 

Выход (gcc demo) является

Руководство: 0
FMOD: 0,2

Однако проблема не отводится только GCC; Я также вижу это в MSVC и clang. В clang иногда бывает другое поведение, если использовать float вместо double.

Это действительно небольшое отрицательное значение от std::remainder происходит от того, что ни 0,1, ни 0,2 не могут быть представлены точно в математике с плавающей запятой. Если вы измените x и y на, скажем, 2 и 0.25, тогда все будет хорошо.

+0

Для 'fmod': *" - это точно значение x - n \ * y, где n - это x/y с сокращенной его дробной частью. "* И под' int (x/h) == 10', 'n' должен быть '10' и, следовательно,' fmod (x, h) == 1 - 10 * .1', который должен быть почти 0. До сих пор материал в вашем ответе недостаточен, чтобы объяснить это. –

+0

Я только что нашел аналогичный вопрос, заданный здесь ..http: //stackoverflow.com/q/26519082/364084. – umbersar

+0

@AndyG Я все еще обрабатываю результат вручную в соответствии с этим объяснением. Если это сработает, я буду отмечать его как ответ – umbersar

 Смежные вопросы

  • Нет связанных вопросов^_^