Data Representation: Bits, Two's Complement, IEEE 754
কম্পিউটার আসলে কীভাবে ডেটা সংরক্ষণ করে
1. The Universe Is Just Bits
To a computer, everything — numbers, text, images, audio, video — is just a sequence of bits: ones and zeros. The same 8 bits can mean a number, a character, a color, or a tiny part of a JPEG — it depends entirely on how the program interprets them.
2. Binary, Decimal, Hex
| Decimal | Binary (8-bit) | Hex |
|---|---|---|
| 0 | 0000 0000 | 0x00 |
| 1 | 0000 0001 | 0x01 |
| 15 | 0000 1111 | 0x0F |
| 16 | 0001 0000 | 0x10 |
| 255 | 1111 1111 | 0xFF |
0xFF is far easier than 11111111.
3. Signed Numbers — Two's Complement
How do you store -5 in bits? The answer C++ (and almost every CPU) uses is two's complement: invert the bits of the positive number and add 1.
0000 0101 → invert = 1111 1010 → +1 = 1111 1011 = -5
Property: positive + (-positive) = 0 (with overflow). The arithmetic just works using ordinary binary addition.
8-bit signed range: -128 to +127. The leftmost bit acts as the sign bit (1 = negative).
4. Fixed-width Types — <cstdint>
int can be 16, 32, or 64 bits depending on the system — that's a portability problem.
For exact sizes, use <cstdint>:
#include <iostream>
#include <cstdint>
int main() {
std::cout << "int8_t = " << sizeof(int8_t) << " byte\n";
std::cout << "int16_t = " << sizeof(int16_t) << " bytes\n";
std::cout << "int32_t = " << sizeof(int32_t) << " bytes\n";
std::cout << "int64_t = " << sizeof(int64_t) << " bytes\n";
std::cout << "int = " << sizeof(int) << " bytes\n";
std::cout << "long = " << sizeof(long) << " bytes\n";
return 0;
}
5. Floating Point — IEEE 754
Real numbers (3.14, -0.001) use the IEEE 754 format. A 32-bit float has:
1 sign bit, 8 exponent bits, 23 mantissa bits.
64-bit double: 1 sign + 11 exponent + 52 mantissa.
0.1 + 0.2 != 0.3 in floating point! 0.1 has no exact binary representation. Always compare floats with a tolerance, never with ==.
#include <iostream>
#include <iomanip>
int main() {
double a = 0.1 + 0.2;
std::cout << std::setprecision(20) << a << "\n";
std::cout << (a == 0.3 ? "equal" : "NOT equal") << "\n";
}
6. Characters & ASCII
A char is one byte. The character 'A' is just the integer 65. 'a' is 97.
'0' is 48. ASCII assigns codes 0–127. UTF-8 extends beyond 127 for international text.
#include <iostream>
int main() {
for (char c = 'A'; c <= 'F'; ++c) {
std::cout << c << " = " << static_cast<int>(c) << "\n";
}
}
7. Practice Problems
- Convert 156 to 8-bit binary by hand.
✨ Show Answer
156 = 128 + 16 + 8 + 4 =
1001 1100. - What is the 8-bit two's complement representation of -1?
✨ Show Answer
+1 =
0000 0001. Invert =1111 1110. Add 1 =1111 1111. So -1 = all ones (0xFF). - Why does
int8_toverflow at +127, not +255?✨ Show Answer
It's a signed 8-bit type. One bit is used for sign, leaving 7 bits for magnitude → range -128 to +127.
uint8_tuses all 8 bits → 0 to 255. - Print the size in bytes of
char,short,int,long,long long,float,double.✨ Show Answer
sizes2.cpp#include <iostream> int main() { std::cout << sizeof(char) << " " << sizeof(short) << " " << sizeof(int) << " " << sizeof(long) << " " << sizeof(long long) << " " << sizeof(float) << " " << sizeof(double) << "\n"; } - Why is comparing floats with
==dangerous?✨ Show Answer
Most decimal fractions can't be represented exactly in binary.
0.1 + 0.2equals0.30000000000000004, not0.3. Always usestd::abs(a - b) < epsilon. - Print the ASCII code of the character '?'.
✨ Show Answer
ascii2.cpp#include <iostream> int main() { std::cout << static_cast<int>('?') << "\n"; // 63 } - What is endianness?
✨ Show Answer
The order in which bytes of a multi-byte integer are stored. Little-endian (Intel/AMD): least significant byte first. Big-endian (some networks, PowerPC): most significant byte first. Matters when reading binary files or network data.
- Convert
0xCAFEto decimal.✨ Show Answer
C×16³ + A×16² + F×16 + E = 12·4096 + 10·256 + 15·16 + 14 = 49152 + 2560 + 240 + 14 = 51966.
- Why does
int x = 2147483647 + 1;sometimes give -2147483648?✨ Show Answer
32-bit signed int max is 2,147,483,647 (
0x7FFFFFFF). Adding 1 wraps to0x80000000= -2,147,483,648 in two's complement. Signed overflow is undefined behavior in C++. - Write a loop that prints all powers of 2 up to 210.
✨ Show Answer
pow2.cpp#include <iostream> int main() { int p = 1; for (int i = 0; i <= 10; ++i) { std::cout << "2^" << i << " = " << p << "\n"; p *= 2; } } - Difference between
floatanddouble?✨ Show Answer
float= 32 bits, ~7 decimal digits precision.double= 64 bits, ~15 decimal digits. Usedoubleby default; only usefloatwhen memory is tight (huge arrays, GPU code). - Convert
'9' - '0'. What's the value and why?✨ Show Answer
'9' = ASCII 57, '0' = ASCII 48.
57 - 48 = 9. This is the standard idiom to convert a digit character to its numeric value.
Summary
Everything in memory is bits — meaning comes from interpretation. Use <cstdint> for fixed-width
integers in portable code. Two's complement makes signed arithmetic just work with the same hardware adder.
IEEE 754 floats are imprecise — never compare them with ==. ASCII codes for digits and
letters are contiguous, enabling clean idioms.