В 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")
То, что каждый компьютерный ученый должен знать об арифметике с плавающей точкой (правка: также есть ссылка в комментарии) - довольно хардкорное чтение (я могу ' Я утверждаю, что прочитал все это), но суть в следующем: вы никогда не получите идеально точных вычислений с плавающей запятой. Из статьи:
Сжатие бесконечного числа действительных чисел в конечное число битов требует приближенного представления.
Не позволяйте вашей программе зависеть от точных результатов вычислений с плавающей запятой - всегда допускайте диапазон допуска. FYI 3.58979e-009 составляет около 0,0000000036. Это находится в пределах любого разумного диапазона допуска, который вы выберете!
Если вы используете float или double в математических операциях, у вас никогда не будет точных результатов. Причина в том, что на компьютере все хранится как степень двойки. Это не соответствует нашей десятичной системе счисления. (Примером является то, что в базе 2 0,1 отсутствует представление)
Кроме того, float и double являются 64-битными, по крайней мере, на некоторых компиляторах и платформах. (Думаю - меня кто-нибудь поправит, если нужно). Это вызовет некоторые ошибки округления для очень больших или очень маленьких значений (0.0000000000xxx)
Для получения точных результатов вам понадобится большая библиотека целых чисел.
Как написано в комментариях к вопросу выше, см. Сайт ... http://docs.sun.com/source/806-3568/ncg_goldberg.html
sin (PI) должен быть равен 0 для точного значения PI. Вы не вводите точное значение PI. Как указывают другие люди, результат, который вы округляете до 7 знаков после запятой, равен 0, что довольно хорошо для вашего приближения.
Если вам нужно другое поведение, вы должны написать свою собственную синусоидальную функцию.
Могут помочь более значащие цифры. Мой компилятор C (gcc) использует константу 3.14159265358979323846
для M_PI в "math.h". Кроме этого, вариантов не так много. Создание собственной функции для проверки ответа (как описано в другом ответе на ваш вопрос), вероятно, является лучшей идеей.
Вы знаете, просто для математической корректности: sin (3.14159265) ins't ноль. Это приблизительно ноль, и именно это программа вам сообщает. Для расчетов это число должно дать вам хороший результат. Для отображения это отстой, поэтому всякий раз, когда вы печатаете число с плавающей запятой, обязательно отформатируйте число.
Я действительно не думаю, что здесь используется какая-то механика с плавающей запятой ... это просто математика.
Что касается кода, будьте осторожны ... не заставляйте ваш код давать неправильный результат, делая приближения до отображения, просто отображайте информацию правильным образом.
3.58979e-009 это 0,0000000358979
Это ~~ 0, как у вас ~~ PI.
double cut(double value, double cutoff=1e-7) {
return (abs(value) > cutoff)*value;
}
это приведет к обнулению значений ниже порога, используйте это так cut (sin (Pi))
он равен нулю, если у вашего оператора равенства достаточно допуска
почему бы не указать необходимое количество цифр
int isin = (int)(sin(val) * 1000);
cout << (isin/1000.0)
Вы можете добавить еще несколько цифр, чтобы получить лучший результат (попробуйте, например, 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.
Вы пробовали M_PI, доступные в большинстве реализаций
или
?
Тем не менее, использование плавающей запятой таким образом всегда приведет к определенной ошибке.
Вы могли бы написать небольшую функцию-оболочку:
double mysin(const double d) {
double ret = sin(d);
if(fabs(ret) < 0.0000001) {
return 0.0;
} else {
return ret;
}
}
Как уже отмечали другие, математические вычисления с плавающей запятой заведомо неточны. Вам нужна какая-то толерантность, если вы хотите, чтобы что-то выглядело точно равным нулю.
Скажем так: 3.58979e-009
так же близко к 0, как ваш 3,14159265
значение соответствует реальному Пи. Технически вы получили то, о чем просили. :)
Теперь, если вы введете только 9 значащих цифр (8 знаков после запятой), то дайте команду выходным данным также не отображать больше, т.е. используйте:
cout.precision(8);
cout << sin(Pi);
Здесь должно отображаться ноль:
cout << fixed << sin(Pi);
(Я не думаю, что вам следует что-либо округлять. Если вас беспокоит отображение, разберитесь с функции отображения, а не само значение.)