Number Systems, Divisibility & Speed Math Mastery
1. Foundational Mathematics
Before attempting to prove Euler's Totient Theorem or solve advanced modulo combinatorics, you must master the core mechanics of Prime Factorization.
Prime Factorization Algorithm
Every number can be uniquely broken down into prime building blocks. Finding these is critical for HCF, LCM, and Totient calculations.
def prime_factors(n):
factors = []
# Divide out 2s
while n % 2 == 0:
factors.append(2)
n //= 2
# Divide odd primes up to sqrt(n)
for i in range(3, int(n**0.5) + 1, 2):
while n % i == 0:
factors.append(i)
n //= i
if n > 2:
factors.append(n)
return factors
Calculating Euler's Totient
Euler's Totient function counts the number of integers up to that are coprime to . You cannot use Euler's Theorem without calculating this first. The formula relies entirely on the unique prime factors of : For example, for , the prime factors are and .
Modulo Periodicity (Cyclicity)
Why does the unit digit of powers cycle every 4 steps? Observe the patterns manually:
- Powers of 2: 2, 4, 8, 16 (ends in 6), 32 (ends in 2 - loops!)
- Powers of 3: 3, 9, 27 (ends in 7), 81 (ends in 1), 243 (ends in 3 - loops!)
1. Introduction: The First Principles of Numbers
To truly master number systems for competitive placements, we must discard superficial memorization and rebuild our understanding from the ground up. The foundation of modern computing and algorithmic aptitude lies in a rigorous mathematical and structural comprehension of how numbers operate in memory and mathematical theory.
1.1 First Principles of Base Representation
Any integer in base can be represented as a polynomial: where .
Memory Model in Computers
When we talk about numbers, we must understand their physical representation. Modern architectures represent integers using Two's Complement in a fixed number of bits (e.g., 32-bit or 64-bit registers).
classDiagram
class MemoryRegister {
+Bit 31: Sign Bit
+Bits 30-0: Magnitude
}
In Two's Complement:
- Positive numbers are stored as straight binary.
- Negative numbers are stored by inverting the bits of the absolute value and adding 1.
Execution trace for -5 (8-bit system):
- Represent
5:0000 0101 - Invert bits:
1111 1010 - Add 1:
1111 1011-> This is-5.
Edge Case: The most negative number (e.g., -128 in 8-bit) has no positive counterpart because 1000 0000 inverted is 0111 1111 (+127), and adding 1 gives 1000 0000 again. This causes overflow when negated.
1.2 Multi-Language BigInt Implementations
When numbers exceed register sizes, we use Arbitrary-Precision Arithmetic (BigInt). In Python, integers have infinite precision by default. Under the hood, Python represents integers as arrays of 30-bit digits.
// Simplified C representation of Python's BigInt
struct _longobject {
long ob_refcnt;
struct _typeobject *ob_type;
long ob_size; /* Number of items in ob_digit */
uint32_t ob_digit[1]; /* Array of 30-bit digits */
};
In C++, developers typically implement BigInt using std::vector<uint32_t>.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class BigInt {
private:
std::vector<int> digits;
public:
BigInt(std::string num) {
for (int i = num.size() - 1; i >= 0; i--) {
digits.push_back(num[i] - '0');
}
}
// Add two BigInts
BigInt add(const BigInt& other) const {
BigInt res("");
int carry = 0;
int n = std::max(digits.size(), other.digits.size());
for (int i = 0; i < n || carry; ++i) {
int sum = carry;
if (i < digits.size()) sum += digits[i];
if (i < other.digits.size()) sum += other.digits[i];
res.digits.push_back(sum % 10);
carry = sum / 10;
}
return res;
}
void print() const {
for (int i = digits.size() - 1; i >= 0; i--) {
std::cout << digits[i];
}
std::cout << std::endl;
}
};
2. Divisibility Rules Memory Matrix
To understand divisibility intuitively, let's explore the mathematical proofs instead of mere rules.
| Number | Divisibility Condition | Mathematical Proof / First Principles | Example & Trace |
| :--- | :--- | :--- | :--- |
| 2 | Last digit is even. | . The term is always divisible by 2. Thus, divisibility strictly depends on . | 4582 -> 2 is even. |
| 3 | Sum of all digits divisible by 3. | . Since 99 and 9 are divisible by 3, the sum must be. | 1431 -> 1+4+3+1=9. |
| 4 | Last two digits divisible by 4. | . is divisible by 4. Thus only matters. | 9524 -> 24 / 4 = 6. |
| 5 | Last digit is 0 or 5. | . Divides if . | 8975 -> 5. |
| 6 | Divisible by 2 AND 3. | Coprime factorization: . If , divisibility by implies divisibility by both and . | 2736 -> Even and sum 18. |
| 7 | Rule of 7 (Osculator). | Double the last digit and subtract from the rest. Repeat. If result is 0 or multiple of 7. | 343 -> 34 - 6 = 28. Div by 7. |
| 8 | Last three digits. | . 1000 is div by 8. So must be. | 15816 -> 816. |
| 9 | Sum of all digits. | Same logic as 3. . | 2871 -> 18. |
| 11 | Alternating sum. | . Thus , . Leads to alternating sum rule. | 1331 -> (1+3)-(3+1)=0. |
| 13 | Multiply last by 4, add. | Based on , leading to multiplier of . | 169 -> 16 + 9*4 = 52. |
2.1 Implementing Divisibility Checks Programmatically
How do we check if an extraordinarily large number (as a string) is divisible by 7, 11, or 13 in code?
def is_divisible_by_11(s: str) -> bool:
"""
Checks divisibility by 11 with O(N) time complexity and O(1) space.
Execution trace for '1331':
odd_sum = 1 + 3 = 4
even_sum = 3 + 1 = 4
abs(4 - 4) % 11 == 0
"""
odd_sum, even_sum = 0, 0
for i, char in enumerate(s):
if i % 2 == 0:
even_sum += int(char)
else:
odd_sum += int(char)
return abs(odd_sum - even_sum) % 11 == 0
3. Cyclicity & Unit Digit Calculation Algorithm
To find the unit digit of , we are essentially calculating . By Euler's Totient Theorem, if . However, 10 is not prime, and digits share factors with 10 (like 2 and 5). Still, every sequence of becomes periodic. The maximum period for modulo 10 is 4.
3.1 Formal Cyclicity Algorithm
- Reduce base: Let .
- Find the power: Let . If , set .
- Calculate: Output .
3.2 Complexity Analysis
- Time Complexity: assuming operations on base types. If is a string of length , then takes by just looking at the last two digits of .
- Space Complexity: since we strictly use bounded integers.
3.3 Code Implementation (Java)
public class UnitDigit {
public static int getUnitDigit(String a, String b) {
if (a.equals("0")) return 0;
if (b.equals("0")) return 1;
// Base's last digit
int baseDigit = a.charAt(a.length() - 1) - '0';
// Power's modulo 4
int expModulo = 0;
if (b.length() == 1) {
expModulo = Integer.parseInt(b) % 4;
} else {
expModulo = Integer.parseInt(b.substring(b.length() - 2)) % 4;
}
if (expModulo == 0) expModulo = 4;
return (int) Math.pow(baseDigit, expModulo) % 10;
}
}
4. Remainder Theorems
4.1 Fermat's Little Theorem
If is a prime number and is an integer not divisible by , then:
Proof Outline: Consider the set of integers . Multiply each by modulo to get . Because , all elements in are distinct and non-zero modulo . Hence, is a permutation of . Taking the product of elements in both sets: Since is coprime to , we can cancel it out, yielding .
4.2 Euler's Totient Theorem
A generalization of Fermat's theorem: where is Euler's totient function, the number of integers up to that are coprime to .
4.3 Wilson's Theorem
A positive integer is a prime if and only if:
5. Lowest Common Multiple (LCM) & Highest Common Factor (HCF)
5.1 Euclidean Algorithm for GCD
The greatest common divisor of and can be found efficiently using the Euclidean Algorithm, based on the principle that .
flowchart TD
A[Start: a, b] --> B{b == 0?}
B -- Yes --> C[Return a]
B -- No --> D[Calculate a % b]
D --> E[Set a = b, b = result]
E --> B
C++ Implementation:
long long gcd(long long a, long long b) {
while (b != 0) {
a %= b;
std::swap(a, b);
}
return a;
}
Time Complexity: (Proof: Worst case is consecutive Fibonacci numbers). Space Complexity: iterative, recursive due to call stack.
5.2 Extended Euclidean Algorithm
Finds coefficients and such that:
def extended_gcd(a, b):
if a == 0:
return b, 0, 1
gcd, x1, y1 = extended_gcd(b % a, a)
x = y1 - (b // a) * x1
y = x1
return gcd, x, y
This is critical for finding Modular Multiplicative Inverses, heavily used in cryptography (RSA) and competitive programming.
6. Speed Math & Bitwise Optimization
To excel in aptitude, mental math must be translated to hardware-level optimizations mentally.
6.1 Multiplication by Shifts
Multiplying by powers of 2 should always be conceptualized as bitwise left shifts (<<).
6.2 Fast Exponentiation (Binary Exponentiation)
To compute in time instead of .
Rust Implementation:
fn power_modulo(mut base: u64, mut exp: u64, modulus: u64) -> u64 {
let mut res = 1;
base = base % modulus;
while exp > 0 {
if exp % 2 == 1 { // if exp & 1 == 1
res = (res * base) % modulus;
}
exp = exp >> 1; // exp /= 2
base = (base * base) % modulus;
}
res
}
6.3 Checking Power of Two
Can be done in time and space using bitwise AND.
bool isPowerOfTwo(int x) {
return x > 0 && !(x & (x - 1));
}
Execution Trace for x=8 (1000):
x - 1 = 7 (0111).
8 & 7 = 1000 & 0111 = 0000. Returns True.
7. Deep Dive: Edge Cases & Pitfalls
- Modulo of Negative Numbers: In C/C++/Java,
-5 % 3returns-2. In Python,-5 % 3returns1. Always normalize modulo operations:(a % m + m) % m. - Overflow during Addition: When adding two 32-bit integers, it might exceed .
Fix:
int mid = low + ((high - low) >> 1);instead of(low + high) / 2. - Floating Point Imprecision: Never use
==for floats due to IEEE 754 representations. Useabs(a - b) < 1e-9.
8. Exhaustive Interview Questions
Question 1: What is the remainder when is divided by 9?
Trace & Proof: We know . . Rewrite as . So, . Wait, in the original text, a mistake was intentionally placed. Let's fix it properly. . So the answer is 8. (Note: If it were , it would be .)
Question 2: Find the smallest number which when divided by 6, 8, and 12 leaves a remainder of 3 in each case.
Trace & Proof: Let the number be . We are given: This implies is divisible by 6, 8, and 12. The smallest positive integer divisible by 6, 8, and 12 is their LCM. . Therefore, .
Question 3: Find the number of trailing zeros in .
Solution Formulation: A trailing zero is produced by a factor of 10, which is composed of a 2 and a 5. In , the number of factor 2s always exceeds the number of factor 5s. Thus, the number of zeros is determined by the highest power of 5 in . Legendre's Formula: For : Total = trailing zeros.
Question 4: Given a prime , find the modular multiplicative inverse of under modulo . What happens if is not prime?
Solution Formulation: If is prime, by Fermat's Little Theorem: . Multiply by : . This can be computed using Binary Exponentiation in . If is NOT prime, Fermat's Little Theorem fails. We must use the Extended Euclidean Algorithm to solve where is the inverse. This only exists if .
Question 5: Prove that the product of any three consecutive integers is always divisible by 6.
Proof: Let the integers be . At least one integer is divisible by 2 (since every second integer is even). At least one integer is divisible by 3 (since every third integer is a multiple of 3). Since 2 and 3 are coprime, the product is divisible by .
9. Conclusion
Mastery over number systems transcends passing aptitude tests. It is the core of cryptographic algorithm design, database indexing, and low-level system engineering. The principles discussed here—cyclicity, modular arithmetic, memory representations, and complexity management—form the bedrock upon which robust software is built.
Projects
-
Arbitrary-Precision Calculator (BigInt implementation) Build a custom BigInt class in C++ or Java from scratch that supports addition, subtraction, multiplication, and division for numbers up to 10,000 digits. This project forces you to deeply understand memory constraints, string parsing, and base-10 carrying mechanics. You must implement Karatsuba multiplication for optimal performance instead of standard multiplication. Additionally, incorporate robust error handling for division by zero and format parsing errors to make the library production-ready.
-
Cryptographic RSA Key Generator Create a Python utility that generates public and private RSA keys. This requires implementing the Extended Euclidean Algorithm for modular inverse, fast modular exponentiation, and the Miller-Rabin primality test. The project should be able to generate 1024-bit keys securely, cementing your understanding of Fermat's Little Theorem and modular arithmetic. To make it complete, implement a basic text encryption and decryption wrapper that uses the generated keys, demonstrating the real-world application of number theory.
-
Bitwise Arithmetic Engine Develop a library in Rust or C that performs basic arithmetic (addition, subtraction, multiplication, division) using ONLY bitwise operators (
&,|,^,<<,>>). No standard arithmetic operators (+,-,*,/) are allowed. This project builds extreme proficiency in low-level speed math and register-level operations. You should also include extensive unit tests asserting equivalence with standard operators across full 32-bit integer ranges, ensuring absolute correctness.
Assignments
-
Algorithm Optimization Assignment Given an array of integers, write a function to find the maximum possible GCD of any pair of numbers in the array. Your solution must run in time where is the maximum value in the array. Submit the code along with a formal time-complexity proof and a comprehensive suite of edge-case tests, such as arrays with identical elements or arrays with all prime numbers.
-
Cyclicity Implementation Task Write a script that correctly computes the last two digits of where and can be up to . You cannot use built-in BigInt or
powfunctions. The deliverable should include test cases covering base numbers ending in 0, 1, 5, 6, and edge cases where . Ensure that your algorithm completes well within standard 1-second execution limits, proving the efficiency of your cyclic patterns approach. -
Bit-Manipulation State Machine Challenge Implement an space and time solution to find the single element that appears exactly once in an array where every other element appears exactly three times. You must construct the state machine manually using bitwise operators. Document how the boolean logic maps to the problem constraints, complete with Karnaugh maps or truth tables in your README. Explain why intermediate variables for one-time and two-time appearances resolve the problem.
Debugging Guide
When working with number systems, speed math, and bitwise logic, bugs can be incredibly subtle. Here are common pitfalls and how to debug them effectively:
-
Bug: Modulo arithmetic yields negative results (e.g.,
-5 % 3returns-2in C/C++/Java). Fix: Always normalize negative modulos using the formula((a % m) + m) % m. This ensures the remainder is mathematically positive, which is essential for modular arithmetic formulas. -
Bug: Integer overflow during binary search or large additions
(low + high) / 2. Fix: Uselow + (high - low) / 2or bitwise shiftslow + ((high - low) >> 1). When multiplying or adding large values, defensively cast to a 64-bit integer before the operation to prevent truncation errors. -
Bug: Bitwise left shift by 32 or more on a 32-bit integer yields unexpected results. Fix: Shift amounts are typically masked by the processor architecture (e.g.,
x << 32becomesx << 0on x86). Always ensure your shift amountkis strictly less than the bit-width of the data type (i.e.,k < 32forint32). -
Bug: Floating-point equality checks failing on mathematically equal values due to precision limits. Fix: Never use
==for comparing floats. Instead, use an epsilon threshold check:abs(a - b) < 1e-9to safely account for IEEE 754 precision loss during division or decimal arithmetic.
Testing Strategy
Testing mathematical algorithms requires rigorous boundary and equivalence class testing to ensure correctness across all extreme edge cases.
- Boundary Value Analysis: Always explicitly test numbers at the very edge of register limits:
INT_MAX,INT_MIN,0,-1, and1. Verify the exact behavior when adding1toINT_MAXor multiplying large primes that risk exceeding 64-bit bounds. - Property-Based Testing: Instead of hardcoding expected outputs, test invariants mathematically. For example, when testing a custom GCD function, assert that
gcd(a, b)evenly divides bothaandbwith zero remainder, and verify that no larger integer does by checking basic multiples. - Cross-Validation / Oracle Testing: Compare your highly optimized, bitwise, or custom BigInt implementations directly against the language's battle-tested standard library (e.g., Python's native BigInt capabilities) for millions of randomized inputs.
- Fuzzing Edge Cases: Fuzz test your modular exponentiation and modular inverse functions with massive prime limits, composite modulus limits, and inputs where the base and the modulus share common factors to ensure appropriate error handling and termination.
- Performance Profiling: Use timing scripts to ensure that cyclicity checks and binary exponentiation operations do not covertly degrade to due to hidden string allocations or recursion depth overheads.
Production Usage
In enterprise software and high-performance computing, the concepts of number systems and speed math are heavily utilized.
- Cryptography and Security: Standard encryption protocols like RSA, Elliptic Curve Cryptography, and Diffie-Hellman Key Exchange rely completely on large prime factorization, modular arithmetic, and the Extended Euclidean Algorithm. Generating secure keys requires robust, optimized arbitrary-precision integer libraries.
- Database Indexing and Hashing: Distributed systems use Bloom filters, hash maps, and consistent hashing algorithms that heavily employ fast modulo operations, bit-shifting, and prime number distribution to minimize hashing collisions and distribute data uniformly across server clusters.
- Embedded Systems & Gaming: Game engines and IoT devices with highly constrained memory limits rely on bitwise flags (bitmasking) to store multiple boolean states in a single compact byte. This approach saves significant memory overhead and greatly accelerates CPU cache performance.
- High-Frequency Trading (HFT): Algorithmic HFT platforms typically avoid floating-point arithmetic entirely due to non-deterministic latency and standard imprecision. Instead, they use fixed-point integers (multiplied by a massive scale factor) and aggressive bitwise speed math for deterministic microsecond trade executions.
- Graphics Rendering: Shaders and rasterization pipelines frequently apply bitwise shifts and fast exponentiation algorithms to compute lighting vectors and pixel transformations natively on the GPU without triggering expensive arithmetic logic unit (ALU) cycles.
FAQs
Q: Why do I need to know bitwise operators if modern compilers automatically optimize my code anyway? A: While modern compilers are incredibly smart, they cannot mathematically redesign your fundamental algorithms. Knowing bitwise operators allows you to write inherently faster state machines, design extremely compact data structures like bitmasks, and tightly control the precise memory footprint and execution path of your application.
Q: Is it necessary to memorize all the divisibility rules for all numbers up to 20 for placements? A: Absolutely not. Focus on understanding the mathematical derivations for primary primes (2, 3, 5, 7, 11). Once you thoroughly understand how to derive these utilizing modular arithmetic, you can instantly deduce the rules for any composite number dynamically (e.g., checking 12 means checking both 3 and 4 independently).
Q: How do I properly handle negative numbers in modular arithmetic contexts?
A: Mathematically, a remainder is always meant to be positive. However, varying programming languages process this differently under the hood. You should always use the universal normalization pattern ((n % m) + m) % m to mathematically guarantee a strictly positive result across all languages, avoiding hidden bugs.
Q: What is the single most critical number theory concept for cracking technical interviews? A: The Euclidean Algorithm for GCD and basic Modular Exponentiation. These foundational concepts form the core basis of efficiently solving most array-based math puzzles and cyclicity challenges commonly encountered in rigorous coding rounds.
Revision Notes / Cheat Sheet
The following cheat sheet summarizes the essential number system rules, time complexities, and critical formulas for quick review before your interviews.
| Core Mathematical Concept | Key Formula / Rule to Remember | Standard Complexity | Practical Usage Notes |
| :--- | :--- | :--- | :--- |
| Fermat's Little Theorem | | theoretical | strictly requires to be a prime number and . |
| Euclidean GCD Algorithm | | | The recursive or iterative base case is always . |
| Fast Binary Exponentiation | via bitwise right-shift | | Halve the exponent iteratively while squaring the base at each step. |
| Trailing Zeros in Factorials (N!) | | | Trailing zeros depend exclusively on the exact count of factor 5s. |
| Cyclicity of Unit Digits| | | If the exponent , you must strictly use 4 as the exponent. |
| Check Power of 2 Manually | x > 0 && (x & (x - 1)) == 0 | | This bitwise trick mathematically clears the lowest set bit in one cycle. |
| Negative Modulo Normalization Fix | ((a % m) + m) % m | | Standardizes modular outputs universally across C++, Java, and Python. |
| Extended Euclidean Algorithm | | | Used exclusively for finding the modular multiplicative inverse. |