tan ( pi/2 ) в target-c (math.h) не undefined

Я написал этот тестовый код:

NSLog(@"%g", tan(M_PI / 2.0));

и вывод консоли:

1.63312e+16

Проблемы связаны с приближением, верно? Я сделал какие-то ошибки или функция tan в math.h действительно сама не обрабатывает этот случай (возвращая мне БЕСКОНЕЧНОСТЬ)? Должен ли я сам обрабатывать эти входные данные (например, когда я получаю входное значение pi/2, я возвращаю сообщение об ошибке) или есть лучший (более элегантный) способ получить правильное значение?

Спасибо


person Massimo    schedule 10.12.2011    source источник
comment
Вы приняли неверный ответ.   -  person Keith Thompson    schedule 29.01.2012


Ответы (1)


Это потому, что M_PI != real pi не может быть представлено, поэтому то, что вы получаете от M_PI, является аппроксимацией числа пи, тангенсом которого является то, что вы получаете.
Редактировать: следующее:

printf("cos(M_PI / 2) = %.30f\nsin(M_PI / 2) = %.30f\n",
       cos(M_PI / 2), sin(M_PI / 2));

будет печатать

cos(M_PI / 2) = 0.000000000000000061232339957368
sin(M_PI / 2) = 1.000000000000000000000000000000

Что показывает, что cos(pi / 2) не равно нулю.
Выполнение деления даст

1.63312393531953E16

что именно вы получаете.

person Dani    schedule 10.12.2011
comment
Это правильный ответ, потому что бесконечность может быть представлена ​​числами с плавающей запятой. - person ; 10.12.2011
comment
Это правда, но функции sin и cos также являются приблизительными и могут корректно с этим справиться. Вызов cos на M_PI вернет -1 правильно, а не приближение, а sin вернет 0. - person Itai Ferber; 10.12.2011
comment
Спасибо, но я уже знал, что на самом деле это то, что я имел в виду, говоря о проблемах, о приближении ... Я сомневался в том, что tan возвращает значение, которое не является БЕСКОНЕЧНОСТЬЮ, как я ожидал ... - person Massimo; 10.12.2011
comment
@ItaiFerber: потому что не возвращает -1. если вы установите presicion, он вернет что-то вроде -0,99999999, а sin вернет что-то вроде 0,00000001. Я отредактирую вопрос с доказательством - person Dani; 10.12.2011
comment
@Massimo: он возвращает другое значение, потому что вы вводите другой ввод. вы не передаете pi/2, вы передаете близкое к нему значение. вот почему вы не получаете вывод для pi/2, вы получаете вывод для значения, близкого к нему. - person Dani; 10.12.2011
comment
NSLog(@%g, cos(M_PI)); дает ровно -1 - person Massimo; 10.12.2011
comment
Я не знаю, что вы получите, когда запустите код, но я получаю следующее: pastie.org/2996608 (выглядит довольно точно для меня). - person Itai Ferber; 10.12.2011
comment
@ItaiFerber: это потому, что %f имеет ограниченную точность. чтобы получить полную точность, используйте %.30f - person Dani; 10.12.2011
comment
@Massimo: это потому, что %g имеет ограниченную точность. чтобы получить полную точность, используйте %.30f - person Dani; 10.12.2011
comment
@Massimo: и проблема не в cos(M_PI), проблема в cos(M_PI / 2) - person Dani; 10.12.2011
comment
@Dani Я знаю, но, поскольку я имею дело с числами двойной точности, а sin, cos и т. Д. Math.h также имеют дело с double, я ожидаю, как и для sin и cos, что основные входные случаи (M_PI, M_PI /2,..) обрабатываются правильно.. - person Massimo; 10.12.2011
comment
@Massimo: double не точно. это просто двойная точность, как следует из названия. - person Dani; 10.12.2011
comment
@ Дэни, спасибо, но я не настолько невежественен .. :) Я знаю, что такое число с двойной точностью .. Уже прошел первый курс информатики ;) Может быть, я не могу достаточно хорошо объяснить из-за моего плохого английского .. - person Massimo; 10.12.2011
comment
@Massimo: Я думаю, вы говорите о том, что cos и sin имеют особый случай. они могли бы это сделать, но тогда не используйте M_PI / 2, используйте M_PI_2, что является лучшим приближением к pi / 2, жестко закодированному (и, возможно, имеющему особые случаи) - person Dani; 10.12.2011
comment
@Dani Я бы хотел, чтобы я мог это сделать, но я не могу, так как пользователь решает, на какое число M_PI нужно разделить .. - person Massimo; 10.12.2011
comment
@Dani M_PI_2 и M_PI / 2 на самом деле являются одним и тем же числом и, к сожалению, не предлагают никаких особых случаев. (Но это всего лишь придирки.) Тем не менее, я думаю, мы все согласны с тем, что эта функция не возвращает бесконечность, это ошибка, верно? - person Itai Ferber; 10.12.2011
comment
@ItaiFerber: это не ошибка в функции. только потому, что у него есть особый случай для некоторого числа, которое не может быть представлено, он не должен перемещать этот особый случай на ближайшее представимое число. если она вернет бесконечность для M_PI / 2, то я назову это ошибкой в ​​функции, потому что это неправильный ответ. ошибка возникает в M_PI, это не должно называться так, это должно называться M_CLOSEST_TO_PI - person Dani; 10.12.2011
comment
@Дани Хорошо, я уступаю. Есть правота, а есть прагматичность. Да, вы правы - тангенс любого числа, немного отличающегося от пи/2, не должен возвращать бесконечность, по крайней мере, математически. Но, с практической точки зрения, если вы можете представить число от пи до х цифр, тогда отношение пи к этому количеству цифр должно быть вашей базовой линией для числа пи, и это должен быть особый случай, когда это число считается истинным значением числа пи. И он должен считать половину этого значения половиной числа пи. Потому что вы не можете быть более точны — вы ограничены системой. - person Itai Ferber; 10.12.2011
comment
@Dani Вы говорите, что функция tan никогда не должна возвращать бесконечность или отрицательную бесконечность, потому что она никогда не может получить истинное значение пи / 2 или 3 * пи / 2 (или какое-то другое кратное). Математически это правильно. Но ради прагматизма он должен принять самое близкое возможное значение числа пи, которое он мог бы получить, и вызвать это число пи, потому что это ограничения, с которыми ему приходится работать. Вот где мы отличаемся в наших линиях мысли. Ограниченное определенным представлением, M_PI_2 должно считаться пи/2, потому что вы не сможете приблизиться к этому. - person Itai Ferber; 10.12.2011
comment
@ItaiFerber: тогда вы получаете два определения загара: загар с программным ограничением и математический загар. тому, кто писал стандартную библиотеку, больше нравился математический загар. если вам нужно программно ограничить загар, как и любая другая функция, которая вам нужна, которой нет в стандартной библиотеке, вы должны написать ее самостоятельно - person Dani; 10.12.2011
comment
Я согласен с @ItaiFerber. Поскольку библиотека определяет M_PI как пи, она должна вообще рассматривать его как пи и работать с приближением, как система делает с каждой операцией. - person Massimo; 11.12.2011
comment
@ItaiFerber: я не согласен. Любая возня с приблизительными значениями, как вы предполагаете, будет означать, что вы не можете выполнять правильные вычисления с числами, которые действительно близки, но не равны пи/2. Невозможно точно представить pi/2 в числах с плавающей запятой, и любой, кто пишет программное обеспечение, выполняющее вычисления с плавающей запятой, должен понимать это и иметь дело с последствиями. - person Keith Thompson; 29.01.2012
comment
@KeithThompson Ребята, вы правы. Мой ответ неверен; жаль, что я больше не думал о своих аргументах, прежде чем браться за эту тему в пылу момента. К сожалению, я не могу удалить свой ответ, потому что он принят. Для протокола, я согласен с вами. - person Itai Ferber; 30.01.2012