Floating-point problem

Jozdowska Edyta · 22 Luty 2020

Ten post został zainspirowany błędem na jaki natknęłam się rozwiązując zadanie odnośnie “HappyNumbers”. Zachęcam do przeczytania bo są to naprawdę fajne liczby i zasługują na swoje miano wesołych :wink:.

Rozwiązując wyżej wspomniane zadanie w js i w php natknęłam się na błąd, który uniemożliwiał mi przejście wszystkich testów sprawdzających poprawność kodu.
Otóż liczby, które powinny być wesołe były niewesołe. Byłam pewna, że kod jest poprawny, działał w pythonie, skąd więc rozbieżność?

Duże liczby w JS / PHP

Spróbujmy wyświelić liczbę 16525534153749833 w js jako liczbę. Rezultatem będzie: 16525534153749832 :thinking:. Jakim cudem?
To samo się dzieje dla liczby: 2712939616709395196 ≠ 2712939616709395000 oraz dla liczby
9244681613480703 ≠ 9244681613480704. 999999999999999910000000000000000
Wyświetlane jest zupełnie inna liczba niż podawana.

Wniosek: Istnieją liczby, które podawane typem jako liczby nie są możliwe do wyświetlenia / użycia np. w przeglądarce.

Stąd do mojego algorytmu trafiały nie te liczby. Zapisując powyższe jako stringi, nie ma problemu. Poniżej pen z przykładami:

Zobaczmy php

1
2
3
var_dump(679927533571841532898);

// float(6.7992753357184E+20)

Dlaczego tak się dzieje?

Zobaczmy dokumentację:

In JavaScript, Number is a numeric data type in the double-precision 64-bit floating point format (IEEE 754). In other programming languages different numeric types can exist, for examples: Integers, Floats, Doubles, or Bignums 1.

Przekładając na polski. Liczby w js nie rozróżniają typów liczb np. short, long, floating-point, integer itp., jak większość języków programowania. PODAWANE SĄ ZAWSZE jako 64-bitowy floating-point.

Oznacza to, że niektórych liczb całkowitych nie jesteśmy w stanie przedstawić w typie liczby bez utraty ich precyzji, stąd 999999999999999910000000000000000.

W php natomiast według dokumentacji:

If PHP encounters a number beyond the bounds of the integer type, it will be interpreted as a float instead. 2.

Co oznacza, że jeśli php napotka liczbę, która przekracza granicę liczby całkowitej w jakiej może być zapisana, zostanie ona zinterpretowana jako liczba zmiennoprzecinkowa. Tak właśnie się stało dla liczby 679927533571841532898 lub 1646476620141690717724578. Liczby te są po prostu za duże.

1
2
var_dump(1646476620141690717724578);
//float(6.7992753357184E+20)

Floating-point precision

Temat precyzyjności floating-point bardziej jest znany do wykonywania obliczeń z liczbami po przecinku np: 0.1 + 0.2

1
0.1 + 0.2 => 0.30000000000000004

Czy to w py, czy w js czy php.

Baaaardzo dokładnie jest na ten temat napisane What every computer Scientist should know about floating-point arithmetic.

Ta nieprecyzyjność jest mi znana. Jednak nie odniosłabym jej nigdy do problemu reprezentacji liczby całkowitej :smile:.

Jozdowska Edyta * FullStack Developer

Pisanie kodu jest moją pasją. Zajmuję się tym od przeszło 10 lat, z większą lub mniejszą intensywnością.
Piszę kod w PHP, JS, SCSS i Python. Nie stronię też od poznawania nowych, lub jak kto woli starych rozwiązań jak Jekyll oraz innych języków np. Java.

więcej o mnie