• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Błędny wynik tangensa Javascript

VPS Starter Arubacloud
+1 głos
341 wizyt
pytanie zadane 21 września 2021 w JavaScript przez Martita Bywalec (2,520 p.)

Dzień dobry jestem początkująca.

Zrobiłam kalkulator, który przelicza stopnie alfa na sinus alfa, cosinus alfa, tangens alfa. Przy wprowadzeniu liczbę 90 stopni przez użytkownika wynik tangensa powinien pokazać ∞ lub infity lub w miejsce wyniku nic nie powinno być (wynik nie istnieje). Natomiast mi wynik pokazuje błędny 16331239353195370 = 16331239353195370.0000 tangens alfa. Jeśli użytkownik wprowadzi liczbę 45 stopni to wynik pokazuje poprawny 1 = 1.0000 .

Proszę o pomoc i wskazanie gdzie jest błąd.

<!DOCTYPE html>
<html lang="pl">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="stopien_sinus.js"></script>
</head>

<body>
    <form id="oblicz" action="" method="post" autocomplete="off">
        <div>
            <h3>Przelicznik Stopnia Alfa na Sinus Alfa</h3>
            Stopień Alfa <input type="number" id="SA"><br>
            Sinus: <span id="SIN">= </span><br><br>
            Cosinus: <span id="KOS">= </span><br><br>
            Tangens: <span id="TAN">= </span><br><br>
            <input type="button" value="Oblicz" onclick="myFunction()">
            <input type="reset" value="RESETUJ" onclick="resetuj()">
        </div>
    </form>

</body>

</html>

 

function myFunction() {
const SA = parseInt(document.getElementById("SA").value);
const SIN = Math.sin(parseInt(SA) * Math.PI / 180);
const KOS = Math.round(Math.cos(parseInt(SA) * Math.PI / 180));
const TAN = Math.round(Math.tan(parseInt(SA) * Math.PI / 180));
    document.getElementById("SIN").innerHTML = Math.sin(SA * Math.PI / 180) + ' = ' + SIN.toFixed(4);
    document.getElementById("KOS").innerHTML = Math.round(Math.cos(SA * Math.PI / 180)) + ' = ' + KOS.toFixed(4);
    document.getElementById("TAN").innerHTML = Math.round(Math.tan(SA * Math.PI / 180)) + ' = ' + TAN.toFixed(4);
   
return false;
}

function resetuj () {

    document.getElementById("SIN").innerHTML = '';
    document.getElementById("KOS").innerHTML = '';
    document.getElementById("TAN").innerHTML = '';
   
}

 

3 odpowiedzi

+2 głosów
odpowiedź 26 września 2021 przez Bosswell Nałogowiec (36,470 p.)
wybrane 26 września 2021 przez Martita
 
Najlepsza

Dla przyszłych poszukiwaczy rozwiązanie wyciągnięte z komentarzy.
Przy wyznaczeniu nieskończoności tangensa dla konkretnych stopni, możemy skorzystać z jego okresowości w celu zredukowania stopni.

Dla 400
(int) 400 / 180 = 2
400 - 2 * 180 = 40
--------
Dla 270
(int) 270 / 180 = 1
270 - 1 * 180 = 90
--------
Dla -90
(int) -90 / 180 = 0
-90 - 0 * 180 = -90
--------
Dla -450
(int) -450 / 180 = -2
-450 - (-2 * 180) = -450 + 360 = -90
--------
a = stopnie;
b = parseInt(a / 180);
c = Math.abs(a - b * 180);

if (c === 90) {
   console.log("Brak rozwiązań");
}

Podane przez użytkownika stopnie, redukujemy przez jego okres 180 stopni. Po redukcji, tangens nie będzie miał rozwiązań dla 90 i -90 stopni.

Aplikacja rozwiązania do zadania:

function myFunction() {
  const container = document.getElementById("TAN");
  const deegres = parseInt(
    document.getElementById("SA").value
  );
 
  const normalizedDeegres = Math.abs(
    deegres - parseInt(deegres / 180) * 180
  );
 
  if (normalizedDeegres === 90){
      container.innerHTML = '<b>Nie istnieje! - &#8734</b>';
 
      return;
  }
 
  container.innerHTML = `<b>${Math.tan(deegres)}</b>`;
}

 

+1 głos
odpowiedź 21 września 2021 przez edutomek Dyskutant (8,380 p.)
Czyli działa (w miarę) poprawnie. Powinno być +inf, jest jakaś bardzo duża liczba.

Po pierwsze - Math.PI to nie jest liczba PI. To jest pewne przybliżenie liczby PI (której dokładnie nie da się zapisać, bo jest to liczba niewymierna). Mamy więc pierwsze źródło błędów numerycznych - operowanie na wartościach przybliżonych.

Wyliczając kąt w radianach nie wyliczymy dokładnie tego PI, PI/2 (innych kątów też nie), lecz jedynie ich pewne przybliżenia.

W zależności od tego, jakie to będą przybliżenia, otrzymamy mniej lub bardziej dokładne wyniki.

Nie wspominając o tym, jak ten tangens jest zaimplementowany. Gdzieś znalazłem informację, że jest to sin(x) / cos(x) - ale jak są zaimplementowane te sinusy i cosinusy? To są jakieś algorytmy numeryczne, a więc wyniki będą przybliżone (czasami lepiej, czasami gorzej) i obarczone błędami numerycznymi.

No i potem takie "kwiatki" wychodzą.

Zresztą nie trzeba funkcji trygonometrycznych, żeby doświadczyć problemów numerycznych: proponuję wpisać w JS a = 0.1, a potem sprawdzić wynik a + a + a (u mnie np. wcale nie wychodzi 0.3; co ciekawe, przy dalszym dodawaniu są poprawne wyniki, ale już przy ośmiu składnikach też nie mam 0.8). Można też popróbować z a = 0.01, a = 0.001... Ciekawskim polecam sprawdzić a = 0.125 i zastanowić się, dlaczego dla tej interesującej wartości akurat wszystko liczone jest poprawnie.

Generalnie, operując na liczbach zmiennoprzecinkowych, należy przyjąć pewną dokładność. Tzn. nie porównujemy wartości zmiennych do stałych, lecz sprawdzamy, czy wartość bezwzględna różnicy jest odpowiednio mała: if ( Math.abs(a - 2) < EPSILON ) ...

Podobnie można postąpić z tymi kątami. Nie wyliczymy dokładnie pewnych wartości (np. tych 45, 90, czy 180 stopni) - to może warto napisać własną funkcję, która dla tych specyficznych wartości (z pewną dokładnością) zwróci poprawny wynik?
komentarz 24 września 2021 przez Bosswell Nałogowiec (36,470 p.)
function myFunction() {
  const container = document.getElementById("TAN");
  const deegres = parseInt(
    document.getElementById("SA").value
  );

  const normalizedDeegres = Math.abs(
    deegres - parseInt(deegres / 180) * 180
  );

  if (normalizedDeegres === 90){
      container.innerHTML = '<b>Nie istnieje! - &#8734</b>';

      return;
  }

  container.innerHTML = `<b>${Math.tan(deegres)}</b>`;
}

 

komentarz 25 września 2021 przez Martita Bywalec (2,520 p.)
Dzięki. Szczegółowo przeanalizowałam kod i teraz już wiem jak to się robi. Ja właśnie przy robieniu różnych zadań uczę się JavaScript.
komentarz 25 września 2021 przez Martita Bywalec (2,520 p.)

@Bosswell, Jak mogę oznaczyć że Twoja odpowiedź jest najlepsza?

komentarz 26 września 2021 przez Bosswell Nałogowiec (36,470 p.)
Dodałem nową odpowiedź z podsumowaniem
komentarz 26 września 2021 przez Martita Bywalec (2,520 p.)
Dzięki. Zaznaczyłam Twoją odpowiedź jako najlepszą.
0 głosów
odpowiedź 22 września 2021 przez Martita Bywalec (2,520 p.)
edycja 24 września 2021 przez Martita

POMÓŻCIE BŁAGAM

Po wprowadzeniu liczby 90 stopni pokazuje wynik Nie istnieje ale po wprowadzeniu 45 wynik  też pokazuje Nie istnieje zamiast 1.0000.

Nie wiem gdzie mam błąd. Błagam pomóżcie.

function myFunction() {
const SA = parseInt(document.getElementById("SA").value);
const TAN = Math.abs(parseInt(SA) - (parseInt(SA)  / 180) * 180);
   if (TAN === SA){
        document.getElementById("TAN").innerHTML = Math.abs(SA - (SA / 180) * 180) + '=' + ' <b>Nie istnieje! - &#8734</b> ' + TAN.toFixed(4);
    }
  
function resetuj () {
    document.getElementById("TAN").innerHTML = '';
}

 

komentarz 24 września 2021 przez Martita Bywalec (2,520 p.)
Błagam pomóżcie . Nie wiem jak to zrobić. Szukałam i nie znalazłam.

Podobne pytania

0 głosów
1 odpowiedź 180 wizyt
0 głosów
1 odpowiedź 306 wizyt
pytanie zadane 30 sierpnia 2022 w C i C++ przez benny13 Obywatel (1,150 p.)
0 głosów
1 odpowiedź 1,159 wizyt

92,765 zapytań

141,690 odpowiedzi

320,503 komentarzy

62,106 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...