Java multipliziert das Betriebsverhalten

8

Ich habe eine Methode geschrieben, um eine gegebene Zahl von Tagen in Millisekunden umzuwandeln:

%Vor%

Ich hatte Schwierigkeiten, herauszufinden, was ich falsch gemacht habe. Jetzt meine Frage: Ist dieser Fehler so offensichtlich?

Die korrigierte Methode:

%Vor%

Wenn ich die Ganzzahl nicht vor der Berechnung in lang umwandele, bekomme ich ein völlig falsches Ergebnis.

    
Gilberto Olimpio 04.02.2009, 17:02
quelle

10 Antworten

8

Ist es offensichtlich? Ich schätze, es hängt davon ab, wie lange Sie Java benutzt haben und wie oft Sie mit Millisekunden zu tun hatten. Natürlich sollte es für bis zu 24 Tage in Ordnung sein ...

Ich denke, der größte Hinweis sollte sein, dass System.currentTimeMillis() eine long zurückgibt. Das ist ein guter Hinweis darauf, dass eine Anzahl von Millisekunden groß werden kann. Der Typ der Variablen, die du einstellst, sollte auch ein guter Hinweis sein.

Natürlich müssen Sie auch wissen, dass bei arithmetischen Operationen mit Ints das Ergebnis int mit Umbruch bei Überlauf ist. Ob das offensichtlich genug ist oder nicht, könnte diskutiert werden, aber es wäre eine ziemlich sinnlose Diskussion. In C #, wenn Sie die Überlaufprüfung eingeschaltet haben, hätten Sie den Fehler ziemlich schnell gefunden - aber dann tun nicht viele Entwickler das (tatsächlich tue ich das nicht, obwohl ich wahrscheinlich sollte).

    
Jon Skeet 04.02.2009, 17:14
quelle
7

Ja, es ist ziemlich offensichtlich, wenn Sie es vorher getan haben. Jedes Mal, wenn Sie eine Reihe von Zahlen multipliziert sehen, sollten Sie automatisch über Integer-Überlauffehler nachdenken. In diesem Fall sind Sie auf einen Überlauf gesetzt, wenn expireTimeInDays mehr als 24 ist. Technisch sollten Sie über Überlauffehler nachdenken, wann immer Sie mit Ganzzahlen arbeiten , aber eine Gruppe von ihnen so multiplizieren sollte eine sehr große rote Fahne sein.

    
Bill the Lizard 04.02.2009 17:14
quelle
3

Ihre Operandenvariable und die Literalzahlen sind vom Typ int. Der Datentyp int hat einen maximalen Wert von 2 ^ 31 -1. Daher führt der Datentyp von int-Überläufen bei solch großen Zahlen zu einer scheinbar falschen Antwort.

In Ihrem ersten Beispiel wird das int bei der Zuweisung zu der Variablen, die nach der Berechnung auftritt, nur auf eine lange Stufe hochgestuft. Das Ergebnis der Berechnung ist ein int.

Im zweiten Beispiel wird der erste Operand auf einen Long-Wert gesetzt, wodurch die Berechnung auf einen Long-Wert gesetzt wird. In diesem Fall ist das Ergebnis der Berechnung aufgrund der Beförderung lang. Der lange Datentyp ist mehr als groß genug für Ihre Berechnung.

    
Martin OConnor 04.02.2009 17:17
quelle
3

Es könnte Sie interessieren, dass dies in "Java Puzzlers" von Joshua Bloch und Neal Gafter behandelt wird.

alt text http://www.javapuzzlers.com/lg-puzzlers-cropped.jpg

In diesem Buch finden Sie viele weitere Java-Fallen, Fallen und Eckenfälle.

Ich stimme dem Sternenblau zu, der einen Kommentar hinterlassen hat. Füge ein L an die Nummer an.

    
Julien Chastang 04.02.2009 17:30
quelle
2

Nein, das ist nicht offensichtlich.

Aber vertrau mir, nach einigen Jahren Übung und der Behebung von Fehlern wie dieser, wirst du sehr vernünftig bei Integer-Überläufen und tust einfach das Richtige, ohne darüber nachzudenken.

Es ist etwas, das jedem passiert ist. Definitiv kein Zeichen für schlechte Code-Praxis, Ignoranz oder so.

    
Nils Pipenbrinck 04.02.2009 17:13
quelle
1

Um die anderen Antworten hinzuzufügen, habe ich es in der Vergangenheit als hilfreich empfunden, Konstanten ( public static final long ) wie MILLISECS_DAY oder MILLISECS_HOUR zu definieren. Viel besser lesbar und nützlich.

    
Avrom 04.02.2009 18:33
quelle
1

Eine andere Möglichkeit dies zu schreiben ist

%Vor%

oder

%Vor%     
Peter Lawrey 05.02.2009 02:39
quelle
1

Wenn Sie FindBugs in Ihrem Code verwenden, wird es genau dieses Problem erkennen. "ICAST: Ergebnis der Ganzzahlmultiplikation zu lang." FindBugs Beispiel ist genau das, was Sie tun; Tage in Millisekunden berechnen.

Dieses Problem war für mich nicht offensichtlich, als ich das erste Mal darauf stieß.

    
Sean McCauliff 05.02.2009 02:47
quelle
1

Es gibt einige statische Analysewerkzeuge (Findbugs), die diese Art von Fehlern finden.

Numerische Mathematik auf Computern kann schwierig sein. Betriebsbedingungsangelegenheiten können die Genauigkeit und Genauigkeit auf eine Weise beeinflussen, die Sie nicht erwarten. Datum Mathe kann auch überraschend schwierig sein. Oft ist es besser, die Date / Calendar-Routinen zu verwenden, anstatt zu versuchen, die Mathematik selbst zu berechnen, aber diese Routinen sind nicht die am besten entwickelten in der Java-Klassenbibliothek.

    
hacken 05.02.2009 03:05
quelle
0

Ich versuche nicht, meinen Fehler zu rechtfertigen, aber es wäre großartig, wenn der Java-Compiler schlau genug wäre, den Int auf lange vor der Berechnung zu befördern (sobald die Berechnung einer Variablen vom Typ long zugewiesen wurde) / p>

Übrigens, ich habe früher mit C / C ++ gearbeitet und wenn es ein C-Programm war, hatte ich das gleiche Problem, aber vor einigen Jahren war ich vorsichtiger mit dieser Art von Operation.

>

Ich werde nächstes Mal mehr Aufmerksamkeit schenken (oder zu python wechseln) ...: D

    
Gilberto Olimpio 04.02.2009 20:10
quelle

Tags und Links