Während ich vor einigen Tagen in C ++ programmierte, habe ich diesen Fehler gemacht (dass ich in der Vergangenheit damit gearbeitet habe!). In einem Teil meines Codes hatte ich 1/6 und ich hatte erwartet, dass es 0,16666666666 ist, was nicht der Fall ist. Wie Sie alle wissen, ist das Ergebnis 0 - C, C ++, Java, Python, alle verhalten sich gleich.
Ich poste es auf meiner Facebook-Seite und jetzt wird diskutiert, ob es eine Programmiersprache gibt, 1/6
die sich genauso verhält wie 1.0/6.0
.
programming-languages
Pouya
quelle
quelle
>> 1 / 6
->== 0.166666666666667
1/6
ist tatsächlich 1/6 (gebrochener Typ), was,Double
erzwungen, 1,66666 ist ...Antworten:
Hat jeder Pascal vergessen?
1/6
Ausbeuten0.1666666...
(mit welcher Genauigkeit auch immer unterstützt wird).1 div 6
ergibt0
Es ist fraglich, ob die C-Regel ein Fehler ist. Fast alle arithmetischen Operatoren von C, bei denen die Operanden vom gleichen Typ sind, ergeben ein Ergebnis vom gleichen Typ. Es gibt etwas zu sagen für die Konsistenz.
Da C hauptsächlich auf Code auf Systemebene abzielt, verwenden die meisten C-Programme überhaupt kein Gleitkomma. Zu einer Zeit könnte das versehentliche Hinzufügen von Gleitkomma-Code zu einem Programm, das es sonst nicht benötigte, ein ernstes Problem sein. Dies ist wahrscheinlich immer noch der Fall für kleine eingebettete Systeme - die wiederum ein Hauptziel für C sind.
In den meisten C-Programmen ist das Abschneiden der Ganzzahldivision wahrscheinlich genau das, was Sie sowieso wollen.
Wenn
1 / 6
ein Gleitkomma-Ergebnis in C erhalten wird, dann:double
mag wie die natürliche Wahl erscheinen, aber Sie bevorzugen möglicherweise die zusätzliche Genauigkeit vonlong double
).C hätte getrennte Operatoren für die beiden Arten der Division bereitstellen können, aber der zweite Punkt oben würde immer noch gelten: Welcher der drei Gleitkommatypen würde für das Ergebnis verwendet? Und da es einfach genug ist, eine Gleitkommadivision zu erhalten, wenn Sie sie benötigen (verwenden Sie eine Gleitkommakonstante für einen oder beide Operanden oder wandeln Sie einen oder beide Operanden in einen Gleitkommatyp um), war dies anscheinend nicht der Fall. Ich hielt das nicht für wichtig.
In der 1974er Version des C-Handbuchs (das ist 4 Jahre vor der Veröffentlichung der ersten Ausgabe von K & R) erwähnt Ritchie nicht einmal die mögliche Verwirrung:
Das heißt, wenn beide Operanden vom Typ
int
oder sindchar
, ist das Ergebnis vom Typint
.Ja, es ist eine Quelle der Verwirrung für einige C-Programmierer, insbesondere für Anfänger - aber C ist nicht als sehr unerfahren bekannt.
quelle
1.666666...
, was eindeutig falsch ist. Meine lahme Entschuldigung ist, dass das Pascal-Testprogramm, das ich geschrieben habe, gedruckt wurde1.6666666666666667E-0001
Tatsächlich wurde dieses Verhalten in Python 3 geändert und verhält sich jetzt wie erwartet (
//
wird jetzt für die Ganzzahldivision verwendet).quelle
/
Erzeugt immer einen Gleitkommawert und ein separater Operator (div
) wird für die Ganzzahldivision verwendet.Aus bekannten Sprachen JavaScript. 1,0 / 6,0 = 1/6 = 0,16666666666666666.
Ich sehe das nicht als überraschend an. Als Faustregel gilt: Wenn eine Sprache zwischen numerischen Ganzzahl- und Gleitkommatypen unterscheidet, ergibt das Teilen von zwei Ganzzahlen eine abgeschnittene Ganzzahl anstelle von Gleitkommazahlen. Wenn dies nicht der Fall ist, werden höchstwahrscheinlich standardmäßig Gleitkommaoperationen verwendet. Dies sollte das erwartete Verhalten des Programmierers sein.
Denken Sie daran, dass hier noch weitere Dinge im Spiel sein könnten, wie der bereits erwähnte separate Ganzzahl-Divisionsoperator oder das implizite Typ-Casting.
quelle
Es gibt viele Sprachen, in denen
((1/6)*6)
1 und nicht 0 resultiert. Zum Beispiel PL / SQL, viele BASIC-Dialekte, Lua.In all diesen Sprachen ergibt 1/6 versehentlich .166666667 oder 0.16666666666667 oder ähnliches. Ich habe die Variante ((1/6) * 6) == 1 gewählt, um diese kleinen Unterschiede zu beseitigen.
quelle
((1/6)*6)==1
Variante gewählt, um diese kleinen Unterschiede zu beseitigen, aber es sieht so aus, als hätte ich die mathematischen Fähigkeiten einiger Leute überschätzt.Haskell behandelt 1/6 und 1,0 / 6,0 als identisch 0,16666666666666666. Außerdem werden 1 / 6.0 und 1.0 / 6 als der gleiche Wert dargestellt.
Dies liegt daran, dass die grundlegenden numerischen Typen in Haskell nicht ganz mit denen anderer Sprachen identisch sind. Wahre Ganzzahldivision ist etwas ... kompliziert.
quelle
Ja, Perl tut es. Der Einzeiler
ergibt die Ausgabe von:
Ich glaube, dass PHP genauso funktioniert.
Bearbeitet, um hinzuzufügen: Ich glaube auch, dass eine notwendige (aber nicht ausreichende) Bedingung dafür
1/6 == 1.0/6.0
ist, dass die betreffende Sprache schwach getippt ist.quelle
/
abhängig von den Arten der Argumente automatisch überladen wird, aber das scheint eine Verletzung des Prinzips des geringsten Erstaunens zu sein ich ...In Squeak Smalltalk
/
für Ganzzahlen werden Bruchobjekte erstellt. Dies ist zwar nicht dasselbe wie die Float-Division, gibt aber dennoch(1/6)*6
1 zurück.quelle
Ja, ich habe gerade die in TI BASIC eingebauten TI-99 / 4A überprüft . Da alle numerischen Ausdrücke als Gleitkomma behandelt werden, ist die Divisionsoperation auch Gleitkomma.
quelle
VB ( VB.Net , VB6 , VBA ...)
Der ganzzahlige Divisionsoperator ist \
quelle
MATLAB. Numerische Literale sind standardmäßig doppelt.
quelle
Clojure verwendet standardmäßig Brüche. Es ist nicht dasselbe wie 1.0 / 6.0, aber Sie können es mit
float
oderdouble
bei Bedarf konvertieren .quelle
Überraschenderweise scheint es in Windows PowerShell (Version 3) ordnungsgemäß zu funktionieren .
Scheint auch in Python 3 zu funktionieren, wie sepp2k erwähnt. Die beiden anderen Sprachen, die ich für REPL zur Verfügung habe, Scala und Ruby, machen beide eine ganzzahlige Division und ergeben 0.
quelle
Die Rexx-Sprache liefert immer eine arithmetisch korrekte Antwort. Zum Beispiel: 5/2 = 2,5. Rexx ist eine großartige Sprache, die nicht genug verwendet wurde. Wenn ein Compiler nicht bestimmen kann, was Sie wollen, ist es theoretisch besser, die richtige Mathematik durchzuführen. Dies ist jedoch möglicherweise nicht effizient. Rexx stellt auch den Operator // bereit.
quelle