Zahlensysteme: Binär, Hexadezimal, Dezimal & Bit-Operationen
Dieser Beitrag ist eine umfassende Einführung in die Zahlensysteme – inklusive Binär, Hexadezimal, Dezimal, Umrechnung und Bit-Operationen mit praktischen Beispielen.
In a Nutshell
Computer verwenden Binärsysteme (0 und 1). Hexadezimal dient als kompakte Darstellung für Binärwerte. Bit-Operationen ermöglichen direkte Manipulation von Daten auf Bitebene.
Lernpfad
Anfänger (Schritt 1-3):
- Grundlagen der Zahlensysteme verstehen (Dezimal, Binär, Hexadezimal)
- Einfache Umrechnungen üben (Dezimal ↔ Binär ↔ Hex)
- Grundlegende Bit-Operationen lernen (AND, OR, XOR)
Fortgeschritten (Schritt 4-6): 4. Zweierkomplement und negative Zahlen verstehen 5. Praktische Anwendungen (IP-Adressen, Farben, MAC-Adressen) 6. Shift-Operationen und Bit-Manipulation
Experte (Schritt 7-10): 7. Erweiterte Themen (BCD, Gray-Code, CRC) 8. IEEE 754 Gleitkomma-Format 9. Endianness und Netzwerk-Byte-Order 10. Performance-Optimierung mit Bit-Operationen
💡 Pro-Tip: Beginne mit den interaktiven Übungen, um dein Verständnis zu testen!
Kompakte Fachbeschreibung
Zahlensysteme sind Methoden zur Darstellung von Zahlen mit unterschiedlichen Basen. Computer verwenden intern das Binärsystem (Basis 2), während Menschen das Dezimalsystem (Basis 10) bevorzugen.
Wichtige Zahlensysteme:
Dezimalsystem (Basis 10)
- Ziffern: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
- Stellenwerte: 10⁰, 10¹, 10², 10³, …
- Verwendung: Menschliche Kommunikation, Alltagsmathematik
- Beispiel: 123 = 1×10² + 2×10¹ + 3×10⁰
Visuelle Darstellung:
1 2 3
↓ ↓ ↓
10² 10¹ 10⁰
100 10 1
= 100 + 20 + 3 = 123
Binärsystem (Basis 2)
- Ziffern: 0, 1
- Stellenwerte: 2⁰, 2¹, 2², 2³, …
- Verwendung: Computerinterne Darstellung
- Beispiel: 1011 = 1×2³ + 0×2² + 1×2¹ + 1×2⁰ = 11
⚠️ Wichtig: Computer arbeiten intern nur mit 0 und 1. Alle Daten werden letztlich als Binärzahlen gespeichert!
Visuelle Darstellung:
1 0 1 1
↓ ↓ ↓ ↓
2³ 2² 2¹ 2⁰
8 4 2 1
= 8 + 0 + 2 + 1 = 11
Hexadezimalsystem (Basis 16)
- Ziffern: 0-9, A, B, C, D, E, F
- Stellenwerte: 16⁰, 16¹, 16², 16³, …
- Verwendung: Kompakte Binärdarstellung, Farben, Speicheradressen
- Beispiel: A3 = 10×16¹ + 3×16⁰ = 163
💡 Pro-Tip: 1 Hex-Ziffer = 4 Binärziffern. Hex ist perfekt für Binär-Darstellung, da es kompakter und lesbarer ist!
Visuelle Darstellung:
A 3
↓ ↓
16¹ 16⁰
16 1
= 160 + 3 = 163
Oktalsystem (Basis 8)
- Ziffern: 0, 1, 2, 3, 4, 5, 6, 7
- Stellenwerte: 8⁰, 8¹, 8², 8³, …
- Verwendung: Historisch in Unix-Systemen
- Beispiel: 75 = 7×8¹ + 5×8⁰ = 61
📜 Historisch: Oktal wurde in frühen Unix-Systemen häufig verwendet (z.B. Dateiberechtigungen mit
chmod 755). Heute ist Hexadezimal verbreiteter.
Visuelle Darstellung:
7 5
↓ ↓
8¹ 8⁰
8 1
= 56 + 5 = 61
Prüfungsrelevante Stichpunkte
- Dezimalsystem: Basis 10, Ziffern 0-9, Stellenwerte 10ⁿ
- Binärsystem: Basis 2, Ziffern 0-1, Computerdarstellung
- Hexadezimalsystem: Basis 16, Ziffern 0-9, A-F, kompakte Darstellung
- Umrechnung: Division/Multiplikation mit Basis, Stellenwertmethode
- Bit-Operationen: AND, OR, XOR, NOT, Shift-Operationen
- Zweierkomplement: Negative Zahlen im Binärsystem
- IHK-relevant: Grundlage für Computerarchitektur und Programmierung
Kernkomponenten
- Zahlensysteme: Dezimal, Binär, Hexadezimal, Oktal
- Umrechnung: Zwischen verschiedenen Basen
- Bit-Operationen: AND, OR, XOR, NOT, Shift
- Zweierkomplement: Negative Zahlen
- Computerarithmetik: Addition, Subtraktion, Multiplikation
- Datentypen: Bits, Bytes, Words
- Speicherdarstellung: Hexadezimale Adressen
- Fehlererkennung: Parität, Checksummen
Schritt-für-Schritt Umrechnungen
💡 Pro-Tip: Übe diese Umrechnungen regelmäßig, sie sind fundamental für das Verständnis von Computersystemen! Zudem kommen sie in fast allen IHK AP1 oder 2 Prüfungen vor.
Hier unser kostenloser online bzw. offline Rechner:
Zahlensystem-Umrechnung
Dezimal zu Binär (Division durch 2)
Beispiel: 13₁₀ → Binär
13 ÷ 2 = 6 Rest 1 ← niederwertigstes Bit
6 ÷ 2 = 3 Rest 0
3 ÷ 2 = 1 Rest 1
1 ÷ 2 = 0 Rest 1 ← höchstwertigstes Bit
Von unten nach oben lesen: 1101₂
Binär zu Dezimal (Stellenwertmethode)
Beispiel: 1101₂ → Dezimal
1 1 0 1
↓ ↓ ↓ ↓
2³ 2² 2¹ 2⁰
8 4 2 1
= 1×8 + 1×4 + 0×2 + 1×1
= 8 + 4 + 0 + 1
= 13₁₀
Dezimal zu Hexadezimal (Division durch 16)
Beispiel: 255₁₀ → Hex
255 ÷ 16 = 15 Rest 15 (F)
15 ÷ 16 = 0 Rest 15 (F)
Von unten nach oben lesen: FF₁₆
Hexadezimal zu Binär (4-Bit-Gruppen)
Beispiel: A3₁₆ → Binär
A (10) 3
↓ ↓
1010 0011
Zusammen: 10100011₂
Binär zu Hexadezimal (4-Bit-Gruppen)
Beispiel: 10100011₂ → Hex
1010 0011
↓ ↓
A 3
Zusammen: A3₁₆
Praxisbeispiele
1. Umrechnung zwischen Zahlensystemen
public class ZahlensystemUmrechnung {
// Dezimal zu Binär
public static String dezimalZuBinaer(int dezimal) {
if (dezimal == 0) return "0";
StringBuilder binaer = new StringBuilder();
while (dezimal > 0) {
binaer.append(dezimal % 2);
dezimal /= 2;
}
return binaer.reverse().toString();
}
// Binär zu Dezimal
public static int binaerZuDezimal(String binaer) {
int dezimal = 0;
int potenz = 0;
for (int i = binaer.length() - 1; i >= 0; i--) {
if (binaer.charAt(i) == '1') {
dezimal += Math.pow(2, potenz);
}
potenz++;
}
return dezimal;
}
// Dezimal zu Hexadezimal
public static String dezimalZuHex(int dezimal) {
if (dezimal == 0) return "0";
char[] hexZiffern = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
StringBuilder hex = new StringBuilder();
while (dezimal > 0) {
int rest = dezimal % 16;
hex.append(hexZiffern[rest]);
dezimal /= 16;
}
return hex.reverse().toString();
}
// Hexadezimal zu Dezimal
public static int hexZuDezimal(String hex) {
int dezimal = 0;
String hexZiffern = "0123456789ABCDEF";
for (int i = 0; i < hex.length(); i++) {
char ziffer = hex.charAt(i);
int wert = hexZiffern.indexOf(ziffer);
dezimal = dezimal * 16 + wert;
}
return dezimal;
}
// Binär zu Hexadezimal
public static String binaerZuHex(String binaer) {
// Binär in 4er-Gruppen aufteilen
while (binaer.length() % 4 != 0) {
binaer = "0" + binaer;
}
StringBuilder hex = new StringBuilder();
for (int i = 0; i < binaer.length(); i += 4) {
String nibble = binaer.substring(i, i + 4);
int wert = binaerZuDezimal(nibble);
hex.append(dezimalZuHex(wert));
}
return hex.toString();
}
// Hexadezimal zu Binär
public static String hexZuBinaer(String hex) {
String[] binaerMap = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
StringBuilder binaer = new StringBuilder();
for (int i = 0; i < hex.length(); i++) {
char ziffer = hex.charAt(i);
int wert = "0123456789ABCDEF".indexOf(ziffer);
binaer.append(binaerMap[wert]);
}
// Führende Nullen entfernen
while (binaer.length() > 1 && binaer.charAt(0) == '0') {
binaer.deleteCharAt(0);
}
return binaer.toString();
}
public static void main(String[] args) {
int zahl = 175;
System.out.println("Zahl: " + zahl);
System.out.println("Binär: " + dezimalZuBinaer(zahl));
System.out.println("Hex: " + dezimalZuHex(zahl));
String binaer = "10101111";
String hex = "AF";
System.out.println("\nBinär " + binaer + " = Dezimal " + binaerZuDezimal(binaer));
System.out.println("Hex " + hex + " = Dezimal " + hexZuDezimal(hex));
System.out.println("Binär " + binaer + " = Hex " + binaerZuHex(binaer));
System.out.println("Hex " + hex + " = Binär " + hexZuBinaer(hex));
}
}
2. Bit-Operationen in verschiedenen Sprachen
// Java Bit-Operationen
public class BitOperationen {
public static void main(String[] args) {
int a = 12; // 1100 in Binär
int b = 10; // 1010 in Binär
System.out.println("a = " + a + " (Binär: " + Integer.toBinaryString(a) + ")");
System.out.println("b = " + b + " (Binär: " + Integer.toBinaryString(b) + ")");
// Bitweises AND (&)
int and = a & b; // 1100 & 1010 = 1000 (8)
System.out.println("a & b = " + and + " (Binär: " + Integer.toBinaryString(and) + ")");
// Bitweises OR (|)
int or = a | b; // 1100 | 1010 = 1110 (14)
System.out.println("a | b = " + or + " (Binär: " + Integer.toBinaryString(or) + ")");
// Bitweises XOR (^)
int xor = a ^ b; // 1100 ^ 1010 = 0110 (6)
System.out.println("a ^ b = " + xor + " (Binär: " + Integer.toBinaryString(xor) + ")");
// Bitweises NOT (~)
int notA = ~a; // ~1100 = 0011 (mit Zweierkomplement)
System.out.println("~a = " + notA + " (Binär: " + Integer.toBinaryString(notA) + ")");
// Left Shift (<<)
int leftShift = a << 2; // 1100 << 2 = 110000 (48)
System.out.println("a << 2 = " + leftShift + " (Binär: " + Integer.toBinaryString(leftShift) + ")");
// Right Shift (>>)
int rightShift = a >> 1; // 1100 >> 1 = 0110 (6)
System.out.println("a >> 1 = " + rightShift + " (Binär: " + Integer.toBinaryString(rightShift) + ")");
// Unsigned Right Shift (>>>)
int unsignedRightShift = a >>> 1; // 1100 >>> 1 = 0110 (6)
System.out.println("a >>> 1 = " + unsignedRightShift + " (Binär: " + Integer.toBinaryString(unsignedRightShift) + ")");
// Praktische Anwendungen
praktischeAnwendungen();
}
private static void praktischeAnwendungen() {
System.out.println("\n=== Praktische Anwendungen ===");
// Bit prüfen (ist das 3. Bit gesetzt?)
int zahl = 12; // 1100
int bitPosition = 2;
boolean bitSet = (zahl & (1 << bitPosition)) != 0;
System.out.println("Bit " + bitPosition + " in " + zahl + " gesetzt: " + bitSet);
// Bit setzen
int mitBit = zahl | (1 << bitPosition);
System.out.println("Setze Bit " + bitPosition + ": " + mitBit);
// Bit löschen
int ohneBit = zahl & ~(1 << bitPosition);
System.out.println("Lösche Bit " + bitPosition + ": " + ohneBit);
// Bit umschalten (toggle)
int umgeschaltet = zahl ^ (1 << bitPosition);
System.out.println("Umschalte Bit " + bitPosition + ": " + umgeschaltet);
// Farbe aus RGB-Werten extrahieren
int farbe = 0xFF6B35; // Orange
int rot = (farbe >> 16) & 0xFF;
int gruen = (farbe >> 8) & 0xFF;
int blau = farbe & 0xFF;
System.out.println("\nFarbe: #" + Integer.toHexString(farbe).toUpperCase());
System.out.println("Rot: " + rot);
System.out.println("Grün: " + gruen);
System.out.println("Blau: " + blau);
}
}
3. Zweierkomplement für negative Zahlen
⚠️ Wichtig: Das Zweierkomplement ist der Standard für negative Zahlen in modernen Computern. Vermeide Einerkomplement und Vorzeichen-Betrag!
public class Zweierkomplement {
// Zweierkomplement berechnen
public static String zweierkomplement(int zahl, int bits) {
if (zahl >= 0) {
return String.format("%" + bits + "s", Integer.toBinaryString(zahl)).replace(' ', '0');
}
// Negative Zahl: 2^bits - |zahl|
int positiv = (int) (Math.pow(2, bits) + zahl);
return String.format("%" + bits + "s", Integer.toBinaryString(positiv)).replace(' ', '0');
}
// Aus Zweierkomplement Dezimalwert berechnen
public static int vonZweierkomplement(String binaer) {
int bits = binaer.length();
// Wenn höchstes Bit 0 ist, positive Zahl
if (binaer.charAt(0) == '0') {
return Integer.parseInt(binaer, 2);
}
// Negative Zahl: - (2^bits - wert)
int wert = Integer.parseInt(binaer, 2);
return wert - (int) Math.pow(2, bits);
}
public static void main(String[] args) {
int[] zahlen = {13, 5, 0, -1, -5, -13};
int bits = 8;
System.out.println("Zweierkomplement mit " + bits + " Bits:");
System.out.println("Zahl\tBinär\t\tDezimal");
System.out.println("----\t----\t\t-------");
for (int zahl : zahlen) {
String binaer = zweierkomplement(zahl, bits);
System.out.println(zahl + "\t" + binaer + "\t" + vonZweierkomplement(binaer));
}
// Bereichsanzeige
System.out.println("\nBereich bei " + bits + " Bits:");
System.out.println("Minimum: " + (-(int) Math.pow(2, bits-1)));
System.out.println("Maximum: " + ((int) Math.pow(2, bits-1) - 1));
// Überlauf demonstrieren
System.out.println("\nÜberlauf-Demonstration:");
int max = (int) Math.pow(2, bits-1) - 1;
int ueberlauf = max + 1;
System.out.println("Max: " + max + " -> " + zweierkomplement(max, bits));
System.out.println("Max+1: " + ueberlauf + " -> " + zweierkomplement(ueberlauf, bits));
System.out.println("Erwartet: " + (-(int) Math.pow(2, bits-1)) + " -> " + zweierkomplement(-(int) Math.pow(2, bits-1), bits));
}
}
4. Computerarithmetik
⚠️ Warnung: Binäre Arithmetik kann zu Überläufen führen. Prüfe immer die Bereichsgrenzen deiner Datentypen!
public class Computerarithmetik {
// Binäre Addition
public static String binaerAddition(String a, String b) {
int laenge = Math.max(a.length(), b.length());
// Mit führenden Nullen auffüllen
a = String.format("%" + laenge + "s", a).replace(' ', '0');
b = String.format("%" + laenge + "s", b).replace(' ', '0');
StringBuilder ergebnis = new StringBuilder();
int carry = 0;
// Von rechts nach links addieren
for (int i = laenge - 1; i >= 0; i--) {
int summe = carry + (a.charAt(i) - '0') + (b.charAt(i) - '0');
ergebnis.append(summe % 2);
carry = summe / 2;
}
// Carry am Ende hinzufügen
if (carry > 0) {
ergebnis.append(carry);
}
return ergebnis.reverse().toString();
}
// Binäre Subtraktion (Zweierkomplement-Methode)
public static String binaerSubtraktion(String a, String b) {
// b negieren (Zweierkomplement)
String negiert = zweierkomplementNegieren(b);
// a + (-b)
return binaerAddition(a, negiert);
}
private static String zweierkomplementNegieren(String binaer) {
// Bits invertieren
StringBuilder invertiert = new StringBuilder();
for (char bit : binaer.toCharArray()) {
invertiert.append(bit == '0' ? '1' : '0');
}
// 1 addieren
return binaerAddition(invertiert.toString(), "1");
}
// Binäre Multiplikation
public static String binaerMultiplikation(String a, String b) {
int aDez = Integer.parseInt(a, 2);
int bDez = Integer.parseInt(b, 2);
int produkt = aDez * bDez;
return Integer.toBinaryString(produkt);
}
// Feste-Punkt-Arithmetik
public static double festePunktAddition(double a, double b, int nachkommastellen) {
int faktor = (int) Math.pow(10, nachkommastellen);
int aInt = (int) Math.round(a * faktor);
int bInt = (int) Math.round(b * faktor);
int ergebnisInt = aInt + bInt;
return (double) ergebnisInt / faktor;
}
// Gleitkomma-Darstellung (vereinfacht)
public static void gleitkommaDarstellung(double zahl) {
if (zahl == 0) {
System.out.println("0 = 0.0 × 2^0");
return;
}
boolean negativ = zahl < 0;
zahl = Math.abs(zahl);
int exponent = 0;
// Normalisieren
while (zahl >= 2.0) {
zahl /= 2.0;
exponent++;
}
while (zahl < 1.0) {
zahl *= 2.0;
exponent--;
}
System.out.println((negativ ? "-" : "") + zahl + " × 2^" + exponent);
}
public static void main(String[] args) {
System.out.println("=== Binäre Arithmetik ===");
String a = "1011"; // 11
String b = "1101"; // 13
System.out.println("a = " + a + " (" + Integer.parseInt(a, 2) + ")");
System.out.println("b = " + b + " (" + Integer.parseInt(b, 2) + ")");
String summe = binaerAddition(a, b);
System.out.println("a + b = " + summe + " (" + Integer.parseInt(summe, 2) + ")");
String differenz = binaerSubtraktion(b, a);
System.out.println("b - a = " + differenz + " (" + Integer.parseInt(differenz, 2) + ")");
String produkt = binaerMultiplikation(a, b);
System.out.println("a × b = " + produkt + " (" + Integer.parseInt(produkt, 2) + ")");
System.out.println("\n=== Feste-Punkt-Arithmetik ===");
double x = 12.34;
double y = 5.67;
double summeFP = festePunktAddition(x, y, 2);
System.out.println(x + " + " + y + " = " + summeFP + " (2 Nachkommastellen)");
System.out.println("\n=== Gleitkomma-Darstellung ===");
double[] zahlen = {12.5, 0.75, -3.125, 256.0};
for (double zahl : zahlen) {
System.out.print(zahl + " = ");
gleitkommaDarstellung(zahl);
}
}
}
5. Python Bit-Operationen und Zahlensysteme
# Python Zahlensysteme und Bit-Operationen
def dezimal_zu_binaer(dezimal):
"""Dezimal zu Binär umrechnen"""
if dezimal == 0:
return "0"
binaer = ""
while dezimal > 0:
binaer = str(dezimal % 2) + binaer
dezimal //= 2
return binaer
def binaer_zu_dezimal(binaer):
"""Binär zu Dezimal umrechnen"""
return int(binaer, 2)
def dezimal_zu_hex(dezimal):
"""Dezimal zu Hexadezimal umrechnen"""
hex_ziffern = "0123456789ABCDEF"
if dezimal == 0:
return "0"
hex = ""
while dezimal > 0:
hex = hex_ziffern[dezimal % 16] + hex
dezimal //= 16
return hex
def hex_zu_dezimal(hex):
"""Hexadezimal zu Dezimal umrechnen"""
return int(hex, 16)
def bit_operationen_demo():
"""Bit-Operationen demonstrieren"""
a = 12 # 1100
b = 10 # 1010
print(f"a = {a} (Binär: {bin(a)})")
print(f"b = {b} (Binär: {bin(b)})")
# Bitweises AND
and_result = a & b
print(f"a & b = {and_result} (Binär: {bin(and_result)})")
# Bitweises OR
or_result = a | b
print(f"a | b = {or_result} (Binär: {bin(or_result)})")
# Bitweises XOR
xor_result = a ^ b
print(f"a ^ b = {xor_result} (Binär: {bin(xor_result)})")
# Bitweises NOT
not_a = ~a
print(f"~a = {not_a} (Binär: {bin(not_a & 0xFFFFFFFF)})")
# Left Shift
left_shift = a << 2
print(f"a << 2 = {left_shift} (Binär: {bin(left_shift)})")
# Right Shift
right_shift = a >> 1
print(f"a >> 1 = {right_shift} (Binär: {bin(right_shift)})")
def farbe_aus_rgb(rot, gruen, blau):
"""RGB-Farbe als 24-Bit-Wert zusammenfassen"""
return (rot << 16) | (gruen << 8) | blau
def rgb_aus_farbe(farbe):
"""RGB-Komponenten aus 24-Bit-Farbe extrahieren"""
rot = (farbe >> 16) & 0xFF
gruen = (farbe >> 8) & 0xFF
blau = farbe & 0xFF
return rot, gruen, blau
def bit_manipulation_demo():
"""Bit-Manipulation demonstrieren"""
zahl = 0b10101000 # 168
print(f"Ursprüngliche Zahl: {zahl} (Binär: {bin(zahl)})")
# Bit prüfen
bit_position = 3
bit_gesetzt = (zahl & (1 << bit_position)) != 0
print(f"Bit {bit_position} gesetzt: {bit_gesetzt}")
# Bit setzen
mit_bit = zahl | (1 << bit_position)
print(f"Setze Bit {bit_position}: {mit_bit} (Binär: {bin(mit_bit)})")
# Bit löschen
ohne_bit = zahl & ~(1 << bit_position)
print(f"Lösche Bit {bit_position}: {ohne_bit} (Binär: {bin(ohne_bit)})")
# Bit umschalten
umgeschaltet = zahl ^ (1 << bit_position)
print(f"Umschalte Bit {bit_position}: {umgeschaltet} (Binär: {bin(umgeschaltet)})")
def hauptprogramm():
"""Hauptprogramm mit allen Demonstrationen"""
print("=== Zahlensysteme Umrechnung ===")
zahl = 175
print(f"Dezimal {zahl}:")
print(f" Binär: {dezimal_zu_binaer(zahl)}")
print(f" Hex: {dezimal_zu_hex(zahl)}")
print("\n=== Bit-Operationen ===")
bit_operationen_demo()
print("\n=== Bit-Manipulation ===")
bit_manipulation_demo()
print("\n=== Farben als RGB ===")
orange = farbe_aus_rgb(255, 107, 53)
print(f"Orange: #{orange:06X}")
r, g, b = rgb_aus_farbe(orange)
print(f"RGB: ({r}, {g}, {b})")
print("\n=== Zweierkomplement (8-Bit) ===")
for i in range(-5, 6):
if i >= 0:
binaer = format(i, '08b')
else:
binaer = format((256 + i), '08b')
print(f"{i:3d}: {binaer}")
if __name__ == "__main__":
hauptprogramm()
Reale Anwendungsbeispiele
1. IP-Adressen (IPv4)
IPv4-Adressen bestehen aus 4 Bytes (32 Bits), typischerweise in Dezimal-Schreibweise:
Beispiel: 192.168.1.1
192 168 1 1
↓ ↓ ↓ ↓
11000000 10101000 00000001 00000001
C0 A8 01 01 (Hex)
Binär: 11000000101010000000000100000001
Hex: C0A80101
Subnet Mask Beispiel: 255.255.255.0
255 255 255 0
↓ ↓ ↓ ↓
11111111 11111111 11111111 00000000
FF FF FF 00 (Hex)
2. MAC-Adressen
MAC-Adressen sind 6 Bytes (48 Bits), typischerweise in Hex-Schreibweise:
Beispiel: 00:1A:2B:3C:4D:5E
00:1A:2B:3C:4D:5E
↓ ↓ ↓ ↓ ↓ ↓
00000000:00011010:00101011:00111100:01001101:01011110
Hersteller (OUI): 00:1A:2B
Geräte-ID: 3C:4D:5E
3. Unicode und UTF-8
Unicode-Zeichen werden als Code Points dargestellt, UTF-8 kodiert diese in Bytes:
Beispiel: ‘A’ (U+0041)
Unicode: U+0041
Dezimal: 65
Binär: 01000001
UTF-8: 01000001 (1 Byte)
Beispiel: ’€’ (U+20AC)
Unicode: U+20AC
Dezimal: 8364
Binär: 00100000 10101100
UTF-8: 11100010 10000011 10101100 (3 Bytes)
Hex: E2 82 AC
4. Farbcodes (RGB)
Web-Farben werden als 24-Bit-Hex-Werte dargestellt:
Beispiel: #FF6B35 (Orange)
#FF6B35
↓↓↓↓↓↓
Rot Grün Blau
FF 6B 35
↓ ↓ ↓
255 107 53
Binär: 11111111 01101011 00110101
Java-Beispiel:
int orange = 0xFF6B35;
int rot = (orange >> 16) & 0xFF; // 255
int gruen = (orange >> 8) & 0xFF; // 107
int blau = orange & 0xFF; // 53
5. Dateigrößen (Binär vs. Dezimal)
Binäre Präfixe (IEC 80000-13):
1 KiB = 2¹⁰ = 1,024 Bytes
1 MiB = 2²⁰ = 1,048,576 Bytes
1 GiB = 3⁰ = 1,073,741,824 Bytes
Dezimale Präfixe (SI):
1 KB = 10³ = 1,000 Bytes
1 MB = 10⁶ = 1,000,000 Bytes
1 GB = 10⁹ = 1,000,000,000 Bytes
Beispiel: 1 GB Festplatte
Hersteller (dezimal): 1,000,000,000 Bytes
Betriebssystem (binär): 1,000,000,000 ÷ 1,073,741,824 = 0.93 GB
6. ASCII-Tabelle (Ausschnitt)
| Zeichen | Dezimal | Hex | Binär |
|---|---|---|---|
| A | 65 | 41 | 01000001 |
| B | 66 | 42 | 01000010 |
| C | 67 | 43 | 01000011 |
| a | 97 | 61 | 01100001 |
| b | 98 | 62 | 01100010 |
| c | 99 | 63 | 01100011 |
| 0 | 48 | 30 | 00110000 |
| 9 | 57 | 39 | 00111001 |
Interaktive Übungen
Umrechnungsaufgaben
Aufgabe 1: Dezimal zu Binär Wandeln Sie folgende Dezimalzahlen in Binär um:
- 42
- 127
- 255
Lösungen anzeigen
42₁₀ = 101010₂
127₁₀ = 1111111₂
255₁₀ = 11111111₂Aufgabe 2: Binär zu Dezimal Wandeln Sie folgende Binärzahlen in Dezimal um:
- 10101
- 11110000
- 10000000
Lösungen anzeigen
10101₂ = 21₁₀
11110000₂ = 240₁₀
10000000₂ = 128₁₀Aufgabe 3: Dezimal zu Hexadezimal Wandeln Sie folgende Dezimalzahlen in Hexadezimal um:
- 100
- 255
- 4095
Lösungen anzeigen
100₁₀ = 64₁₆
255₁₀ = FF₁₆
4095₁₀ = FFF₁₆Aufgabe 4: Hexadezimal zu Binär Wandeln Sie folgende Hexadezimalzahlen in Binär um:
- A5
- FF
- 1B
Lösungen anzeigen
A5₁₆ = 10100101₂
FF₁₆ = 11111111₂
1B₁₆ = 00011011₂Bit-Operationen Quiz
Frage 1: Was ist das Ergebnis von 12 & 10?
Lösung anzeigen
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 & 1010 = 1000₂ = 8₁₀Frage 2: Was ist das Ergebnis von 12 | 10?
Lösung anzeigen
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 | 1010 = 1110₂ = 14₁₀Frage 3: Was ist das Ergebnis von 12 ^ 10?
Lösung anzeigen
12₁₀ = 1100₂
10₁₀ = 1010₂
1100 ^ 1010 = 0110₂ = 6₁₀Frage 4: Was ist das Ergebnis von 8 << 2?
Lösung anzeigen
8₁₀ = 1000₂
1000 << 2 = 100000₂ = 32₁₀Frage 5: Was ist das Ergebnis von 16 >> 2?
Lösung anzeigen
16₁₀ = 10000₂
10000 >> 2 = 100₂ = 4₁₀Herausforderungsaufgaben
Aufgabe 6: Bit-Manipulation Gegeben ist die Zahl 42 (101010₂). Setzen Sie das 3. Bit (von rechts, 0-indexiert).
Lösung anzeigen
42 = 101010₂
3. Bit von rechts = Bit Position 2
42 | (1 << 2) = 42 | 4 = 46₁₀ = 101110₂Aufgabe 7: Zweierkomplement Stellen Sie -5 im 8-Bit-Zweierkomplement dar.
Lösung anzeigen
5₁₀ = 00000101₂
Invertieren: 11111010₂
+ 1: 11111011₂
-5₁₀ = 11111011₂ (8-Bit Zweierkomplement)Aufgabe 8: IP-Adresse Wandeln Sie die IP-Adresse 10.0.0.1 in Hexadezimal um.
Lösung anzeigen
10.0.0.1
↓ ↓ ↓ ↓
0A 00 00 01
Hex: 0A000001Häufige Fehler und Fallstricke
1. Off-by-one Fehler bei Bit-Positionen
Problem: Bit-Positionen werden oft falsch gezählt (0-indexiert vs. 1-indexiert)
// ❌ Falsch: Bit-Position 3 ist das 4. Bit von rechts
int bitPosition = 3;
boolean bitSet = (zahl & (1 << bitPosition)) != 0; // Prüft Bit 3 (4. Bit)
// ✅ Richtig: Klare Dokumentation der Indexierung
// Bit-Position 0 = rechtestes Bit (LSB)
// Bit-Position 7 = linkstes Bit bei 8-Bit
int bitPosition = 2; // 3. Bit von rechts (0-indexiert)
boolean bitSet = (zahl & (1 << bitPosition)) != 0;
2. Vorzeichen-Behandlung bei Shifts
Problem: Right-Shift verhält sich unterschiedlich bei signed/unsigned
// Java: Signed Right Shift (>>) füllt mit Vorzeichen-Bit
int x = -8; // 11111111111111111111111111111000
int result = x >> 2; // 11111111111111111111111111111110 (-2)
// Unsigned Right Shift (>>>) füllt mit 0
int x = -8;
int result = x >>> 2; // 00111111111111111111111111111110 (1073741822)
3. Überlauf-Probleme
Problem: Integer-Überlauf wird oft ignoriert
// ❌ Keine Überlauf-Prüfung
int max = Integer.MAX_VALUE; // 2147483647
int ueberlauf = max + 1; // -2147483648 (Überlauf!)
// ✅ Mit Überlauf-Prüfung
if (max == Integer.MAX_VALUE) {
throw new ArithmeticException("Integer overflow");
}
4. Hex-Konventionen missverstehen
Problem: Verschiedene Schreibweisen für Hex-Zahlen
// Verschiedene Konventionen:
0xFF // Java/C Präfix
0xFF // C# Präfix
0xFF // JavaScript Präfix
#FF // CSS/Web
FFh // Assembler
$FF // Pascal
5. Endianness vergessen
Problem: Byte-Reihenfolge wird ignoriert
// Little Endian (x86, ARM): niederwertigstes Byte zuerst
int wert = 0x12345678;
// Im Speicher: 78 56 34 12
// Big Endian (Network, PowerPC): höchstwertiges Byte zuerst
// Im Speicher: 12 34 56 78
// Konvertierung:
int littleEndian = 0x12345678;
int bigEndian = Integer.reverseBytes(littleEndian); // 0x78563412
6. Falsche Basis bei parseInt
Problem: Basis wird nicht korrekt angegeben
// ❌ Falsch: Dezimal statt Binär
int wert = Integer.parseInt("1010"); // 1010 (dezimal)
// ✅ Richtig: Basis angeben
int wert = Integer.parseInt("1010", 2); // 10 (dezimal)
int hexWert = Integer.parseInt("FF", 16); // 255 (dezimal)
7. Zweierkomplement-Bereich überschreiten
Problem: Zahl passt nicht in angegebene Bit-Breite
// 8-Bit Zweierkomplement: -128 bis 127
int wert = 200; // ❌ Überschreitet Bereich!
// Bereichsprüfung:
if (wert < -128 || wert > 127) {
throw new IllegalArgumentException("Wert außerhalb 8-Bit Bereich");
}
8. Float- vs. Integer-Division
Problem: Integer-Division schneidet Nachkommastellen ab
// ❌ Falsch: Integer-Division
int ergebnis = 5 / 2; // 2 (statt 2.5)
// ✅ Richtig: Float-Division
double ergebnis = 5.0 / 2.0; // 2.5
9. Negation vs. Komplement
Problem: Verwechslung von logischer Negation und Bit-Komplement
// Logisches NOT (!)
boolean a = true;
boolean b = !a; // false
// Bitweises NOT (~)
int x = 5; // 0101
int y = ~x; // 1010 (mit Zweierkomplement: -6)
10. Führende Nullen bei Hex
Problem: Führende Nullen ändern die Bedeutung bei某些 Kontexten
// In Java: 0x0F = 15, 0xF = 15 (gleich)
// Aber bei String-Vergleichen:
String a = "0F";
String b = "F";
// a.equals(b) = false!
Praktische Tipps für Entwickler
1. Debugging mit Binär/Hex-Ansicht
IDE-Tools nutzen:
// IntelliJ/Eclipse: Binär-Ansicht im Debugger
// Variable: 175
// Binär: 10101111
// Hex: AF
Logging mit verschiedenen Basen:
System.out.println("Dezimal: " + zahl);
System.out.println("Binär: " + Integer.toBinaryString(zahl));
System.out.println("Hex: " + Integer.toHexString(zahl));
System.out.println("Oktal: " + Integer.toOctalString(zahl));
2. Bit-Flags in APIs
Effiziente Status-Flags:
// Flag-Konstanten definieren
public static final int READ = 1 << 0; // 0001
public static final int WRITE = 1 << 1; // 0010
public static final int EXECUTE = 1 << 2; // 0100
// Flags kombinieren
int permissions = READ | WRITE; // 0011
// Flags prüfen
boolean canRead = (permissions & READ) != 0;
boolean canWrite = (permissions & WRITE) != 0;
boolean canExecute = (permissions & EXECUTE) != 0;
3. Performance-Vorteile von Bit-Operationen
Multiplikation/Division durch Shifts:
// Schneller als * 2
int x = 5;
int verdoppelt = x << 1; // 10
// Schneller als / 2
int halbiert = x >> 1; // 2
// Modulo 2^n mit AND
int modulo8 = x & 0x7; // x % 8
⚠️ Vorsicht: Moderne Compiler optimieren oft automatisch, nur bei kritischen Performance-Szenarien verwenden.
4. Farbwerte manipulieren
RGB-Farben effizient verarbeiten:
// Farbe erstellen
int farbe = (255 << 16) | (107 << 8) | 53; // #FF6B35
// Komponenten extrahieren
int rot = (farbe >> 16) & 0xFF;
int gruen = (farbe >> 8) & 0xFF;
int blau = farbe & 0xFF;
// Farbe manipulieren
int neueFarbe = farbe & 0x00FFFFFF; // Rot-Komponente löschen
neueFarbe |= (200 << 16); // Neuen Rot-Wert setzen
5. Netzwerk-Byte-Order
Portabilität sichern:
// Host to Network Short (16-bit)
short hostPort = 8080;
short networkPort = Short.reverseBytes(hostPort);
// Network to Host Long (32-bit)
int networkAddress = 0xC0A80101; // 192.168.1.1
int hostAddress = Integer.reverseBytes(networkAddress);
6. Bitmasken für Konfiguration
Konfiguration kompakt speichern:
public class Config {
private int flags = 0;
public static final int DEBUG = 1 << 0;
public static final int VERBOSE = 1 << 1;
public static final int LOGGING = 1 << 2;
public void setFlag(int flag) {
flags |= flag;
}
public void clearFlag(int flag) {
flags &= ~flag;
}
public boolean hasFlag(int flag) {
return (flags & flag) != 0;
}
}
7. Speicher-effiziente Datenstrukturen
Bits für boolesche Werte:
// Statt 8 booleans (8 Bytes):
// boolean[] flags = new boolean[8];
// Ein int (4 Bytes) für 8 Flags:
int flags = 0;
flags |= (1 << 3); // Setze 3. Flag
8. Hash-Funktionen mit Bit-Operationen
Einfache Hash-Funktion:
public static int simpleHash(String s) {
int hash = 0;
for (int i = 0; i < s.length(); i++) {
hash = (hash << 5) - hash + s.charAt(i);
}
return hash;
}
9. Paritäts-Berechnung
Paritäts-Bit für Fehlererkennung:
public static boolean calculateParity(int x) {
boolean parity = false;
while (x != 0) {
parity = !parity;
x = x & (x - 1); // Löscht niederwertigstes gesetztes Bit
}
return parity;
}
10. Power-of-2 Prüfung
Effiziente Prüfung auf Zweierpotenz:
public static boolean isPowerOfTwo(int x) {
return x > 0 && (x & (x - 1)) == 0;
}
// Beispiele:
// isPowerOfTwo(1) = true (2⁰)
// isPowerOfTwo(2) = true (2¹)
// isPowerOfTwo(4) = true (2²)
// isPowerOfTwo(8) = true (2³)
// isPowerOfTwo(6) = false
Erweiterte Themen
1. BCD (Binary Coded Decimal)
BCD kodiert jede Dezimalziffer in 4 Bits:
Beispiel: 42 in BCD
4 2
↓ ↓
0100 0010
BCD: 01000010
Vorteile:
- Einfache Konvertierung zu/from Dezimal
- Präzise Dezimalarithmetik
Nachteile:
- Ineffiziente Speichernutzung (6 von 16 Werten ungenutzt)
- Komplexere Arithmetik
Java-Implementierung:
public class BCD {
public static int decimalToBCD(int decimal) {
int bcd = 0;
int shift = 0;
while (decimal > 0) {
int digit = decimal % 10;
bcd |= (digit << shift);
decimal /= 10;
shift += 4;
}
return bcd;
}
public static int bcdToDecimal(int bcd) {
int decimal = 0;
int multiplier = 1;
while (bcd > 0) {
int digit = bcd & 0xF;
decimal += digit * multiplier;
bcd >>= 4;
multiplier *= 10;
}
return decimal;
}
}
2. Gray-Code
Gray-Code ist ein binäres Zahlensystem, bei dem sich aufeinanderfolgende Werte nur in einem Bit unterscheiden:
Gray-Code Tabelle (4 Bit):
Dezimal | Binär | Gray-Code
--------|-------|----------
0 | 0000 | 0000
1 | 0001 | 0001
2 | 0010 | 0011
3 | 0011 | 0010
4 | 0100 | 0110
5 | 0101 | 0111
6 | 0110 | 0101
7 | 0111 | 0100
Binär zu Gray-Code:
public static int binaryToGray(int binary) {
return binary ^ (binary >> 1);
}
Gray-Code zu Binär:
public static int grayToBinary(int gray) {
int binary = gray;
while (gray > 0) {
gray >>= 1;
binary ^= gray;
}
return binary;
}
Anwendung: Rotary-Encoder, Fehlerminimierung bei Schaltern
3. CRC (Cyclic Redundancy Check)
CRC ist ein Fehlererkennungsverfahren für Datenübertragung:
Einfache CRC-8 Implementierung:
public class CRC8 {
private static final int POLYNOMIAL = 0x07;
public static int calculate(byte[] data) {
int crc = 0x00;
for (byte b : data) {
crc ^= b;
for (int i = 0; i < 8; i++) {
if ((crc & 0x80) != 0) {
crc = (crc << 1) ^ POLYNOMIAL;
} else {
crc <<= 1;
}
}
}
return crc & 0xFF;
}
}
Verwendung:
- Netzwerkprotokolle (Ethernet, USB)
- Datei-Integritätsprüfung
- Speicher-Fehlererkennung
4. IEEE 754 Gleitkomma-Format
Standard für Fließkommazahlen:
32-Bit Single Precision:
Bit 31: Vorzeichen (S)
Bits 30-23: Exponent (E, 8 Bit)
Bits 22-0: Mantisse (M, 23 Bit)
Wert = (-1)^S × 2^(E-127) × (1 + M)
Beispiel: 12.5 in IEEE 754
12.5 = 1100.1₂ = 1.1001₂ × 2³
S = 0 (positiv)
E = 127 + 3 = 130 = 10000010₂
M = 10010000000000000000000
IEEE 754: 01000001010010000000000000000000
Hex: 41480000
Java-Implementierung:
public class IEEE754 {
public static String floatToBits(float value) {
int bits = Float.floatToIntBits(value);
return String.format("%32s", Integer.toBinaryString(bits))
.replace(' ', '0');
}
public static float bitsToFloat(String bits) {
int intValue = Integer.parseInt(bits, 2);
return Float.intBitsToFloat(intValue);
}
}
5. Endianness (Byte-Reihenfolge)
Big Endian: Höchstwertiges Byte zuerst (Network Byte Order) Little Endian: Niederwertigstes Byte zuerst (x86, ARM)
Beispiel: 0x12345678
Big Endian: 12 34 56 78
Little Endian: 78 56 34 12
Konvertierung in Java:
public class Endianness {
// Little Endian zu Big Endian
public static int littleToBig(int value) {
return Integer.reverseBytes(value);
}
// Big Endian zu Little Endian
public static int bigToLittle(int value) {
return Integer.reverseBytes(value);
}
// Prüfen der System-Endianness
public static boolean isLittleEndian() {
int test = 0x12345678;
byte[] bytes = new byte[] {
(byte) (test >> 24),
(byte) (test >> 16),
(byte) (test >> 8),
(byte) test
};
return bytes[0] == 0x78; // Little Endian
}
}
Wichtig bei:
- Netzwerkprotokollen (TCP/IP nutzt Big Endian)
- Dateiformaten
- Cross-Plattform-Entwicklung
6. Paritäts-Bit
Einfaches Fehlererkennungsverfahren:
Even Parity (gerade Parität):
Daten: 1011
Parität: 0 (damit Anzahl der 1s gerade ist: 10110 → 3 Einsen = ungerade ❌)
Parität: 1 (damit Anzahl der 1s gerade ist: 10111 → 4 Einsen = gerade ✅)
Java-Implementierung:
public class Parity {
public static boolean calculateEvenParity(byte data) {
int count = Integer.bitCount(data & 0xFF);
return (count % 2) == 0;
}
public static byte setEvenParity(byte data) {
if (calculateEvenParity(data)) {
return (byte) (data & 0x7F); // Paritäts-Bit = 0
} else {
return (byte) (data | 0x80); // Paritäts-Bit = 1
}
}
}
7. Checksummen
Einfache Prüfsummen für Datenintegrität:
Simple Checksum:
public class Checksum {
public static int calculate(byte[] data) {
int sum = 0;
for (byte b : data) {
sum += (b & 0xFF);
}
return sum & 0xFFFF; // 16-Bit Checksum
}
public static boolean verify(byte[] data, int checksum) {
return calculate(data) == checksum;
}
}
8. Base64-Kodierung
Binäre Daten in ASCII-Zeichen kodieren:
Beispiel:
Binär: 01000001 01000010 01000011 (ABC)
Base64: QUJD
Java-Implementierung:
import java.util.Base64;
public class Base64Example {
public static String encode(String input) {
return Base64.getEncoder().encodeToString(input.getBytes());
}
public static String decode(String encoded) {
byte[] decoded = Base64.getDecoder().decode(encoded);
return new String(decoded);
}
}
9. Bit-Rotation
Rotation ohne Verlust von Bits:
Left Rotation:
public static int rotateLeft(int value, int shift) {
return (value << shift) | (value >>> (32 - shift));
}
Right Rotation:
public static int rotateRight(int value, int shift) {
return (value >>> shift) | (value << (32 - shift));
}
Beispiel:
int x = 0b11000000; // 192
int rotated = rotateLeft(x, 2); // 0b00000011 (3)
10. Hamming-Distanz
Anzahl unterschiedlicher Bits zwischen zwei Werten:
public static int hammingDistance(int a, int b) {
int xor = a ^ b;
return Integer.bitCount(xor);
}
// Beispiel:
// hammingDistance(0b1010, 0b1100) = 2
// 1010 ^ 1100 = 0110 (2 Einsen)
Anwendung: Fehlerkorrektur-Codes, Kryptographie
Umrechnungstabelle
| Dezimal | Binär | Hexadezimal | Oktal |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 1 | 0001 | 1 | 1 |
| 2 | 0010 | 2 | 2 |
| 3 | 0011 | 3 | 3 |
| 4 | 0100 | 4 | 4 |
| 5 | 0101 | 5 | 5 |
| 6 | 0110 | 6 | 6 |
| 7 | 0111 | 7 | 7 |
| 8 | 1000 | 8 | 10 |
| 9 | 1001 | 9 | 11 |
| 10 | 1010 | A | 12 |
| 11 | 1011 | B | 13 |
| 12 | 1100 | C | 14 |
| 13 | 1101 | D | 15 |
| 14 | 1110 | E | 16 |
| 15 | 1111 | F | 17 |
Bit-Operationen Übersicht
Bit-Operationen
| Operator | Symbol | Beschreibung | Beispiel |
|----------|--------|-------------|----------|
| AND | & | Bitweises UND | 5 & 3 = 1 |
| OR | \| | Bitweises ODER | `5 \| 3 = 7` |
| XOR | ^ | Exklusives ODER | `5 ^ 3 = 6` |
| NOT | ~ | Bitweises NICHT | `~5 = -6` |
| Left Shift | << | Links verschieben | `5 << 2 = 20` |
| Right Shift | >> | Rechts verschieben | `5 >> 1 = 2` |
| Unsigned Right Shift | >>> | Vorzeichenloses Rechtsverschieben | `5 >>> 1 = 2` |
Speichergrößen
| Einheit | Bytes | Bits | Bereich (unsigned) |
|---|---|---|---|
| Byte | 1 | 8 | 0 - 255 |
| Word | 2 | 16 | 0 - 65,535 |
| DWord | 4 | 32 | 0 - 4,294,967,295 |
| QWord | 8 | 64 | 0 - 18,446,744,073,709,551,615 |
Zweierkomplement Bereich
| Bits | Minimum | Maximum |
|---|---|---|
| 8 | -128 | 127 |
| 16 | -32,768 | 32,767 |
| 32 | -2,147,483,648 | 2,147,483,647 |
| 64 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 |
Vorteile und Nachteile
Vorteile von Binärsystem
- Einfach: Nur zwei Zustände (0 und 1)
- Zuverlässig: Leicht fehlerfrei zu implementieren
- Effizient: Optimal für elektronische Schaltungen
- Universell: Grundlage aller digitaler Systeme
Vorteile von Hexadezimalsystem
- Kompakt: 4 Binärziffern = 1 Hexziffer
- Lesbar: Kürzer und übersichtlicher als Binär
- Standard: Weit verbreitet in der Programmierung
- Praktisch: Ideal für Adressen und Farben
Nachteile
- Abstraktion: Nicht intuitiv für Menschen
- Umrechnung: Erfordert mentale Arithmetik
- Fehleranfällig: Leicht bei manueller Umrechnung
Häufige Prüfungsfragen
1. **Wandeln Sie 175 (dezimal) in Binär und Hexadezimal um!**
175₁₀ = 10101111₂ = AF₁₆
2. **Was ist das Ergebnis von 12 & 10 (bitweises AND)?**
12₁₀ = 1100₂, 10₁₀ = 1010₂ → 1100 & 1010 = 1000₂ = 8₁₀
3. **Erklären Sie das Zweierkomplement!**
Methode zur Darstellung negativer Zahlen im Binärsystem durch Bit-Inversion und Addition von 1.
4. **Wofür werden Hexadezimalzahlen verwendet?**
Kompakte Darstellung von Binärwerten, Farben, Speicheradressen, Fehlercodes.
Wichtigste Quellen
- https://de.wikipedia.org/wiki/Zahlensystem
- https://de.wikipedia.org/wiki/Zweierkomplement
- https://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html



