Ich habe gesehen, wie Programmierer die Formel verwendet haben
mid = start + (end - start) / 2
anstatt die einfachere Formel zu verwenden
mid = (start + end) / 2
zum Finden des mittleren Elements im Array oder in der Liste.
Warum benutzen sie die erstere?
(start + end)
könnte überlaufen,(end - start)
kann aber nicht.start
undend
Zeiger sind.start + (end - start) / 2
trägt auch semantische Bedeutung:(end - start)
ist die Länge, so sagt dies :start + half the length
.Antworten:
Es gibt drei Gründe.
Funktioniert zunächst
start + (end - start) / 2
einmal auch, wenn Sie Zeiger verwenden, solangeend - start
nicht 1 überläuft .Zweitens
start + (end - start) / 2
wird nicht überlaufen, wennstart
undend
sind große positive Zahlen. Bei signierten Operanden ist der Überlauf undefiniert:(Beachten Sie, dass dies
end - start
überlaufen kann, aber nur, wennstart < 0
oderend < 0
.)Oder mit vorzeichenloser Arithmetik wird ein Überlauf definiert, der Ihnen jedoch die falsche Antwort gibt. Bei vorzeichenlosen Operanden
start + (end - start) / 2
wird jedoch niemals überlaufen, solangeend >= start
.Schließlich möchten Sie häufig auf das
start
Element runden .Fußnoten
1 Nach dem C-Standard ist
ptrdiff_t
das Verhalten undefiniert , wenn das Ergebnis der Zeigersubtraktion nicht als a dargestellt werden kann. In der Praxis erfordert dies jedoch die Zuweisung eineschar
Arrays unter Verwendung mindestens der Hälfte des gesamten Adressraums.quelle
(end - start)
in demsigned int
Fall ist undefiniert, wenn es überläuft.end-start
nicht überläuft? AFAIK Wenn Sie ein Negativ nehmenstart
, sollte es möglich sein, es überlaufen zu lassen. Sicher, die meisten Male, wenn Sie den Durchschnitt berechnen, wissen Sie, dass Werte sind>= 0
...end - start
definiert sind, da Objektgrößen nicht signiert sind, während Zeigerunterschiede signiert sind. Alsoend - start
"funktioniert sogar mit Zeigern", vorausgesetzt, Sie behalten auch irgendwie die Größe des Arrays unten beiPTRDIFF_MAX
. Um dem Standard gerecht zu werden, ist dies für die meisten Architekturen kein großes Hindernis, da dies halb so groß ist wie die Speicherkarte.Wir können ein einfaches Beispiel nehmen, um diese Tatsache zu demonstrieren. Angenommen, in einem bestimmten großen Array versuchen wir, den Mittelpunkt des Bereichs zu finden
[1000, INT_MAX]
. JetztINT_MAX
ist der größte Wert, den derint
Datentyp speichern kann. Selbst wenn dies1
hinzugefügt wird, wird der Endwert negativ.Auch
start = 1000
undend = INT_MAX
.Mit Hilfe der Formel:
(start + end)/2
,der Mittelpunkt wird sein
Aber mit der Formel erhalten
(start + (end-start)/2)
wir:quelle
INT_MAX
ist das Ergebnis nicht negativ, sondern undefiniert.INT_MAX
bis umlaufen-INT_MAX
. Es ist jedoch eine schlechte Angewohnheit, sich darauf zu verlassen.Um das zu ergänzen, was andere bereits gesagt haben, erklärt der erste seinen weniger mathematisch denkenden Menschen seine Bedeutung klarer:
liest als:
wohingegen:
liest als:
Was nicht so klar zu sein scheint wie das erste, zumindest wenn man es so ausdrückt.
wie Kos betonte, kann es auch lesen:
Was klarer ist, aber meiner Meinung nach immer noch nicht so klar wie das erste.
quelle
start + (end-start) / 2 kann einen möglichen Überlauf vermeiden, zum Beispiel start = 2 ^ 20 und end = 2 ^ 30
quelle