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.
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
a <b
gilt, aber a --b <0
gilt nichta <= b
gilt, aber a --b <= 0
gilt nichta> = b
gilt, aber a --b> = 0
gilt nichta == b
gilt, aber a --b == 0
gilt nichtEs gibt viele Fälle.
** 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.
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.
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.
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.)
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,
a
und b
gleich sind.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. ** **.
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