x /= n : Verstehe ich nicht.

nbergmann

Aktives Mitglied
int x = 25;
int n = 3;
x /= n;
Könnt ihr mir die 3. Zeile erklären?
Für das nächste Mal:
Wie finde ich die Antwort auf eine derartige Frage in Eclipse oder JShell?
 
Was sich bei so Fragen immer anbietet: Google.

Also in Googe z.B. nach "Java /=" suchen und schon bekommst du entsprechende Treffer.
 
x/= n ist das gleiche wie x = x /n
Ich bin hier der Pedant und muss sagen dass das so nicht ganz stimmt. Es ist equivalent zu x = (TYPE_X)(x / n). Es inkludiert einen impliziten Cast auf den Ziel-Typ. Das ist ein Detail das man immer im Blick haben sollte. Also:

Java:
int x = 5;

x = x / 5.235; // Compiler-Fehler, "double" passt nicht in "int".
x /= 5.235; // Leise Konvertierung nach "int", entspricht also "x = (int)(x / 5.235)"

Wie finde ich die Antwort auf eine derartige Frage in Eclipse oder JShell?
Gar nicht, aber die offizielle Java Dokumentation ist sehr gut. ... Ich merke gerade die sind gar nicht in der Doku...moment...hier sind sie mit aufgefuehrt, aber ohne weiterfuehrende Erklaerung, habe ich die Doku zu frueh gelobt.
 
Zuletzt bearbeitet:
Zu dem Thema ist mir gerade ein Gedanke gekommen ... Weiß jemand zufällig, ob "x /=n" in irgend einer Weise optimiert wird, wenn's also um das Laden von Werten, Stackadressen und ähnlichem geht? Oder kommt im Byte-Code genau das gleiche raus?
 
Oder kommt im Byte-Code genau das gleiche raus?
Für dieses Beispiel:
Java:
package bytecode;

public class Bytecode {

    public static void main(String[] args) {
        m1(8, 2);
        m2(8, 2);
    }

    static int m1(int a, int b) {
        a = a / b;
        return a;
    }
    
    static int m2(int a, int b) {
        a /= b;
        return a;
    }
    
}
wird in meiner Complilerversion für m1() und m2() der gleiche Bytecode erzeugt:
Code:
// Compiled from Bytecode.java (version 16 : 60.0, super bit)
public class bytecode.Bytecode {
 
  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Bytecode();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 3]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: bytecode.Bytecode
 
  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 2, Locals: 1
  public static void main(java.lang.String[] args);
     0  bipush 8
     2  iconst_2
     3  invokestatic bytecode.Bytecode.m1(int, int) : int [16]
     6  pop
     7  bipush 8
     9  iconst_2
    10  invokestatic bytecode.Bytecode.m2(int, int) : int [20]
    13  pop
    14  return
      Line numbers:
        [pc: 0, line: 6]
        [pc: 7, line: 7]
        [pc: 14, line: 8]
      Local variable table:
        [pc: 0, pc: 15] local: args index: 0 type: java.lang.String[]
 
  // Method descriptor #19 (II)I
  // Stack: 2, Locals: 2
  static int m1(int a, int b);
    0  iload_0 [a]
    1  iload_1 [b]
    2  idiv
    3  istore_0 [a]
    4  iload_0 [a]
    5  ireturn
      Line numbers:
        [pc: 0, line: 11]
        [pc: 4, line: 12]
      Local variable table:
        [pc: 0, pc: 6] local: a index: 0 type: int
        [pc: 0, pc: 6] local: b index: 1 type: int
 
  // Method descriptor #19 (II)I
  // Stack: 2, Locals: 2
  static int m2(int a, int b);
    0  iload_0 [a]
    1  iload_1 [b]
    2  idiv
    3  istore_0 [a]
    4  iload_0 [a]
    5  ireturn
      Line numbers:
        [pc: 0, line: 16]
        [pc: 4, line: 17]
      Local variable table:
        [pc: 0, pc: 6] local: a index: 0 type: int
        [pc: 0, pc: 6] local: b index: 1 type: int
}
 
static int m1(int a, int b) {
a = a / b;
return a;

a /= b;
return a;
da der einzige unterschied zwischen den Rechnungen der Cast ist wie oben schon beschrieben würd eder im byte code raus kommen normalerweise

ABER da die einzigen zwei werte für die berechnung sowieso den gleichen datentyp haben braucht man NIEMALS den cast, warum sollte ich von int nach int casten? => wird niemals passieren also wirds "wahrscheinlich" optimiert


der cast würde ja dann beim parameter aufruf schon passieren aber diese problematik ist ja beim methoden aufruf und nicht bei der rechnung
 
Pardon, wenn es irgendetwas Optimierungswürdiges gäbe, dann stünde es dort... Hier muss man genau sein.

Die Gleitzahldivision ist eindeutig spezifiziert und dass ein Cast in denselben Zieltyp entfallen kann, ist trivial. 🙂
 
Pardon, wenn es irgendetwas Optimierungswürdiges gäbe, dann stünde es dort... Hier muss man genau sein.

Die Gleitzahldivision ist eindeutig spezifiziert und dass ein Cast in denselben Zieltyp entfallen kann, ist trivial. 🙂
es steht da
int ergebnis = (int) (intzahl)/(intzahl)

der cast ist schlichtweg sinnlos => dewegen fällt er weg
 
Ich sprach von der JLS. Hier wurde erwähnt, dass der Operator gar nicht dokumentiert bzw. spezifiziert sei. Das stimmt so natürlich nicht. Tutorials sind auch etwas anderes als Dokumentationen.

Ich bin immer Fan davon, korrekte Begrifflichkeiten zu verwenden.
 
Na klar stehen keine Implementierungsdetails in der Spezifikation. Ich habe meine Aussage diesbezüglich ja auch schon konkretisiert: Optimierungsmöglichkeiten können aus der Spezifikation abgeleitet werden.
 
Optimierungsmöglichkeiten können aus der Spezifikation abgeleitet werden.
Du scheinst dich da ja auszukennen. Wie funktioniert das eigentlich in der Praxis? Man liest die JLS und entdeckt dort eine interessante Funktionalität F. Dann überlegt man sich, dass F ja z.B. mithilfe des inperformanten aber trivialen Algorithmus A_einfaeltig oder auch durch den ausgeklügelten schnellen Algorithmus A_ausgefuchst implementiert sein könnte. Daraus leitet man ab, dass bisher wahrscheinlich alle A_einfaeltig benutzt haben und sich deshalb die Investition in A_ausgefuchst bestimmt lohnen wird. Und so spart man sich die mühsamen Untersuchungen der Implementierungen, um Optimierungspotenzial zu finden, was ja angesichts deren Vielzahl ohnehin ein Wahnsinn wäre. Dass A_ausgefuchst bereits implementiert wurde kann man ja wegen ... na ja, aus irgendwelchen Gründen eben ... ausschließen. Läuft das so ab?
 
Der Kernpunkt ist doch einfach, dass die Optimierungen so nicht wirklich dokumentiert sind. Zumal es Optimierungen auf vielen Ebenen geben kann:
Java -> Bytecode - so lange die Regeln hier befolgt werden kann ein Compiler machen, was er will.
Bytecode -> Machine Code - so lange es dem JVMS entspricht darf hier eine Implementation frei walten.
'Utility' -> hier ist fast alles offen. Wie z.B. der GC vorgeht ist komplett der Implementation überlassen. Das geht dann bis hin zum 'ich 'abe gar kein Auto GC'
Oft kann man über ein Blick in die Referenzimplementation einige Einsichten gewinnen, aber wie eingeschränkt sich da Dinge ableiten lassen zeigen dann a) Veränderungen über die Zeit b) neue Implementationen (a.la. J9 von IBM/Eclipse Foundation)

Ein Verweis auf Dokumentation ist also extrem anzuzweifeln (Wobei es gute Blog Einträge gibt und so - aber da ist auch immer die Frage: auf was bezieht es sich und ist es noch aktuell bzw auf die Software anzuwenden, die ich gerade nutze?

Und am Ende noch (Last but Not least): es gibt ja auch Lösungen wie GraalVM wo die Struktur wieder etwas anders ist...
 

Neue Themen


Zurück
Oben