Matematyka.runda (num) vs num.tofixed (0) i niespójności przeglądarki

Rozważ następujący kod:

for (var i=0;i<3;i++){
   var num = i + 0.50;
   var output = num + " " + Math.round(num) + " " + num.toFixed(0);
   alert(output);
}

W Operze 9.63 dostaję:

0.5 1 0

1.5 2 2

2.5 3 2

W FF 3.03 dostaję:

0.5 1 1

1.5 2 2

2.5 3 3

W IE 7 dostaję:

0.5 1 0

1.5 2 2

2.5 3 3

Zwróć uwagę na pogrubione wyniki. Dlaczego są to niespójności prezent? Czy to oznacza, że toFixed(0) Należy unikać? Jaki jest prawidłowy sposób zaokrąglania liczby do najbliższej liczby całkowitej?

Author: Mark Amery, 2009-02-19

6 answers

Edit: aby odpowiedzieć na swoją edycję, użyj Math.round. Możesz również prototypować obiekt Number tak, aby spełniał Twoje polecenia, jeśli wolisz taką składnię.

Number.prototype.round = function() {
  return Math.round(this);
}
var num = 3.5;
alert(num.round())

Nigdy wcześniej nie używałem Number.toFixed() (głównie dlatego, że większość bibliotek JS dostarcza toInt() metoda), ale sądząc po twoich wynikach powiedziałbym, że bardziej spójne byłoby stosowanie metod Math(round, floor, ceil) Następnie toFixed jeśli spójność między przeglądarkami jest tym, czego szukasz.

 29
Author: tj111,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 18:57:34

FF robi dobrze z toFixed, ponieważ krok 10 poniżej mówi "Jeśli są dwa takie n, wybierz większe n".]}

I jako Grant Wagner powiedział: użyj matematyki.ceil (x) lub Matematyka.floor(x) zamiast x.tofixed () .

Wszystko poniżej pochodzi ze specyfikacji języka ECMAScript :

15.7.4.5 Number.prototype.toFixed (fractionDigits)

Zwraca łańcuch zawierający liczbę reprezentowaną w punkcie stałym notacja z fractionDigits cyfry po przecinku. Jeśli fractionDigits jest niezdefiniowana, 0 zakłada się. W szczególności wykonaj następujące kroki:

  1. niech f będzie ToInteger(fractionDigits). (If fractionDigits is undefined, ten krok daje wartość 0).
  2. If f < 0 or f > 20, throw a RangeError exception.
  3. niech x będzie tą wartością liczbową.
  4. jeśli x jest NaN, zwraca łańcuch "NaN".
  5. niech s będzie ciągiem pustym.
  6. jeśli x ≥ 0, przejdź do kroku 9.
  7. niech będzie "-".
  8. niech x = –x.
  9. jeśli x ≥ 10^21, pozwól m = ToString(x) i przejdź do kroku 20.
  10. niech n będzie liczbą całkowitą, dla której dokładna wartość matematyczna n ÷ 10^f – x jest jak najbliżej zera. Jeśli są dwa takie n, wybierz większe n.
  11. Jeśli n = 0, niech m będzie ciągiem "0". W przeciwnym razie niech m będzie łańcuch składający się z cyfr reprezentacji dziesiętnej z n (w kolejności, bez zer wiodących).
  12. jeśli f = 0, przejdź do kroku 20.
  13. niech k będzie liczbą znaków w m.
  14. jeśli k > f, przejdź do kroku 18.
  15. niech z będzie ciągiem składającym się z f+1–k wystąpień znak '0'.
  16. niech m będzie konkatenacją łańcuchów z i m.
  17. niech k = f + 1.
  18. niech a będzie pierwszym k–f znakiem m, a b będzie pozostałe f znaki m.
  19. niech m będzie konkatenacja trzech strun a, ".", i b.
  20. zwraca konkatenację łańcuchów s i m.

Właściwością length metody toFixed jest 1.

Jeśli metoda toFixed jest wywołana z więcej niż jednym argumentem, to zachowanie jest nieokreślone (patrz punkt 15).

Implementacja może rozszerzyć zachowanie toFixed dla wartości fractionDigits mniejsze niż 0 lub większe niż 20. W tym przypadku toFixed niekoniecznie rzuci RangeError dla takich wartości.

Uwaga wyjście toFixed może być bardziej precyzyjne niż toString dla niektóre wartości, ponieważ toString wyświetla tylko wystarczająco znaczące cyfry aby odróżnić liczbę od sąsiednich wartości liczbowych. Na przykład, (1000000000000000128).toString() zwraca "1000000000000000100", podczas gdy (1000000000000000128).toFixed(0) zwraca "1000000000000000128".

 11
Author: some,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05

Aby rozwiązać swoje dwa oryginalne problemy / pytania:

Matematyka.runda (num) vs num.toFixed (0)

Problem tkwi w błędnym przekonaniu, że powinny one zawsze dawać ten sam rezultat. W rzeczywistości rządzą nimi różne zasady. Spójrz na liczby ujemne, na przykład. Ponieważ Math.round używa "round half up" jako zasady, zobaczysz, że Math.round(-1.5) ewaluuje do -1, mimo że Math.round(1.5) ewaluuje do 2.

Number.prototype.toFixed, z drugiej strony, używa co jest zasadniczo równoważne "zaokrąglenie połowy od zera" zgodnie z zasadą, zgodnie z Krok 6 spec , która zasadniczo mówi, aby traktować negatywy jako liczby dodatnie, a następnie dodać znak ujemny na końcu. Tak więc, (-1.5).toFixed(0) === "-2" i (1.5).toFixed(0) === "2" są prawdziwymi wyrażeniami we wszystkich przeglądarkach zgodnych ze specyfikacją. Zauważ, że te wartości są ciągami znaków, a nie liczbami. Zauważ ponadto, że zarówno -1.5.toFixed(0), jak i -(1.5).toFixed(0)=== -2 (liczbą) ze względu na pierwszeństwo operatora.

Przeglądarka niespójności

Większość nowoczesnych przeglądarek-lub przynajmniej te, których można się spodziewać w momencie pisania tego tekstu z wyjątkiem IE-wszyscy powinni poprawnie wdrożyć specyfikacje. (Zgodnie z komentarz Renee , toFixed problem, który wskazałeś w Operze został naprawiony, prawdopodobnie od czasu, gdy zaczęli używać tego samego silnika JS co Chrome.) Nadal warto to powtórzyć, nawet jeśli specyfikacje były konsekwentnie wdrażane we wszystkich przeglądarkach, zachowanie zdefiniowane w specyfikacji, szczególnie dla toFixed zaokrąglania, może być nadal nieco nieintuitywne dla" zwykłych śmiertelników "programistów JS, którzy oczekują prawdziwej matematycznej dokładności-zobacz Javascript Tofixed Not Rounding i ten" działa zgodnie z przeznaczeniem " błąd, który został złożony na silniku JS V8 dla przykładów.

Podsumowanie

W skrócie, są to dwie różne funkcje z dwoma różnymi typami zwrotów i dwoma różnymi zestawami reguł zaokrąglania.

Jak inni sugerowane, chciałbym również powiedzieć "użyj dowolnej funkcji pasuje do konkretnego przypadku użycia" (zwracając szczególną uwagę na specyfikę toFixed, zwłaszcza błędnej implementacji IE). osobiście skłaniałbym się bardziej ku zaleceniu jakiejś wyraźnej kombinacji Math.round/ceil/floor, ponownie, jak inni wspominali. Edit: ...chociaż po powrocie i przeczytaniu twojego wyjaśnienia, Twój przypadek użycia (zaokrąglenie do liczby całkowitej) zdecydowanie wymaga trafnie nazwanego Math.round funkcja.

 9
Author: Noyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-21 15:27:42

Tofixed () Zwraca wartość łańcuchową. Z Języka Javascript: Definitywny Przewodnik

Zamienia liczbę na łańcuch zawierający określoną liczbę cyfry po miejscu dziesiętnym.

Matematyka.round () Zwraca liczbę całkowitą.

Najwyraźniej, toFixed () wydają się być bardziej przydatne dla pieniędzy, na przykład,

'$' + 12.34253.toFixed(2) = '$12.34'

Wielka szkoda, że toFixed () nie wydaje się zaokrąglać jak należy!

 6
Author: Matt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-24 04:09:59

Zamiast toFixed(0) użyj Math.ceil() lub Math.floor(), w zależności od tego, co jest wymagane.

 2
Author: Grant Wagner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-19 18:44:40

To na pewno tak wygląda, jeśli otrzymujesz niespójne odpowiedzi.

Mogę się tylko domyślać, że twoim celem za pomocą tofixed(0) jest przekształcenie liczby dziesiętnej w liczbę całkowitą, w tym momencie polecam Math.piętro (). Jest trochę więcej dyskusji na temat najlepszego sposobu, aby to zrobić w to pytanie .

 0
Author: Daniel Lew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:08