Kiedy programowałem w C ++ kilka dni temu, popełniłem ten błąd (że mam historię!). W jednej części mojego kodu miałem 1/6 i spodziewałem się, że będzie to 0.16666666666, co nie jest prawdą. Jak wszyscy wiemy, wynikiem jest 0 - C, C ++, Java, Python - wszystkie zachowują się tak samo.
Publikuję go na mojej stronie na Facebooku, a teraz trwa debata na temat tego, czy istnieje język programowania, w którym 1/6
zachowuje się tak samo jak 1.0/6.0
.
programming-languages
Pouja
źródło
źródło
>> 1 / 6
->== 0.166666666666667
1/6
jest w rzeczywistości 1/6 (typ ułamkowy), co w przypadku przymusuDouble
wynosi 1,66666 ...Odpowiedzi:
Czy wszyscy zapomnieli o Pascalu?
1/6
daje0.1666666...
(z dowolną obsługiwaną precyzją).1 div 6
daje0
Jest dyskusyjne, czy reguła C jest błędem. Prawie wszystkie operatory arytmetyczne C, w których operandy są tego samego typu, dają wynik tego samego typu. Można powiedzieć coś o spójności.
Ponadto, ponieważ C jest głównie ukierunkowany na kod na poziomie systemu, większość programów C wcale nie używa zmiennoprzecinkowych. Pewnego razu przypadkowe dodanie kodu zmiennoprzecinkowego do programu, który inaczej nie potrzebowałby, może być poważnym problemem. Prawdopodobnie nadal tak jest w przypadku małych systemów wbudowanych - które znów są głównym celem dla C.
W większości programów typu C skrócenie podziału liczb całkowitych jest prawdopodobnie tym, czego chcesz.
Jeśli
1 / 6
uzyskano wynik zmiennoprzecinkowy w C, to:double
może to wydawać się naturalnym wyborem, ale możesz preferować dodatkową precyzjęlong double
)C mógł zapewnić osobne operatory dla dwóch rodzajów podziału, ale drugi punkt powyżej nadal miałby zastosowanie: który z trzech typów zmiennoprzecinkowych byłby zastosowany do wyniku? A ponieważ łatwo jest uzyskać podział zmiennoprzecinkowy, jeśli go potrzebujesz (użyj stałej zmiennoprzecinkowej dla jednego lub obu operandów lub rzutuj jeden lub oba operandy na typ zmiennoprzecinkowy), najwyraźniej nie było uważałem to za ważne.
W wersji podręcznika C z 1974 r. (Czyli 4 lata przed publikacją pierwszego wydania K&R) Ritchie nawet nie wspomina o możliwym zamieszaniu:
co mówi, że jeśli oba operandy są typu
int
lubchar
, wynikiem jest typint
.Tak, jest to źródłem zamieszania dla niektórych programistów C, szczególnie początkujących - ale C nie jest znane z tego, że jest bardzo przyjazne początkującym.
źródło
1.666666...
, co jest oczywiście błędne. Moja kiepska wymówka jest taka, że napisałem wydrukowany program testowy Pascala1.6666666666666667E-0001
W rzeczywistości to zachowanie zostało zmienione w Pythonie 3 i teraz działa tak, jak się spodziewasz (
//
jest teraz używane do dzielenia liczb całkowitych).źródło
/
zawsze tworzy wartość zmiennoprzecinkową, adiv
do dzielenia liczb całkowitych używany jest oddzielny operator ( ).Z popularnych języków JavaScript. 1,0 / 6,0 = 1/6 = 0,166666666666666666.
Nie uważam tego za zaskakujące. Zasadniczo, jeśli język rozróżnia typy liczb całkowitych i zmiennoprzecinkowych, podzielenie dwóch liczb całkowitych da skróconą liczbę całkowitą zamiast liczby zmiennoprzecinkowej. Jeśli nie, najprawdopodobniej domyślnie będą to operacje zmiennoprzecinkowe. Takie powinno być oczekiwane zachowanie programisty.
Pamiętaj tylko, że mogą tu być dodatkowe rzeczy, takie jak wspomniany już osobny operator podziału liczb całkowitych lub rzutowanie typu niejawnego.
źródło
Istnieje wiele języków, w których
((1/6)*6)
wyniki to 1, a nie 0. Na przykład PL / SQL, wiele dialektów BASIC, Lua.Przypadkowo we wszystkich tych wersjach językowych 1/6 daje 0,166666667 lub 0,166666666666667 lub coś podobnego. Wybrałem wariant ((1/6) * 6) == 1, aby pozbyć się tych małych różnic.
źródło
((1/6)*6)==1
wariant, aby pozbyć się tych drobnych różnic, ale wygląda na to, że przeceniłem umiejętności matematyczne niektórych osób.Haskell traktuje 1/6 i 1.0 / 6.0 jako identyczne 0,16666666666666666. Renderuje również 1 / 6.0 i 1.0 / 6 jako te same wartości.
Wynika to z faktu, że podstawowe typy liczbowe w języku Haskell nie są identyczne z innymi językami. Prawdziwy podział liczb całkowitych jest nieco ... skomplikowany.
źródło
Tak, Perl wie. Jednowarstwowy
daje w wyniku:
Wierzę, że PHP działa w ten sam sposób.
Zredagowano, by dodać: Uważam również, że warunkiem koniecznym (ale niewystarczającym)
1/6 == 1.0/6.0
jest słabe pisanie danego języka.źródło
/
jest przeciążony automatycznie w zależności od rodzaju argumentów, ale to wydaje się być naruszeniem zasady najmniejszych zdziwieniem do ja ...W Squeak Smalltalk
/
na liczbach całkowitych tworzy obiekty Fraction. Więc chociaż nie jest to to samo co dzielenie zmiennoprzecinkowe, nadal(1/6)*6
zwraca 1.źródło
Tak, właśnie sprawdziłem TI-99 / 4A wbudowany w TI BASIC . Ponieważ traktuje wszystkie wyrażenia liczbowe jako zmiennoprzecinkowe, operacja dzielenia również jest zmiennoprzecinkowa.
źródło
VB ( VB.Net , VB6 , VBA ...)
Operatorem podziału liczb całkowitych jest \
źródło
MATLAB. Literały liczbowe są domyślnie podwajane.
źródło
Clojure domyślnie używa ułamków. To nie to samo co 1.0 / 6.0, ale możesz przekonwertować na to za pomocą
float
lubdouble
kiedy potrzebujesz.źródło
Zaskakujące, wydaje się, że działa poprawnie w Windows PowerShell (wersja 3) .
Wydaje się również działać w Pythonie 3, jak wspomniano w sepp2k. Pozostałe dwa języki, które mam łatwo dostępne na REPL, Scala i Ruby, oba dzielą liczby całkowite i dają 0.
źródło
Język Rexx zawsze daje poprawną arytmetycznie odpowiedź. Na przykład: 5/2 = 2,5. Rexx to świetny język, który nie został wystarczająco wykorzystany. Teoretycznie, gdy kompilator nie może określić, czego chcesz, lepiej wykonać poprawną matematykę, jednak może to nie być wydajne. Rexx zapewnia również operator //.
źródło