[JAVA] Das Ende der katastrophalen Programmierung # 03 "Der Vergleich von ganzen Zahlen, wenn" a> b ", nimmt an, dass es" a - b> 0 "ist."

Ein gewöhnlicher Programmierer versteht es intuitiv und reflexiv. Ich möchte einen Artikel über eine rudimentäre und einfache Geschichte schreiben. Wegen der rudimentären Natur ein schwerer Programmierer wie ich Ich mache es gut (auch wenn ich dachte, ich hätte es verstanden).

Wenn es Fehler oder unangemessene Inhalte gibt, kommentieren Sie bitte Wir werden Korrekturen und Anpassungen des Inhalts berücksichtigen.

Diesmal, "Ende der katastrophalen Programmierung # 01" Mach es mit absoluten ganzen Zahlen "" Ich habe einen Artikel geschrieben, der auf dem Beitrag im Kommentarbereich von basiert. Danke für deinen Kommentar.

1. Vergleich der linken und rechten Seite

Programmieren ist manchmal Mathematik, manchmal nicht Mathematik.

In einigen Bereichen der Mathematik Wenn "a> b", dann wäre "a - b> 0" korrekt.

In der Programmierung Es gibt viele Fälle, in denen "a> b" gilt, "a - b> 0" jedoch nicht.

Ähnlich

Es gibt viele Fälle.

2. Dieses Mal sprechen wir über den Integer-Typ

** Dieses Mal werde ich es auf den Integer-Typ beschränken **. ** Wenn es sich um einen Gleitkommatyp handelt, müssen Sie in einer anderen Dimension vorsichtig sein ** Ich werde zu einem anderen Zeitpunkt einen Artikel schreiben.

Um die Geschichte einfacher zu machen Stellen Sie sich einen 32-Bit-Integer-Typ mit Vorzeichen vor. In Java, C # und C / C ++ wird es als int-Typ bezeichnet. (In C / C ++ wird ein Verarbeitungssystem mit einem int-Typ von 32 Bit angenommen. Für einige Leute können Sie sich int32 oder Int32 vorstellen. )

Der Bereich, den ein 32-Bit-Integer-Typ mit Vorzeichen darstellen kann, ist für viele Programmiersprachen: "-2147483648 bis 2147483647" Es sollte sein.

1.3. Lassen Sie es uns vorerst versuchen

Versuchen Sie, den folgenden Code für Java und C # auszuführen. Es werden nur die booleschen Werte (Wahr oder Falsch) von a> b und a --b> 0 angezeigt. Versuchen Sie, einige Werte in "a" und "b" zu setzen.

Vorerst werde ich es mit C # versuchen. Selbst wenn Sie dies in Java oder C / C ++ tun, unterscheidet sich der Bildschirmausgabeteil geringfügig.

//Geben Sie Werte für a und b ein und probieren Sie verschiedene Dinge aus.
int a = 100;
int b = 100;

//Für Java System.out.printf("a > b : %s%n", (a > b));Und.
Console.WriteLine("a > b : {0}",     (a > b));
Console.WriteLine("a - b > 0 : {0}", (a - b > 0));

Nach einigen Versuchen sieht es so aus.

Wert von a Wert von b a > b a - b > 0
100 100 False False
100 50 True True
-2000000000 500000000 False True
2000000000 -500000000 True False

In den ersten beiden stimmt die Wahrheit von "a> b" und "a - b> 0" überein, Die beiden unteren stimmen nicht überein.

3. Seien Sie auch in den vier Regeln immer vorsichtig

Sie sollten auch bei einfachen Operationen wie Addition, Subtraktion, Multiplikation und Division (+, -, \ *, /) immer vorsichtig sein.

Für ganzzahligen Typ Addition, Subtraktion, Multiplikation und Division (+, -, \ *, /) können ** überlaufen **. Darüber hinaus führt die Ganzzahldivision (/) zu einem Fehler (Ausnahme, Absturz usw.), wenn sie in vielen Sprachen und Umgebungen durch ** 0 geteilt wird **.

Divisionen, die ** negative ganze Zahlen enthalten, können auch schwierige Situationen ** verursachen.

Zum Beispiel

int a = 5;
int b = -2;
int answer = a / b;

Wenn Sie dies tun, gibt es Sprachen / Umgebungen, in denen "Antwort" zu "-2" wird, und Sprachen / Umgebungen, in denen "-3" zu "-3" wird. Wenn zum Beispiel die Division von ganzen Zahlen ** abgeschnitten ** ist, ist sie "-2". Wenn es als ** Bodenfunktion ** funktioniert, Da ein ganzzahliger Wert angenommen wird, der kleiner als das Berechnungsergebnis ist, wird er zu "-3".

In ähnlicher Weise können sich Restoperationen (%), die negative Ganzzahlen enthalten, je nach Sprache und Umgebung unterschiedlich verhalten.

Wenn Sie glauben, dass die Ganzzahldivision (/) nicht überläuft, Möglicherweise möchten Sie (Mindestwert vom Typ int) / (-1) versuchen. (Dieser Vorgang kann je nach Sprache und Umgebung besonders behandelt werden.)

Es ist ein wenig abseits des Themas, aber dieses Mal werden wir einen Überlauf in Betracht ziehen.

4. Manchmal vergesse ich versehentlich, durch Subtraktion überzulaufen

Wenn Sie nur von -2147483648 bis 2147483647 ausdrücken können Es ist leicht vorstellbar, dass Addition (+) und Multiplikation (*) einen Überlauf verursachen können. Natürlich besteht die Möglichkeit eines Überlaufs durch Subtraktion (-), aber Abhängig von der Situation können Sie es versehentlich vergessen.

Das Folgende ist ein Beispiel für einen Überlauf außerhalb des Bereichs, der ausgedrückt werden kann.

Berechnung Berechnungsergebnis von Hand berechnet Ergebnis der Berechnung in Java
2147483647 + 5 2147483652 -2147483644
2147483 * 10000 21474830000 -6480
2147483647 - (-5) 2147483652 -2147483644
-2147483648 - 5 -2147483653 2147483643

Die untere Operation liegt unter der unteren Grenze, die im negativen Bereich ausgedrückt werden kann. Dies ist auch ein Überlauf (Überlauf in negativer Richtung). Einige Leute nennen dies "Unterlauf", aber im Allgemeinen Wenn der Wert so nahe bei 0 liegt, dass er nicht mit Gleitkommagenauigkeit ausgedrückt werden kann, Es sollte richtig sein, es als Unterlauf zu bezeichnen. Streng genommen ist Unterlauf ein Missbrauch der obigen Situation für ganzzahlige Werte. (Normalerweise ist es ein Bereich, der im Verlauf der Geschichte verstanden werden kann, daher ist es schwierig, darauf hinzuweisen.)

5. Beenden

Beim Erstellen eines Programms, das komplizierte Berechnungen durchführt Ich denke, dass Überlauf oft ein bisschen mühsam ist.

In einem einfachen Fall Auf den ersten Blick besteht die Möglichkeit, dies in einem Fall zu tun, der nicht in direktem Zusammenhang mit dieser Geschichte zu stehen scheint.

Um ein konkretes Beispiel zu geben Wie "Comparator" und "Comparable Interface", Es scheint, dass es einige Fälle gibt, in denen der Mechanismus zum Ordnen der Instanzen von Objekten verwendet wird.

Zum Beispiel, wenn Sie die Instanzen in der Liste nach Wunsch des Programmierers sortieren möchten. Wenn Sie Instanzen A und B eines Objekts haben Dies ist derjenige, der verwendet wird, um zu bestimmen, welcher der erste in der Reihenfolge ist.

In dem Beispiel, in dem die Klasse verwendet wird, wird der Code lang, sodass wir das Beispiel für den Werttyp verwenden. Das Folgende ist ein Beispiel für C #, aber es sieht in Java ähnlich aus. In letzter Zeit hat die Anzahl der Sprachen, die Lambda-Ausdrücke verwenden können, zugenommen, daher werde ich in Lambda-Ausdrücken schreiben. (Ich kann es etwas klarer schreiben, aber ich schreibe es redundant mit Schwerpunkt auf Verständlichkeit.)

//Array von ganzzahligen Werten
var array = new int[] { 3, 1, -2147483647, -5 };

//In Liste speichern
var list = new List<int>(array);

//Bewerten und sortieren nach Lambda-Ausdruck
list.Sort(
  (a, b) =>
  {
    return (a - b);
  }
);

foreach (var item in list)
{
  Console.WriteLine(item);
}

Der Punkt ist der Lambda-Teil.

(a, b) =>
{
  return (a - b);
}

aber,

int compare(int a, int b)
{
  return (a - b);
}

Ich denke es ist leicht zu verstehen.

In vielen Frameworks, Vergleichsvergleichsmethode, Vergleichsfunktion,

Es soll implementiert werden, um zurückzukehren.

Mit dieser Spezifikation können Programmierer sehr gut verstehen, was sie mit einer einzelnen Operation tun möchten. Aufgrund der Spezifikationen der App ist "(a - b)" Wenn klar ist, dass es innerhalb des Bereichs liegt, in dem keine Möglichkeit eines Überlaufs besteht Es gibt kein Problem mit return (a --b);.

Wenn die Möglichkeit eines Überlaufs besteht, entspricht das Sortierergebnis möglicherweise nicht Ihren Erwartungen.

Das obige Codebeispiel soll die Zahlen in aufsteigender Reihenfolge sortieren. Das Ergebnis ist wie folgt.

1
3
-2147483647
-5

Es ist überhaupt nicht in aufsteigender Reihenfolge. ** Beachten Sie auch, dass die Ergebnisse abhängig von der ursprünglichen Reihenfolge im ursprünglichen Array "Array" variieren. ** **.

5. Gegenmaßnahmen

Grundsätzlich sollten Sie immer auf die Möglichkeit eines Überlaufs achten, wenn Sie vier Regeln ausführen.

Wenn Sie im Vergleichsbeispiel keine vier Regeln ausführen müssen Es gibt auch eine Methode zur Implementierung ohne vier Regeln. Bei der Programmierung kann eine naive und dumme Implementierung tatsächlich sicherer oder effizienter sein. Es ist in Ordnung.

In diesem Beispiel war array also ein Array vom Typ int Sie müssen die Sortierung nicht selbst definieren, Ich möchte, dass Sie es beim Sortieren von Objekten, die Sie selbst definiert haben, angemessen lesen.

list.Sort(
  (a, b) =>
  {
    int result = -1;

    if( a > b )
    {
        result = 1;
    }
    else if( a == b )
    {
        result = 0;
    }

    return result;  
  }
);

Oder wenn Sie einen ternären Operator verwenden

list.Sort(
  (a, b) =>
  {
    return (a > b) ? 1 : ((a == b) ? 0 : -1);
  }
);

Oder eine einfache Implementierung wird funktionieren.

Wenn das zu vergleichende Objekt eine vergleichbare Implementierung hat, Es wäre besser, dies auszunutzen.

Mit C #

list.Sort(
  (a, b) =>
  {
    return a.CompareTo(b);
  }
);

Es fühlt sich an wie.

Für Java Ich denke, Sie werden "Integer.compare (a, b)" und so weiter verwenden.

Recommended Posts

Das Ende der katastrophalen Programmierung # 03 "Der Vergleich von ganzen Zahlen, wenn" a> b ", nimmt an, dass es" a - b> 0 "ist."
Das Ende der katastrophalen Programmierung # 01 "Mach es mit dem absoluten Wert einer ganzen Zahl"
[Java] Es kann glücklich sein, wenn der Rückgabewert der Methode, die null zurückgibt, Optional <> ist
Anmerkung: [Java] Wenn sich eine Datei im überwachten Verzeichnis befindet, verarbeiten Sie sie.
Rufen Sie den Typ eines Elements eines Arrays ab, um festzustellen, ob es sich um ein Array handelt
Das zu RestTemplate hinzugefügte patchForObject kann nicht effektiv verwendet werden, wenn es sich um eine Standardimplementierung handelt (die HttpURLConnection verwendet).
Gibt es Ende 2017 einen Leistungsunterschied zwischen Oracle JDK und OpenJDK?
Erstellen Sie ein Paket, das ein allgemeiner Entwicklungsteil von Automation Anywhere A2019 # 1 ist. ~ Erstellen und verwenden Sie zunächst das SDK-Beispiel so wie es ist
[Quarkus] Eine Falle, die nicht funktioniert, selbst wenn Sie das GCP Pub / Sub-Beispiel so wie es ist kopieren und einfügen
Zum Zeitpunkt des dialogReturn-Ereignisses habe ich überprüft, ob es nicht aktualisiert wird, auch wenn ich eine Komponente mit Aktualisierung angegeben habe
Der Vergleich von enum ist == und gleich ist gut [Java]
Die Frage, welche besser ist, ob oder wechseln
Ein Memo des Programms, mit dem Sie feststellen können, dass die Wahrscheinlichkeit eines Würfelwurfs etwa 1/6 beträgt
Selbst wenn ich die Einstellung von STRICT_QUOTE_ESCAPING in CATALINA_OPTS in tomcat8.5 schreibe, wird sie nicht wiedergegeben.
[Docker] Ist es gut genug, um es als mehrstufigen Build zu bezeichnen? → Die Geschichte, die so gut wurde