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 .
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 . Jakim cudem?
To samo się dzieje dla liczby: 2712939616709395196 ≠ 2712939616709395000 oraz dla liczby
9244681613480703 ≠ 9244681613480704. 9999999999999999 ≠ 10000000000000000
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 9999999999999999 ≠ 10000000000000000.
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 .