2012-12-08 16 views
7

Dlaczego tan 45 (0.7853981633974483 w radian) daje mi 0.9999? Co jest nie tak z następującym kodem?tan 45 daje mi 0,9999

System.out.println(Math.tan(Math.toRadians(45.0))); 

nie sądzę istnieje jakaś literówka w tutaj.

Jakie jest rozwiązanie?

+0

Prawdopodobnie zaokrąglić błąd. Ale to * powinno * zaokrąglić do 1 tak czy inaczej, jeśli wyświetla tylko 4 cyfry. – Mysticial

+2

Python daje mi '0.99999999999999989', niezależnie od liczby cyfr, które do niego wprowadzam. To prawdopodobnie błąd zmiennoprzecinkowy i błąd aproksymacji. – Blender

+0

Czy pominąłeś jakieś cyfry? –

Odpowiedz

16

Obliczenia zmiennoprzecinkowe często prowadzą do takich nieścisłości. Problem polega na tym, że liczby nie mogą być dokładnie reprezentowane w ustalonej liczbie bitów.

Aby podać inny przykład (w systemie dziesiętnym), wszyscy zgadzamy się, że 3 * (1/3) = 1. Jeśli jednak twój kalkulator ma tylko 4 miejsca dziesiętne, 1/3 będzie reprezentowany jako 0.3333. Gdy zostanie pomnożone przez 3, otrzymasz 0.9999 nie 1.

Jako dodatkowe informacje, zmiennoprzecinkowe w większości systemów są zwykle reprezentowane przy użyciu standardu IEEE754. Możesz go wyszukać lub odszukać stronę Wikipedii, by dowiedzieć się więcej. IEEE floating point

+0

jakie jest zatem rozwiązanie? – siaooo

+1

@siaooo Zaokrąglij do odpowiedniej liczby miejsc dziesiętnych, których potrzebujesz, dla 'tan (45)' to zaokrągli do 1. –

+0

@ScottChamberlain ok dzięki – siaooo

2

Użyj tego

double radians = Math.toRadians(45.0); 

System.out.format("The tangent of 45.0 degrees is %.4f%n", Math.tan(radians)); 
+1

-1 Ta odpowiedź nie rozumie, że problemem jest arytmetyka zmiennoprzecinkowa. Konwertowanie radianów na stopnie nie jest. –

+2

@woodchips Nie sądzę, że ta odpowiedź jest twierdzeniem, że konwersja radianów na stopnie jest problemem. Sądzę jednak, że ** przekształcanie radianów na stopnie jest w pewnym stopniu kwestią **: gdybyśmy znormalizowali poprawnie zaokrąglone transcendentalne funkcje (my nie), to gdybyśmy mieli funkcję styczną, która akceptuje stopnie (my haven t), wtedy wynik tej funkcji zastosowany do 45 będzie wynosił 1. Jednak poprawnie zaokrągliśmy funkcję styczną radianową, którą mamy, nie stosujemy jej do π/4, ale do najbliższego 'podwójnego', a zatem ledwie możemy spodziewaj się, że otrzymasz 1 w zamian. –

+0

@woodchips Poza tym, ta odpowiedź to obcięcie miejsc po przecinku ** w momencie konwersji na wynik dziesiętny dla wyniku **. To wciąż stawia ją o jedną głowę powyżej "obciętej liczby zmiennoprzecinkowych liczb zmiennoprzecinkowych do ustalonej liczby miejsc po przecinku", z której można zobaczyć wiele pytań i odpowiedzi na temat StackOverflow. –

0

To pewnie dlatego tan(45) wynosi 1, a reszta to zaokrąglenie błędu. Obliczenia zmiennoprzecinkowe są mało prawdopodobne, aby dać dokładne wyniki, ze względu na sposób działania obliczeń zmiennoprzecinkowych.

+3

To dlatego, że bierzesz styczną * najbliższej podwójnej * do pi/4. 'tan' w bibliotece matematycznej jest poprawnie zaokrąglone. Obliczenia zmiennoprzecinkowe polegają na tym, że działają szybko, a * dają * dokładne wyniki, jeśli zwracasz uwagę na to, co robisz. – tmyklebu

10

Najbliżej double do pi/4 jest dokładnie0x1.921fb54442d18p-1. Styczna tego podwójnego, na więcej bitów niż potrzebujesz, to 0x1.fffffffffffff72cece67p-1. Zaokrąglanie do najbliższego double daje dokładnie0x1.fffffffffffffp-1, ponieważ 0x1.fffffffffffff72cece67p-1 jest mniejszy niż 0x1.fffffffffffff8p-1.

+0

Tak! Dobra odpowiedź! Czy Java określa poprawnie zaokrąglone funkcje transcendentalne? –

+1

@PascalCuoq: Java nie prosi o prawidłowe zaokrąglenie. Określa (patrząc na dokumentację API, która moim zdaniem jest kanoniczna), że odpowiedzi muszą znajdować się w granicach 1 ulp poprawnego wyniku i że, o ile biegun opalenizny nie jest berween 'x' i' y', 'Math.tan (x) - Math.tan (y) 'nie ma przeciwnego znaku jako tan (x) -tan (y). – tmyklebu

+0

Szybkie wyszukiwanie w Google zaprowadziło mnie z powrotem do klasycznego http://www.cs.berkeley.edu/~wkahan/LOG10HAF.TXT. Warto ponownie przeczytać. –

Powiązane problemy