Ch 2.3 Radix (Number Bases)
Computers are electronic devices capable of processing only 0s and 1s. However, in daily life we primarily use the decimal (base-10) system. To understand variables more deeply, it is important to know how computers store and read values.
1. Understanding Number Bases
A numeral system (radix) is a way of expressing numbers. The base differs depending on how many distinct digits are used.
| Base | Digits Used | Application | Example (representing 10) |
|---|---|---|---|
| Decimal (base-10) | 0~9 (10 digits) | Everyday life | 10 |
| Binary (base-2) | 0, 1 (2 digits) | Computer internals | 1010 |
| Octal (base-8) | 0~7 (8 digits) | File permissions, etc. | 12 |
| Hexadecimal (base-16) | 0 | Colors, memory addresses | A |
The decimal number 15 in each base:
Decimal: 15
Binary: 1111 (1×8 + 1×4 + 1×2 + 1×1)
Octal: 17 (1×8 + 7×1)
Hexadecimal: F (15×1)
Why Do Computers Use Binary?
The basic element of a computer, the transistor, has only two states: current flowing (1) or not flowing (0). All numbers and characters are expressed by combining these two states.
Current flowing: ━━━━┐ ┌━━━━┐ ┌━━━━
No current: └─────┘ └─────┘
[0] [1] [0] [1] [0] = 01010 = 10 (ten)
2. Using Different Bases in Java
Java uses special prefixes to distinguish different number bases.
| Base | Prefix | Example |
|---|---|---|
| Decimal | (none) | 10 |
| Binary | 0b or 0B | 0b1010 |
| Octal | 0 (the digit zero) | 012 |
| Hexadecimal | 0x or 0X | 0xA |
public class RadixLiteral {
public static void main(String[] args) {
int decNum = 10; // Decimal
int binNum = 0b1010; // Binary (0b prefix)
int octNum = 012; // Octal (0 prefix)
int hexNum = 0xA; // Hexadecimal (0x prefix)
// All store the same value (10)
System.out.println("Decimal: " + decNum); // 10
System.out.println("Binary: " + binNum); // 10
System.out.println("Octal: " + octNum); // 10
System.out.println("Hex: " + hexNum); // 10
System.out.println("All equal? " + (decNum == binNum && binNum == octNum && octNum == hexNum));
// true - Java processes all of them as decimal internally
}
}
Octal pitfall: 012 is NOT 12 — it is octal 12, which equals decimal 10! Be careful not to accidentally prepend a zero, as it will be interpreted as octal.
int wrong = 010; // Octal 10 = decimal 8 (!)
int right = 10; // Decimal 10
3. Bits and Bytes
bit: The smallest unit of computer storage. Either 0 or 1.
|
├── 4 bits = 1 nibble
|
└── 8 bits = 1 byte
|
├── 1,024 bytes = 1 KB (kilobyte)
|
├── 1,024 KB = 1 MB (megabyte)
|
├── 1,024 MB = 1 GB (gigabyte)
|
└── 1,024 GB = 1 TB (terabyte)
public class BitByteDemo {
public static void main(String[] args) {
// 1 byte = 8 bits -> -128 ~ 127 or 0 ~ 255
byte oneByte = 127;
System.out.println("1 byte max value: " + oneByte);
System.out.println("Binary representation: " + Integer.toBinaryString(oneByte)); // 1111111
// 2 hex digits = 1 byte
int hex1byte = 0xFF; // 11111111 = 255
System.out.println("0xFF = " + hex1byte); // 255
// File size unit conversion
long fileBytes = 5_368_709_120L; // 5 GB in bytes
long fileMB = fileBytes / (1024 * 1024);
long fileGB = fileBytes / (1024 * 1024 * 1024);
System.out.println("File size: " + fileMB + " MB = " + fileGB + " GB");
}
}
4. Using Radix Conversion Methods
Java's Integer class provides various methods for radix conversion.
public class RadixConversion {
public static void main(String[] args) {
int num = 255;
// Decimal -> other base string
System.out.println("Decimal: " + num);
System.out.println("Binary: " + Integer.toBinaryString(num)); // 11111111
System.out.println("Octal: " + Integer.toOctalString(num)); // 377
System.out.println("Hex: " + Integer.toHexString(num)); // ff
System.out.println("Hex (uppercase): " + Integer.toHexString(num).toUpperCase()); // FF
System.out.println("---");
// Other base string -> decimal
// parseInt(string, radix) format
System.out.println("Binary '11111111' = " + Integer.parseInt("11111111", 2)); // 255
System.out.println("Octal '377' = " + Integer.parseInt("377", 8)); // 255
System.out.println("Hex 'FF' = " + Integer.parseInt("FF", 16)); // 255
System.out.println("Hex 'ff' = " + Integer.parseInt("ff", 16)); // 255 (case-insensitive)
// Output in arbitrary base
System.out.println("255 in base 5: " + Integer.toString(255, 5)); // 2010
System.out.println("255 in base 7: " + Integer.toString(255, 7)); // 513
}
}
5. Two's Complement Representation of Negative Numbers
Computers represent negative numbers using the Two's Complement method.
Binary representation of positive 1 (8 bits):
00000001
How to get -1 (Two's Complement):
Step 1: One's complement (invert each bit) 11111110
Step 2: Add 1 11111111
Therefore -1 = 11111111 (8 bits)
Comparison:
1 = 00000001
-1 = 11111111
2 = 00000010
-2 = 11111110
public class TwosComplement {
public static void main(String[] args) {
// Comparing binary representations of positive and negative numbers
System.out.println("1 = " + Integer.toBinaryString(1));
System.out.println("-1 = " + Integer.toBinaryString(-1)); // 32 ones
System.out.println("127 = " + Integer.toBinaryString(127));
System.out.println("-128 = " + Integer.toBinaryString(-128));
// Sign bit (most significant bit)
// Starts with 0 -> positive, starts with 1 -> negative
int positive = 0b01111111; // 127 (positive, MSB=0)
int negative = 0b10000000; // 128... but -128 in signed byte
byte b1 = (byte) 0b01111111; // 127
byte b2 = (byte) 0b10000000; // -128 (sign bit is 1)
System.out.println("0b01111111 as byte: " + b1); // 127
System.out.println("0b10000000 as byte: " + b2); // -128
}
}
6. Big-Endian vs Little-Endian
When storing multi-byte data in memory, there are rules about the order in which bytes are arranged.
Storing integer 0x12345678 (4 bytes):
Big-Endian (most significant byte first):
Address: 0x100 0x101 0x102 0x103
Value: 0x12 0x34 0x56 0x78
Little-Endian (least significant byte first):
Address: 0x100 0x101 0x102 0x103
Value: 0x78 0x56 0x34 0x12
Java uses Big-Endian. Because the JVM always uses big-endian, it behaves the same regardless of which platform it runs on. In contrast, most Intel/AMD x86 CPUs use little-endian.
7. Practical Uses of Hexadecimal
Hexadecimal is a compressed, human-readable form of binary and is frequently used in practice.
Color Codes (HTML/CSS)
public class ColorCode {
public static void main(String[] args) {
// Web color codes use the hexadecimal RRGGBB format
// Example: #FF5733 = R:255, G:87, B:51
int color = 0xFF5733; // Store color as hexadecimal
int red = (color >> 16) & 0xFF; // Upper 8 bits
int green = (color >> 8) & 0xFF; // Middle 8 bits
int blue = color & 0xFF; // Lower 8 bits
System.out.printf("Color code: #%06X%n", color);
System.out.printf("R: %d (%02X)%n", red, red);
System.out.printf("G: %d (%02X)%n", green, green);
System.out.printf("B: %d (%02X)%n", blue, blue);
}
}
Output:
Color code: #FF5733
R: 255 (FF)
G: 87 (57)
B: 51 (33)
Memory Address Representation
public class MemoryAddress {
public static void main(String[] args) {
// Object hash code (similar to memory address)
Object obj = new Object();
int hashCode = System.identityHashCode(obj);
System.out.printf("Hash code (decimal): %d%n", hashCode);
System.out.printf("Hash code (hex): 0x%X%n", hashCode);
// Example: Hash code (decimal): 1829164700
// Hash code (hex): 0x6D06D69C
}
}
8. Practical Example: Converting RGB Colors to Hexadecimal
public class RGBConverter {
// Convert RGB values to hex color code
static String toHexColor(int r, int g, int b) {
// Validate each value is in 0~255 range
if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
throw new IllegalArgumentException("RGB values must be in the range 0~255.");
}
return String.format("#%02X%02X%02X", r, g, b);
}
// Parse hex color code into RGB
static int[] fromHexColor(String hexColor) {
// Remove '#' and parse
String hex = hexColor.startsWith("#") ? hexColor.substring(1) : hexColor;
int r = Integer.parseInt(hex.substring(0, 2), 16);
int g = Integer.parseInt(hex.substring(2, 4), 16);
int b = Integer.parseInt(hex.substring(4, 6), 16);
return new int[]{r, g, b};
}
public static void main(String[] args) {
// RGB -> Hex
System.out.println("White (255,255,255): " + toHexColor(255, 255, 255)); // #FFFFFF
System.out.println("Black (0,0,0): " + toHexColor(0, 0, 0)); // #000000
System.out.println("Red (255,0,0): " + toHexColor(255, 0, 0)); // #FF0000
System.out.println("Blue (0,0,255): " + toHexColor(0, 0, 255)); // #0000FF
System.out.println("Java Orange (237,119,50): " + toHexColor(237, 119, 50)); // #ED7732
// Hex -> RGB
int[] rgb = fromHexColor("#1E90FF"); // Dodger Blue
System.out.printf("Dodger Blue #1E90FF: R=%d, G=%d, B=%d%n", rgb[0], rgb[1], rgb[2]);
// Dodger Blue #1E90FF: R=30, G=144, B=255
// Same value in different bases
System.out.println("\n=== Same Value in Various Bases ===");
int value = 255;
System.out.printf("Decimal: %d%n", value);
System.out.printf("Binary: %s%n", Integer.toBinaryString(value));
System.out.printf("Octal: %s%n", Integer.toOctalString(value));
System.out.printf("Hex: %s%n", Integer.toHexString(value).toUpperCase());
}
}
Output:
White (255,255,255): #FFFFFF
Black (0,0,0): #000000
Red (255,0,0): #FF0000
Blue (0,0,255): #0000FF
Java Orange (237,119,50): #ED7732
Dodger Blue #1E90FF: R=30, G=144, B=255
=== Same Value in Various Bases ===
Decimal: 255
Binary: 11111111
Octal: 377
Hex: FF
9. Bitwise Operator Basics (Advanced)
public class BitwiseBasics {
public static void main(String[] args) {
int a = 0b1010; // Decimal 10
int b = 0b1100; // Decimal 12
System.out.println("a = " + Integer.toBinaryString(a) + " (" + a + ")");
System.out.println("b = " + Integer.toBinaryString(b) + " (" + b + ")");
// AND (&): 1 only when both bits are 1
System.out.println("a & b = " + Integer.toBinaryString(a & b) + " (" + (a & b) + ")"); // 1000 = 8
// OR (|): 1 when either bit is 1
System.out.println("a | b = " + Integer.toBinaryString(a | b) + " (" + (a | b) + ")"); // 1110 = 14
// XOR (^): 1 when bits differ
System.out.println("a ^ b = " + Integer.toBinaryString(a ^ b) + " (" + (a ^ b) + ")"); // 0110 = 6
// NOT (~): invert all bits
System.out.println("~a = " + (~a)); // -11
// Left shift (<<): multiply by 2
System.out.println("a << 1 = " + (a << 1)); // 20 (10 * 2)
// Right shift (>>): divide by 2
System.out.println("a >> 1 = " + (a >> 1)); // 5 (10 / 2)
}
}
Practical uses of bitwise operators:
n & 1: Check even/odd (0 = even, 1 = odd)n << 1: Multiply by 2 (faster than multiplication)n >> 1: Divide by 2a ^ b ^ b == a: Swap using XOR property
Summary
- Binary: computer internal representation (
0bprefix) - Octal: used for file permissions, etc. (
0prefix — be careful!) - Hexadecimal: colors, memory addresses, hash values (
0xprefix) - Radix conversion:
Integer.toBinaryString(),Integer.toHexString(),Integer.parseInt(str, radix) - Two's complement: computer's method for representing negative numbers
- Big-endian: byte storage order used by Java's JVM
- 1 byte = 8 bits= 2 hexadecimal digits