Как я могу обойти тот факт, что в C ++, sin (M_PI) не 0? - PullRequest
14 голосов
/ 20 апреля 2010

В С ++,

const double Pi = 3.14159265;
cout << sin(Pi);                          // displays: 3.58979e-009

ДОЛЖЕН отображаться номер ноль

Я понимаю, что это потому, что Pi аппроксимируется, но есть ли какой-нибудь способ, которым я могу жестко закодировать значение Pi в моей программе, которое вернет 0 для sin (Pi)? (может быть другая константа?)

В случае, если вам интересно, что я пытаюсь сделать: я конвертирую полярность в прямоугольник, и хотя есть некоторые приемы printf (), которые я могу сделать, чтобы напечатать его как «0.00», он все еще не последовательно возвращать приличные значения (в некоторых случаях я получаю «-0,00»)

Строки, которые требуют греха и косинуса:

x = r*sin(theta);
y = r*cos(theta);

Кстати: мой прямоугольник -> Polar работает нормально ... это просто полярник -> прямоугольник

Спасибо!

edit: Я ищу обходной путь, чтобы я мог вывести на консоль sin (несколько кратных Pi) в виде удобного круглого числа (в идеале без тысячи операторов if)

Ответы [ 14 ]

28 голосов
/ 20 апреля 2010

То, что должен знать каждый компьютерный ученый об арифметике с плавающей точкой (редактировать: также получил ссылку в комментарии) - довольно жесткое чтение (не могу утверждать, что прочитал все это), но суть в том, что вы никогда не получите совершенно точные вычисления с плавающей точкой. Из статьи:

Для сжатия бесконечного числа действительных чисел в конечное число бит требуется приблизительное представление.

Не позволяйте вашей программе зависеть от точных результатов вычислений с плавающей запятой - всегда допускайте диапазон допуска. К вашему сведению 3.58979e-009 составляет около 0,0000000036. Это хорошо в любом разумном диапазоне допуска, который вы выберете!

15 голосов
/ 20 апреля 2010

Скажем так: 3.58979e-009 равно так же близко к 0, как ваше значение 3.14159265 к реальному Пи. То, что вы получили, технически, то, что вы просили. :)

Теперь, если вы поместите только 9 значащих цифр (8 десятичных разрядов) в, то дайте указание выводу также больше не отображать, т.е. используйте:

cout.precision(8);
cout << sin(Pi);
4 голосов
/ 20 апреля 2010

Это должно отображать ноль:

cout << fixed << sin(Pi);

(Я не думаю, что вы должны пытаться что-то округлить. Если вас беспокоит отображение, разберитесь с функциями отображения, а не с самим значением.)

4 голосов
/ 20 апреля 2010

Вы пробовали M_PI, доступный в большинстве <cmath> или <math.h> реализаций?

Даже в этом случае использование плавающей запятой таким образом всегда будет приводить к некоторой ошибке.

3 голосов
/ 20 апреля 2010

равно нулю, если ваш оператор равенства имеет достаточный допуск

3 голосов
/ 20 апреля 2010

3.58979e-009 это 0,0000000358979

Это ~~ 0 как твой ~~ PI.

2 голосов
/ 20 апреля 2010

Вы можете добавить еще несколько цифр, чтобы получить лучший результат (например, 3.1415926535897932384626433832795029L), но вы все равно получите ошибки округления.

Тем не менее, вы можете создать свои собственные sin и cos версии, которые проверяют ваше известное значение Пи и возвращают в этом случае ровно ноль.

namespace TrigExt
{
    const double PI = 3.14159265358979323846;

    inline double sin(double theta)
    {
        return theta==PI?(0.0):(std::sin(theta));
    }
}

Вы также можете расширить эту функцию для других тригонометрических функций и для обработки кратных Пи.

1 голос
/ 20 апреля 2010

sin (PI) должен быть равен 0, для точного значения PI. Вы не вводите точное значение PI. Как указывают другие люди, результат, который вы округляете до 7 десятичных знаков, равен 0, что очень хорошо для вашего приближения.

Если вам нужно другое поведение, вы должны написать свою собственную функцию синуса.

1 голос
/ 20 апреля 2010

почему бы не ввести столько цифр, сколько вам нужно

 int isin = (int)(sin(val) * 1000);
 cout << (isin/1000.0)
1 голос
/ 20 апреля 2010

Вы можете написать небольшую функцию-обертку:

double mysin(const double d) {
    double ret = sin(d);
    if(fabs(ret) < 0.0000001) {
        return 0.0;
    } else {
        return ret;
    }
}

Как уже отмечали другие, математика с плавающей точкой общеизвестно неточна. Вам нужна некоторая терпимость, если вы хотите, чтобы что-то выглядело как ровно ноль.

...