2016-11-24 14 views
-1

у меня есть:Math.sin давая странные ответы

double num1 = sc.nextInt(); 

Я использовал:

double sin = Math.sin(Math.toRadians(num1)); 

и сделал вывод:

if(calc.contains("sin")) { 
    System.out.println (sin); 
} 

если я напечатал для num1:

30 и он вычисляет грех. Это дает мне 0.49999999999999994

+1

Пожалуйста, прочитайте [Что каждый компьютерный ученый должен знать о арифметике с плавающей точкой] (https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) –

+1

Извините, я не подумайте, что это дубликат этого вопроса. Обычная «математика с плавающей запятой» объясняет, почему определенные цифры типа «0,1» не могут быть представлены точно. Но 0,5 ** ** можно представить точно, поэтому ответ на этот вопрос должен быть чем-то другим. – ajb

+0

@ajb Да, 0,5 можно представить точно, но pi/6 не может. Итак, мы преобразуем точный 30 в неточный pi/6, а затем найдем синус, который не совсем равен 0,5. –

ответ

0

sin (30 °), конечно, 0,5, но нет словаря, который содержит ключ 30° со значением 0.5, поэтому компьютеру необходимо его вычислить.

enter image description here

формула показывает выше.

Вычислим грех (30 °), 30 ° = π/6, так что е (х) = π/6 - π^3/1296 - π^5/933120 - ....

И то в этом процессе ошибка точности может привести к «непредсказуемым» (фактически предсказуемым) проблемам.

+0

Я думаю, что этот ответ промахивается. Контракт на 'sin' говорит, что результат должен быть в пределах 1 ULP от« правильного ». Но проблема заключается в аргументе 'sin' - это' π/6', в котором происходит неточность. –

+0

@DavidWallace Вы правы, неточность 'π/6' является фактической ошибкой точности в этом случае. – Sraw

2

№/6 не может быть представлен точно на компьютере (он также не может быть представлен точно на бумаге). Это приведет к тому, что результат будет немного отброшен. Используя «bc», высокоточный калькулятор Unix (примечание: я не знаю, насколько это точно для синуса и косинуса), я считаю, что фактическое значение в вашей программе будет π/6 + ε, где ε - около 5.3604 x 10 -17. Используя формулу для sin (x + y), ожидаемым результатом должно быть sin π/6 cos ε + sin ε cos π/6. cos ε составляет около 1 - 10 -33, поэтому этого разницы будет недостаточно, чтобы повлиять на результат. Однако sin ε cos π/6 составляет около 4,64 × 10 -17. Таким образом, фактический результат должен быть примерно 0,4999999999999999535774978 вместо 0,5.

Этот результат не будет представлен точно в double. Поскольку double имеет мантисс из 52 бит, числа, значения которых> = 0,25 и < 0,5, могут быть представлены числами, которые отключены на целых 2 -54. double, используемый для представления этого результата, будет 0.499999999999999944488848768742172978818416595458984375. Когда это будет напечатано с помощью System.out.println, оно остановится после того, как будет напечатано определенное количество знаков после запятой, поэтому это будет усечено до 0,4999999999999999994, что является результатом, который вы видите. (Количество отображаемых цифр обсуждается в [http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#toString-double-](this javadoc).

+0

Извините, я этого раньше не видел. – ajb