2015-07-20 10 views
1

Этого я не ожидал. Я знаю, что эти цифры не являются 100% точным, но я не ожидал, что дополнительные углы, дающие разные результаты sin и cos:Почему грех (45) и cos (45) дают разные результаты?

Эта функция возвращает 0.70710678118654746000000...

sin(45 * PI/180.0); 

в то время как эта функция возвращает follwing 0.70710678118654757000000...

cos(45 * PI/180.0); 

так, это:

0.707106781186547**46**000000... vs 
0.707106781186547**57**000000... 

, а не только тех, кто ... sin(1 * PI/180.0) также возвращает немного другой номер, чем cos(89 * PI/180.0) хотя они должны быть одинаковыми.

Кроме того, это не только sin против cos проблема, это также sin против sin проблема: sin(1 * PI/180.0) возвращает другое значение, чем sin(179 * PI/180.0), опять же, они должны быть одинаковыми.

Я попытался использовать радианы, а не градусы, и есть точно такая же разница, я попытался использовать небольшое значение PI, огромное значение PI (около 100 десятичных знаков и более), и они все еще разные, я попробовал использовать cmath вместо math.h, я попытался использовать M_PI вместо PI, определенный мной.

Разница всегда одна и та же, около 16-го десятичного знака. Не поймите меня неправильно, я знаю, что я никогда не получу 100% точного значения этих чисел, но, ПОСЛЕДНИЕ, я ожидал получить то же самое «неточное» значение sin и cos дополнительных углов. Что, черт возьми, не так со всем этим?


Мне нужно их быть таким же, потому что программа, которую я сейчас работаю (самотеком тренажер меня попросили сделать) используют объекты, которые имеют double (я также попытался float) переменными, которые в основном углами (градусы или радианы, я пробовал оба). Это направления, которые объекты используют для перемещения, также мне нужны углы для вычисления взаимодействий между объектами.

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

Программа запускает тысячи и даже миллионы итераций, поэтому ошибка значения становится абсурдно огромной! Выражаясь ясно, планеты в конечном итоге выйти из их баланса и все становится катастрофой, я действительно с ума :(

Ps Я на Windows 7, 32 бит.

+2

Там только около 16 десятичных цифр точности в двойной. – ooga

+0

Ну, я знаю, что я никогда не получу идеальную ценность для греха (45), такого значения не существует, идеального и круглого значения PI тоже не существует, но я, по крайней мере, ожидал, что дополнительные углы ошибося Точно так же:/ – Dimakhaerus

+1

Возможно, вам захочется найти (или реализовать) символическую вычислительную библиотеку. Разумеется, вы будете жертвовать высокой точностью. –

ответ

3

Я знаю, что будет никогда не получите 100% точное значение этих чисел, но AT НАИМЕНЬШИМ я ожидал получить такой же «unprecise» значение греха и соз дополнительных углов.

Почему?Они вычисляются по-разному, поэтому будут возникать (и накапливаться) различные ошибки с плавающей запятой. То, что вы видите, не является ошибкой; Арифметика FP не предсказуема математическими законами.

Btw., Обеспечивающий, например, 30 или 100 цифр PI не будут отличаться от
, если ваш тип не может содержать 30 цифр.

+0

Я знаю, что касается ПИ, это была отчаянная попытка заставить его работать должным образом. Ну, это, безусловно, огромная ошибка, независимо от того, как они рассчитываются, они должны возвращать одинаковое значение:/ Спасибо, что ответили !! – Dimakhaerus

+0

@ Dimakhaerus Если вы называете это ошибкой, как насчет предложения решения? Правильно, таких ожиданий невозможно, потому что таких бесконечных особых случаев. Например, 'sin (60) == sqrt (3)/2' является еще одним. ... Без лишнего объема памяти будут ошибки, и ничто не может помешать этому. – deviantfan

+0

Предоставление даже 30 цифр является полным избытком для большинства целей, '355/113', из памяти, достаточно хорош, чтобы найти автомобиль на поверхности планеты. '3.141592653589' (то, что я помню с головы) может, вероятно (хотя я еще не проверил) найти горох в солнечной системе :-) – paxdiablo

2

независимо от того, как они рассчитываются, они должны возвращать одно и то же значение

Ваши ожидания неверны. В IEEE-754 только базовые операторы (+-*/) и sqrt должны быть правильно закруглены. Трансцендентный функции как sin, cos, exp ... не требуется, потому что это очень сложный

Там нет стандарта, который требует верного округления трансцендентных функций. IEEE-754 (2008) рекомендует, но не требует, чтобы эти функции были правильно закруглены.


Теперь, если вы посмотрите на ваши ценности

         ↓ 
0.70710678118654746 = 0x1.6a09e667f3bccp-1 
0.70710678118654757 = 0x1.6a09e667f3bcdp-1 
             ↑ 

Таким образом, они находятся в пределах 1ulp друг от друга, и достаточно точен в два раза точность

Не поймите меня неправильно, я знаю, что никогда не получит 100% точное значение этих цифр, но по крайней мере я ожидал, чтобы получить тот же «unprecise» значение греха и соз дополнительных углов

Существует не только один алгоритм для расчета sin и cos. Каждый из них будет правильным для некоторого набора входов, но некорректным для некоторых других. Они также имеют разные требования к памяти и времени, поэтому некоторые из них могут быть очень быстрыми с более высокой ошибкой, для некоторых потребуется гораздо больше времени и памяти, но они могут достичь гораздо большей точности.

Реализации компилятора могут использовать разные алгоритмы для этих функций, поэтому, если вам нужны согласованные результаты, используйте одну тщательно разработанную библиотеку на разных платформах. Например, GCC использует MPFR для достижения правильно округленных результатов независимо от платформ.

Среднесрочный центр GCC интегрирован с библиотекой MPFR. Это позволяет GCC оценивать и заменять во время компиляции вызовы на встроенные математические функции, имеющие постоянные аргументы с их математически эквивалентными результатами. При использовании MPFR GCC может генерировать правильные результаты независимо от реализации математической библиотеки или точности с плавающей точкой на платформе хоста.Это также позволяет GCC генерировать одинаковые результаты независимо от того, составляет один в нативной или кросс-компиляции конфигураций для конкретной мишени

https://gcc.gnu.org/gcc-4.3/changes.html#mpfropts

How does C compute sin() and other math functions?

+0

Спасибо! Это дает мне лучшее представление о том, почему моя программа терпит неудачу, когда у меня есть значения cos и sin, которые должны быть одинаковыми, я попытаюсь заставить их на самом деле быть одинаковыми, если это не работает, я попробую с другой библиотекой, как вы говорите! :) – Dimakhaerus

+1

Просто небольшое добавление: даже если у вас есть «точная» реализация 'sin' и' cos' (т. Е. Никогда не ошибается более чем на 0.5ulp), вы не получите одинаковые значения для синуса и косинуса здесь, так как входной аргумент не является точно PI/4 (в зависимости от того, как это значение будет округлено, синус или косинус будут больше). Фактически вы можете наблюдать аналогичную проблему при вычислении 'sin (M_PI)' (который не равен 0.0) – chtz