Как я могу обойти тот факт, что в С++ грех (M_PI) не равен 0?
В С++,
const double Pi = 3.14159265;
cout << sin(Pi); // displays: 3.58979e-009
СЛЕДУЕТ отображать нулевой номер
Я понимаю, что это связано с тем, что Pi аппроксимируется, но есть ли способ, которым я могу иметь значение Pi, жестко закодированное в моей программе, которое вернет 0 для sin (Pi)? (может быть, другая константа?)
В случае, если вам интересно, что я пытаюсь сделать: я конвертирую полярную в прямоугольную, и, хотя есть некоторые трюки printf(), которые я могу сделать, чтобы напечатать их как "0.00", она все еще не последовательно возвращают достойные ценности (в некоторых случаях я получаю "-0,00" )
Линии, которые требуют sin и косинус:
x = r*sin(theta);
y = r*cos(theta);
Кстати: My Rectangular → Polar отлично работает... это просто Polar → Rectangular
Спасибо!
edit: Я ищу обходной путь, чтобы я мог печатать грех (несколько кратных Pi) как приятный круглый номер на консоли (в идеале без тысячи if-statement)
Ответы
Ответ 1
Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой (редактировать: также получил ссылку в комментарии) довольно хардкорное чтение (я могу 't утверждают, что прочитали все это), но суть этого заключается в следующем: вы никогда не получите абсолютно точных вычислений с плавающей запятой. Из статьи:
Сжатие бесконечного числа действительных чисел в конечное число бит требует приблизительного представления.
Не позволяйте вашей программе зависеть от точных результатов вычислений с плавающей запятой - всегда допускайте диапазон допуска. FYI 3.58979e-009 составляет около 0,0000000036. Это хорошо в пределах любого допустимого диапазона допустимости, который вы выберете!
Ответ 2
Скажем так, 3.58979e-009
как близко до 0, так как ваше значение 3.14159265
соответствует реальному Pi. То, что у вас есть, технически, то, что вы просили.:)
Теперь, если вы набрали только 9 значащих цифр (8 знаков после запятой), тогда инструктируйте вывод также больше не отображать, т.е. используйте:
cout.precision(8);
cout << sin(Pi);
Ответ 3
Вы пытались M_PI, доступный в большинстве реализаций <cmath>
или <math.h>
?
Тем не менее, использование плавающей запятой таким образом всегда приведет к определенному количеству ошибок.
Ответ 4
3.58979e-009 это 0,0000000358979
Является ~~ 0, как ваш ~~ PI.
Ответ 5
он равен нулю, если ваш оператор равенства имеет достаточный допуск
Ответ 6
Это должно отображаться ноль:
cout << fixed << sin(Pi);
(я не думаю, что вы должны пытаться что-либо обойти. Если вы беспокоитесь о дисплее, обратитесь к функциям дисплея, а не к самому значению.)
Ответ 7
Вы можете добавить еще несколько цифр, чтобы получить лучший результат (попробуйте, например, 3.1415926535897932384626433832795029L), но вы все равно получите ошибки округления.
Тем не менее, вы можете создать свои собственные версии sin
и cos
, которые проверяют ваше известное значение Pi и возвращают ровно нуль в этих случаях.
namespace TrigExt
{
const double PI = 3.14159265358979323846;
inline double sin(double theta)
{
return theta==PI?(0.0):(std::sin(theta));
}
}
Вы также можете развернуть эту вещь для других тригонометрических функций и обрабатывать кратные Pi.
Ответ 8
Вы можете написать небольшую функцию обертки:
double mysin(const double d) {
double ret = sin(d);
if(fabs(ret) < 0.0000001) {
return 0.0;
} else {
return ret;
}
}
Как отмечали другие, математика с плавающей запятой, как известно, неточна. Вам нужна какая-то толерантность, если вы хотите, чтобы что-то показалось ровно нулевым.
Ответ 9
почему бы не заставить сколько-нибудь цифр вам нужно
int isin = (int)(sin(val) * 1000);
cout << (isin/1000.0)
Ответ 10
sin (PI) должно равняться 0 для точного значения PI. Вы не вводите точное значение PI. Как указывают другие люди, результат округления до 7 знаков после запятой равен 0, что довольно хорошо для вашего приближения.
Если вам нужно другое поведение, вы должны написать свою собственную синусоидальную функцию.
Ответ 11
Если вы используете float или double в математических упражнениях, у вас никогда не будет точных результатов.
Причина в том, что на компьютере все хранится как сила 2. Это не точно соответствует нашей десятичной системе счисления. (Например, существует n o представление в базе 2 из 0.1)
Кроме того, float и double имеют 64 бита, по крайней мере, на некоторых компиляторах и платформах. (Я думаю - кто-то меня исправит, если понадобится). Это приведет к некоторым ошибкам округления для очень больших значений или для очень малых значений (0.0000000000xxx)
Для получения точных результатов вам понадобится библиотека большого размера.
Как написано в комментариях к вышеуказанному вопросу, смотрите сайт...
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Ответ 12
double cut(double value, double cutoff=1e-7) {
return (abs(value) > cutoff)*value;
}
это будет нулевое значение ниже порогового значения, используйте его следующим образом: cut(sin(Pi))
Ответ 13
Более значимые цифры могут помочь. Мой компилятор C (gcc) использует константу 3.14159265358979323846
для M_PI в "math.h". Кроме этого, вариантов не так много. Лучше всего создать свою собственную функцию для проверки ответа (как описано в другом ответе на ваш вопрос).
Ответ 14
Вы знаете, только для математической корректности: sin (3.14159265) ins't ноль. Он приблизительно равен нулю, что и говорит вам программа. Для расчетов это число должно дать вам хороший результат. Для отображения это отстой, поэтому всякий раз, когда вы печатаете поплавок, обязательно отформатируйте число.
На самом деле я не думаю, что в работе есть какая-то механика с плавающей запятой... это просто простая математика.
О коде, однако, будьте осторожны... не заставляет ваш код давать неправильный результат, делая приближения перед дисплеем, просто отображая информацию правильно.