2015-10-14 11 views
21

Ich versuche, tiefer zu bekommen mit Post und Pre Inkrementoren ist aber ein bisschen mit dem folgenden Ausdruck fest:Inkrementierer Logik

public static void main(String[] args) { 
    int i = 0; 
    i = i+=(++i + (i+=2 + --i) - ++i); 
    // i = 0 + (++i + (i+=2 + --i) - ++i); 
    // i = 0 + (1 + (3 + 2) - 1); 
    // i = 0 + (6 - 1); 
    System.out.println(i); // Prints 0 instead of 5 
} 

Ich weiß, ich bin fehle die Logik irgendwo, aber wo?

Was ich versucht habe:

  • von links nach rechts gehen (obwohl ich weiß es ist nicht zu empfehlen)
  • vom insidest Klammer gehen und von dort aus starten.

Danke für die Hilfe

PS: Die Kommentare sind die Details meines Kalkül

EDIT 1

ich von 2 zu de hart codierten Wert aus dem Ausdruck zu ändern versucht, etwas anderes und das Ergebnis gibt immer 0

Schauen Sie sich dieses Beispiel an:

Dieser Ausdruck sollte logischerweise nicht in der Nähe von 0 sein, aber irgendwie wird es gedruckt.

Das gleiche passiert, wenn ich eine negative verwenden:

int i = 0; 
    i = i+=(++i + (i+=(-32650) + --i) - ++i); 
    System.out.println(i); // Prints 0 

EDIT 2

Nun änderte ich den Wert von i zu beginnen:

int i = 1; 
    i = i+=(++i + (i+=2 + --i) - ++i); 
    System.out.println(i); // Prints 2 

    i = 2; 
    i = i+=(++i + (i+=10000 + --i) - ++i); 
    System.out.println(i); // Prints 4 

    i = 3; 
    i = i+=(++i + (i+=(-32650) + --i) - ++i); 
    System.out.println(i); // Prints 6 

Es gibt das Doppel von i jedes Tim e, was auch immer der fest codierte Wert ist.

+0

könnten Sie eleborate, warum Sie denken, Es ist '5' statt '0' – SomeJavaGuy

+0

Die Kommentare im Code sind meine calculs –

+1

Ahh Artikel nicht fangen, die – SomeJavaGuy

Antwort

22

Java Language Specification, 15.7 Evaluation Order Zitiert:

Die Programmiersprache Java garantiert, dass die Operanden von Operatoren erscheinen in einer bestimmten Auswertung bewertet werden, nämlich von links nach rechts.

Die linken Operanden eines Binäroperators erscheintvollständig ausgewertet zu werden, bevor irgendein Teil des Operanden der rechten Hand ausgewertet wird.

Wenn der Bediener ein Verbindung-Zuweisungsoperator (§15.26.2), dann Auswertung des linken Operanden umfasst sowohl die variable daran erinnert, dass der linke Operand bezeichnet und fetching und Speicher, dass Variablenwert zur Verwendung in der implizierten binären Operation.

So im Wesentlichen i += ++i wird den alten Wert von i auf der linken Seite erinnern, vor die rechte Seite zu bewerten.

Denken Sie daran, Auswerteauftrag von Operanden und Vorrang von Operatoren sind zwei verschiedene Dinge.

Zeigen Auswerteauftrag, Schritt für Schritt, mit gespeicherten Wert in {Klammern}:

int i = 0; 
i = i += (++i + (i += 2 + --i) - ++i); // i = 0 
i{0} = i += (++i + (i += 2 + --i) - ++i); // i = 0 
i{0} = i{0} += (++i + (i += 2 + --i) - ++i); // i = 0 
i{0} = i{0} += (1 + (i += 2 + --i) - ++i); // i = 1 
i{0} = i{0} += (1 + (i{1} += 2 + --i) - ++i); // i = 1 
i{0} = i{0} += (1 + (i{1} += 2 + 0 ) - ++i); // i = 0 
i{0} = i{0} += (1 + (i{1} += 2  ) - ++i); // i = 0 
i{0} = i{0} += (1 + 3     - ++i); // i = 3 
i{0} = i{0} += (4      - ++i); // i = 3 
i{0} = i{0} += (4      - 4 ); // i = 4 
i{0} = i{0} += 0        ; // i = 4 
i{0} = 0          ; // i = 0 
0            ; // i = 0 

Followup zu Änderungen

Wenn wir den Anfangswert I und die Konstante N Namen in Frage zu stellen:

int i = I; 
i = i += (++i + (i += N + --i) - ++i); 

Dann können wir sehen, dass die Werte sind:

+0

Hallo Andreas! Dies scheint in der Tat eine akzeptable Antwort zu sein, aber würde es Ihnen etwas ausmachen (wenn es nicht zu viel verlangt wird), dieselbe Logik anzuwenden, wenn i = etwas anderes ist und auch wenn der fest codierte Wert größer als 2 ist? Das wäre großartig, ich habe versucht es zu tun, kam aber mit einer falschen Antwort. –

+2

@YassinHajaj Habe das einfach gemacht. :-) – Andreas

+0

Vielen Dank! Das ist großartig ! –

1

Ok, lassen Sie uns alles, was brechen:

int i = 0; // i = 0, no big deal 

beginnen Sie dann in der innersten Klammer:

(i+=2 + --i) 
  • es erste Abnahme i und verwenden das Ergebnis (-1)
  • dann addiere 2 (-1+2=1)
  • und das Ergebnis an i hinzuzufügen (die 0 zu Beginn der Operation ist) (0+1=1=i)

Am Ende wird das erste Dekrement von der reassignation ignoriert.

Nächste Klammer:

i+= (++i + previous_result - ++i) 
  • es die i (mit ++i) erhöhen an zwei Punkten
  • dann wird der Betrieb (i+1) + previous_result - (i+2) (beachten Sie, wie der Zuwachs nicht gleichzeitig sind), die gibt 2 + 1 - 3 = 0.
  • das Ergebnis der Operation wird in den Ausgang i (0)
  • hinzugefügt wird

Auch der Zuwachs durch die reassignation verwerfen lassen.

schließlich:

i = previous_result 

Welche gibt 0 :)

+0

Ich bearbeite die Frage, weil ich zu etwas wirklich komischem kam! –

5

Dies ist die Logik berücksichtigt Ihre erste bearbeiten Einnahme (mit einer unbekannten X):

public static void main(String[] args) { 
    int i = 0; 
    i = i+=(++i + (i+=X + --i) - ++i); 
    // i = 0 += (++i + ((i += (X + --i)) - ++i)); 
    // i = 0 += (1 + ((i += (X + --i)) - ++i)); // i = 1 
    // i = 0 += (1 + ((1 += (X + --i)) - ++i)); // i = 1 and i will then take the result of 1 += (X + --i) 
    // i = 0 += (1 + ((1 += (X + 0)) - ++i)); // i = 0 and i will then take the result of 1 += (X + 0) 
    // i = 0 += (1 + (X + 1 - ++i)); // i = X + 1 
    // i = 0 += (1 + (X + 1 - X - 2)); // i = X + 2 
    // i = 0 += (0); // i = X + 2 
    // i = 0; 
    System.out.println(i); // Prints 0 
} 

Tricks hier:

  • += ist ein assignement operator so ist es rechtsassoziativ: in den Schnipseln, I Klammer dies deutlicher
  • Das Ergebnis des Zuweisungsausdruck auszudrücken hinzugefügt ist der Wert der Variablen, nachdem die Zuordnung
  • Die postfix increment operator ++ und postfix decrement operator -- aufgetreten ist Addiere oder subtrahiere 1 von dem Wert und das Ergebnis wird zurück in die Variable gespeichert.
  • Der +additive operator berechnet zunächst den linken und dann den rechten Operanden.

Für Ihre zweite bearbeiten (mit einer unbekannten I hinzugefügt):

public static void main(String[] args) { 
    int i = I; 
    i = i+=(++i + (i+=X + --i) - ++i); 
    // i = I += (++i + ((i += (X + --i)) - ++i)); 
    // i = I += (I+1 + ((i += (X + --i)) - ++i)); // i = I+1 
    // i = I += (I+1 + ((I+1 += (X + --i)) - ++i)); // i = I+1 and i will then take the result of I+1 += (X + --i) 
    // i = I += (I+1 + ((I+1 += (X + I)) - ++i)); // i = I and i will then take the result of I+1 += (X + I) 
    // i = I += (I+1 + (X+2*I+1 - ++i)); // i = X + 2*I + 1 
    // i = I += (I+1 + (X+2*I+1 - X-2*I-2)); // i = X + 2*I + 2 
    // i = I += (I); // i = X + 2*I + 2 
    // i = 2 * I; 
    System.out.println(i); // Prints 2 * I 
} 
+0

nach dieser Logik, könnten Sie eleborieren, warum "i = i + = (++ i + (i + = 2)) == i = i + = (++ i + (i + = 2 + - i)); = 4' – SomeJavaGuy

+0

Ich bearbeite die Frage, weil ich zu etwas wirklich komischem kam! –

+0

Hey @Tunaki, könntest du den Schnitt, den ich gemacht habe, überprüfen. Diese Logik gilt nicht mehr –

0

geklam- mert nimmt den Vorrang. um von inneren meisten würde

(i+=2 + --i) =>i=i+=2==(2) --2 =0 
(++i - ++i) =>1-1=0 
i=i+ =0+0 =0 

Jeder Ausdruck ergibt 0

2

Ich schlage vor, die folgenden zu den äußersten: formatieren Sie den Code anders, so dass es nur 1 Anweisung pro Zeile, z.B.

@Test 
public void test() { 
    int i = 0; 
    i = 
    i+= 
    (
    ++i 
    + 
    (
    i+= 
    2 
    + 
    --i 
    ) 
    - 
    ++i 
    ); 
    System.out.println(i); // Prints 0 instead of 5 
} 

Dann führen Sie es unter dem Debugger und drücken Sie immer F5 ("Schritt in"). Dies wird Ihnen helfen, in der Auftragspositionen ausgewertet zu verstehen bekommen:

  1. int i=0;
  2. i=: ... (muss für Ergebnis der Berechnung A warten)
  3. i+= ...(B muss warten)
  4. ++i: i = 1
  5. i+= ... (C benötigt warten)
  6. 2+
  7. --i: i = 0
  8. ...: i = 3 (Ergebnis für Warte C)
  9. -
  10. ++i: i = 4 und Operanden - auch 4
  11. ...: i = 0 (für die Wartezeit B RESULT)
  12. ...: i = 0 (für Warte A zur Folge hat)

Linie 10 wird immer das Ergebnis der Linie 3 0 machen, so dass der Anfangswert von i wird niemals durch die ganze Operation verändert werden.

1

Wegen der höchsten Präzedenz (...) wird zuerst dann ausgewertet ++ & - und dann die restlichen Operatoren. Ihr Ausdruck ist wie

i = i += ((++i) + (i+=2 + (--i)) - (++i)); 

//i = i = i + ((++i) + (i+=2 + (--i)) - (++i)); 
//i = i = 0 + ((++i) + (i+=2 + (--i)) - (++i)); 
//i = i = 0 + ((1) + (i+=2 + (--i)) - (++i)); 
//i = i = 0 + ((1) + (i+=2 + (0)) - (++i)); 
//i = i = 0 + ((1) + (2 + (0)) - (++i)); 
//i = i = 0 + ((1) + (2) - (++i)); 
//i = i = 0 + ((1) + (2) - (3)); 
//i = i = 0 + (3 - 3); 
//i = i = 0 + (0); 
//i = 0 

Bitte vollständig Ihren Ausdruck klammern. Sie werden die Bewertungsreihenfolge des Ausdrucks verstehen.

Für Ihre EDIT 1

i = i+=((++i) + (i+=32500 + (--i)) - (++i)); 

// 0 + ((++i) + (i+=32500 + (--i)) - (++i)); // i = 0 
// 0 + ((1) + (i+=32500 + (--i)) - (++i)); // i = 1 
// 0 + ((1) + (i+=32500 + (0)) - (++i)); // i = 0 
// 0 + ((1) + (32500 + (0)) - (++i)); // i = 32500 
// 0 + ((1) + (32500) - (++i)); // i = 32500 
// 0 + ((1) + (32500) - (32501)); // i = 32501 
// 0 + (32501 - 32501); // i = 32501 
// 0 // i = 0 
1

ich den Wert von i verfolgt und hier sind die Ergebnisse:

i = i+=(++i + (i+=2 + --i) - ++i); 
initialization: i = 0; 
++i: i = 1;(1st one) and store this value 
(i+=2 + --i): In it 
--i: i = 0;(i was changed by the previous ++i) 
i += 2 + 0: i = 2;(value of the inner (i+=2 + --i), store it) 
++i: i = 3; 
1 + 2 -3: i = 0; 
i += 0: i = 0; 

Der Wert des zweiten i von links nicht gleich Null ist, ist es die Wert von i nachdem alle Operationen auf der rechten Seite beendet sind.