То, как я могу работать вокруг того, что в C++, sin(M_PI) не 0?

В C++,

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

это ДОЛЖНО отобразить нуль числа

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

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

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

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

BTW: Мое Прямоугольное-> Полярный хорошо работает..., это - просто Полярное-> Прямоугольный

Спасибо!

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

14
задан Adam 26 April 2010 в 19:39
поделиться

14 ответов

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

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

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

28
ответ дан 1 December 2019 в 05:59
поделиться

Если вы используете float или double в математических операциях, у вас никогда не будет точных результатов. Причина в том, что на компьютере все хранится как степень двойки. Это не соответствует нашей десятичной системе счисления. (Примером является то, что в базе 2 0,1 отсутствует представление)

Кроме того, float и double являются 64-битными, по крайней мере, на некоторых компиляторах и платформах. (Думаю - меня кто-нибудь поправит, если нужно). Это вызовет некоторые ошибки округления для очень больших или очень маленьких значений (0.0000000000xxx)

Для получения точных результатов вам понадобится большая библиотека целых чисел.

Как написано в комментариях к вопросу выше, см. Сайт ... http://docs.sun.com/source/806-3568/ncg_goldberg.html

0
ответ дан 1 December 2019 в 05:59
поделиться

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

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

1
ответ дан 1 December 2019 в 05:59
поделиться

Могут помочь более значащие цифры. Мой компилятор C (gcc) использует константу 3.14159265358979323846 для M_PI в "math.h". Кроме этого, вариантов не так много. Создание собственной функции для проверки ответа (как описано в другом ответе на ваш вопрос), вероятно, является лучшей идеей.

-1
ответ дан 1 December 2019 в 05:59
поделиться

Вы знаете, просто для математической корректности: sin (3.14159265) ins't ноль. Это приблизительно ноль, и именно это программа вам сообщает. Для расчетов это число должно дать вам хороший результат. Для отображения это отстой, поэтому всякий раз, когда вы печатаете число с плавающей запятой, обязательно отформатируйте число.

Я действительно не думаю, что здесь используется какая-то механика с плавающей запятой ... это просто математика.

Что касается кода, будьте осторожны ... не заставляйте ваш код давать неправильный результат, делая приближения до отображения, просто отображайте информацию правильным образом.

-1
ответ дан 1 December 2019 в 05:59
поделиться

3.58979e-009 это 0,0000000358979

Это ~~ 0, как у вас ~~ PI.

3
ответ дан 1 December 2019 в 05:59
поделиться
double cut(double value, double cutoff=1e-7) {
  return (abs(value) > cutoff)*value;
}

это приведет к обнулению значений ниже порога, используйте это так cut (sin (Pi))

0
ответ дан 1 December 2019 в 05:59
поделиться

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

3
ответ дан 1 December 2019 в 05:59
поделиться

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

 int isin = (int)(sin(val) * 1000);
 cout << (isin/1000.0)
1
ответ дан 1 December 2019 в 05:59
поделиться

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

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

namespace TrigExt
{
    const double PI = 3.14159265358979323846;

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

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

2
ответ дан 1 December 2019 в 05:59
поделиться

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

Тем не менее, использование плавающей запятой таким образом всегда приведет к определенной ошибке.

4
ответ дан 1 December 2019 в 05:59
поделиться

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

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

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

1
ответ дан 1 December 2019 в 05:59
поделиться

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

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

cout.precision(8);
cout << sin(Pi);
15
ответ дан 1 December 2019 в 05:59
поделиться

Здесь должно отображаться ноль:

cout << fixed << sin(Pi);

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

4
ответ дан 1 December 2019 в 05:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: