Math Operations — Interview Questions¶
Junior Level (7 Questions)¶
Q1: What are the five basic arithmetic operators in Java?¶
Answer
The five arithmetic operators are: | Operator | Name | Example | Result | |----------|------|---------|--------| | `+` | Addition | `5 + 3` | `8` | | `-` | Subtraction | `5 - 3` | `2` | | `*` | Multiplication | `5 * 3` | `15` | | `/` | Division | `5 / 3` | `1` (integer) | | `%` | Modulo (remainder) | `5 % 3` | `2` | **Key point:** Integer division truncates the decimal part. To get a decimal result, at least one operand must be `double` or `float`.Q2: What is the difference between x++ and ++x?¶
Answer
Both increment `x` by 1, but they differ in the **value returned by the expression**: - **Post-increment (`x++`):** Use current value in expression, then add 1 - **Pre-increment (`++x`):** Add 1 first, then use new value in expression The final value of `x` is the same in both cases — only the intermediate expression value differs.Q3: What does 10 / 3 return? How about 10.0 / 3?¶
Answer
When both operands are `int`, Java performs **integer division** (truncation toward zero). When at least one operand is `float` or `double`, Java performs floating-point division. **Common mistake:** Writing `double result = 1 / 3;` expecting `0.333...` but getting `0.0` because `1 / 3` is evaluated as integer division first, then widened to `double`.Q4: Name five commonly used methods from the Math class.¶
Answer
| Method | Description | Example | |--------|-------------|---------| | `Math.abs(x)` | Absolute value | `Math.abs(-5)` = `5` | | `Math.max(a, b)` | Larger of two values | `Math.max(3, 7)` = `7` | | `Math.min(a, b)` | Smaller of two values | `Math.min(3, 7)` = `3` | | `Math.pow(base, exp)` | Power | `Math.pow(2, 10)` = `1024.0` | | `Math.sqrt(x)` | Square root | `Math.sqrt(144)` = `12.0` | | `Math.random()` | Random double [0, 1) | `0.0` to `0.999...` | | `Math.round(x)` | Round to nearest integer | `Math.round(4.5)` = `5` | | `Math.ceil(x)` | Round up | `Math.ceil(4.1)` = `5.0` | | `Math.floor(x)` | Round down | `Math.floor(4.9)` = `4.0` | `Math` is in `java.lang`, so no import is needed. All methods are `static`.Q5: What happens when you divide an integer by zero? What about a double by zero?¶
Answer
**Why the difference?** Integer division has no way to represent infinity, so it throws an exception. Floating-point follows the IEEE 754 standard, which defines special values for infinity and "not a number" (NaN).Q6: What is operator precedence? Give an example.¶
Answer
Operator precedence determines the order in which operators are evaluated: **Precedence (high to low):** 1. Parentheses `()` 2. Unary: `++`, `--`, `+`, `-` 3. Multiplicative: `*`, `/`, `%` 4. Additive: `+`, `-` 5. Assignment: `=`, `+=`, `-=`, etc. **Best practice:** When in doubt, use parentheses to make intent clear.Q7: Why does System.out.println("Value: " + 2 + 3) print "Value: 23" instead of "Value: 5"?¶
Answer
The `+` operator is evaluated left to right: 1. `"Value: " + 2` — String concatenation produces `"Value: 2"` 2. `"Value: 2" + 3` — String concatenation produces `"Value: 23"` Once a `String` is involved, subsequent `+` operators perform concatenation, not addition. **Fix:** Use parentheses to force arithmetic first: **Another example:**Middle Level (7 Questions)¶
Q8: Why should you never use double for monetary calculations?¶
Answer
`double` uses binary floating-point (IEEE 754), which cannot exactly represent most decimal fractions: In financial systems, these tiny errors accumulate over millions of transactions, leading to discrepancies. **Solution:** Use `BigDecimal` with `String` constructor: **Rule:** Always create `BigDecimal` from a `String`, never from a `double`.Q9: What is the difference between BigDecimal.equals() and BigDecimal.compareTo()?¶
Answer
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1.00");
System.out.println(a.equals(b)); // false — different scale (1 vs 2)
System.out.println(a.compareTo(b)); // 0 — numerically equal
// Dangerous: different scales create different map entries
Map<BigDecimal, String> map = new HashMap<>();
map.put(new BigDecimal("1.0"), "one");
map.put(new BigDecimal("1.00"), "one again");
System.out.println(map.size()); // 2 (two entries!)
// Safe: use TreeMap (uses compareTo)
Map<BigDecimal, String> treeMap = new TreeMap<>();
treeMap.put(new BigDecimal("1.0"), "one");
treeMap.put(new BigDecimal("1.00"), "one again");
System.out.println(treeMap.size()); // 1
Q10: What are Math.addExact() and related methods? When would you use them?¶
Answer
Java 8 introduced `Math.*Exact()` methods that throw `ArithmeticException` on overflow instead of silently wrapping: **Available methods:** - `Math.addExact(int, int)` / `Math.addExact(long, long)` - `Math.subtractExact(int, int)` / `Math.subtractExact(long, long)` - `Math.multiplyExact(int, int)` / `Math.multiplyExact(long, long)` - `Math.incrementExact(int)` / `Math.decrementExact(int)` - `Math.negateExact(int)` / `Math.toIntExact(long)` **Use when:** Input comes from external sources (user input, APIs) and overflow would be a security risk or logical error. NOT needed for loop counters or internal calculations with known bounds.Q11: What does Math.floorMod(-7, 3) return? How is it different from -7 % 3?¶
Answer
**Standard `%` (truncation modulo):** Result has the same sign as the **dividend** (left operand). - `-7 = (-2) * 3 + (-1)`, so `-7 % 3 = -1` **`Math.floorMod()` (floor modulo):** Result has the same sign as the **divisor** (right operand). - `-7 = (-3) * 3 + 2`, so `floorMod(-7, 3) = 2` **Practical use case:** Circular array indexing:Q12: What is NaN? How do you check for it?¶
Answer
NaN ("Not a Number") is a special floating-point value defined by IEEE 754. It results from undefined mathematical operations: **Key property — NaN is not equal to anything, including itself:** **How to check:** **NaN behavior in comparisons:** - Any comparison with NaN returns `false` (except `!=`) - `NaN < 5` is `false`, `NaN > 5` is `false`, `NaN == 5` is `false`Q13: What RoundingMode should banks use, and why?¶
Answer
Banks should use `RoundingMode.HALF_EVEN` (also called **banker's rounding**):BigDecimal a = new BigDecimal("2.5");
BigDecimal b = new BigDecimal("3.5");
BigDecimal c = new BigDecimal("4.5");
// HALF_UP: always rounds 0.5 up
System.out.println(a.setScale(0, RoundingMode.HALF_UP)); // 3
System.out.println(b.setScale(0, RoundingMode.HALF_UP)); // 4
// HALF_EVEN: rounds 0.5 to nearest EVEN number
System.out.println(a.setScale(0, RoundingMode.HALF_EVEN)); // 2 (even)
System.out.println(b.setScale(0, RoundingMode.HALF_EVEN)); // 4 (even)
System.out.println(c.setScale(0, RoundingMode.HALF_EVEN)); // 4 (even)
Q14: What happens with Math.abs(Integer.MIN_VALUE)?¶
Answer
This is because: - `Integer.MIN_VALUE` = -2,147,483,648 - `Integer.MAX_VALUE` = 2,147,483,647 - The positive value 2,147,483,648 does not fit in `int` range - The result overflows back to `Integer.MIN_VALUE` **Safe alternatives:**Senior Level (6 Questions)¶
Q15: How would you design a high-throughput pricing engine that needs exact decimal arithmetic?¶
Answer
**Strategy: Fixed-point `long` arithmetic on hot path, `BigDecimal` at boundaries.**// Store money as cents (long) — 100x faster than BigDecimal
long priceCents = 1999; // $19.99
long taxMicros = 80000; // 8% (in millionths)
// Hot path: pure long arithmetic
long taxCents = (priceCents * taxMicros + 500_000) / 1_000_000;
long totalCents = priceCents + taxCents;
// Boundary: convert to BigDecimal for API response / persistence
BigDecimal total = BigDecimal.valueOf(totalCents, 2); // $21.59
Q16: Explain the difference between LongAdder and AtomicLong. When would you use each?¶
Answer
**`AtomicLong`** uses a single shared variable with CAS (compare-and-swap): - Every thread contends on the same memory location - Good for low contention (1-4 threads) - Supports `get()`, `compareAndSet()`, `getAndAdd()` **`LongAdder`** uses striped cells — each thread writes to its own cell, sum is computed lazily: - Reduces contention by spreading updates across multiple cells - 5-10x faster than `AtomicLong` under high contention (8+ threads) - `sum()` is NOT atomic — may miss concurrent updates - Does NOT support `compareAndSet()`// Use AtomicLong when:
// - You need read-your-write consistency
// - You need compareAndSet (optimistic locking)
// - Contention is low
AtomicLong sequence = new AtomicLong();
long next = sequence.incrementAndGet();
// Use LongAdder when:
// - Write-heavy, read-infrequent
// - High contention (metrics, counters)
// - Exact sum only needed at reporting time
LongAdder requestCounter = new LongAdder();
requestCounter.increment();
long total = requestCounter.sum(); // not real-time accurate
Q17: What is Kahan summation and when do you need it?¶
Answer
**Problem:** When summing millions of `double` values, naive addition accumulates floating-point rounding errors: **Kahan summation** compensates for lost low-order bits by tracking a compensation variable: **When to use:** - Summing large arrays of floating-point values (statistics, scientific computing) - When the sum is much larger than individual values (catastrophic cancellation risk) - Financial reporting over large datasets **Alternatives:** `DoubleStream.sum()` in Java uses Kahan-like compensation internally.Q18: How does the JIT compiler optimize Math.sqrt() and Math.abs()?¶
Answer
The HotSpot JIT compiler treats many `Math` methods as **intrinsics** — it replaces the method call with direct CPU instructions: | Method | x86-64 Instruction | Cost | |--------|-------------------|------| | `Math.sqrt(double)` | `vsqrtsd` | ~15 cycles | | `Math.abs(double)` | `vandpd` (mask sign bit) | 1 cycle | | `Math.max(int, int)` | `cmp` + `cmov` (no branch) | 2 cycles | | `Math.addExact(int, int)` | `add` + `jo` (hardware overflow flag) | 1-2 cycles | No method call overhead occurs — the JIT inlines these to single or few CPU instructions. This is why `Math.sqrt()` is as fast as a C implementation. **Verification:** Use `-XX:+PrintAssembly` with hsdis to confirm intrinsification in JIT output. **Note:** `Math.sin()`, `Math.cos()`, and `Math.log()` are NOT always intrinsified — they may fall back to software implementations (fdlibm), which are slower.Q19: Explain the BigDecimal compact representation. What is intCompact?¶
Answer
`BigDecimal` has a dual internal representation: 1. **Compact form:** For values where the unscaled value fits in a `long`, the value is stored directly in `intCompact` (a `long` field). No `BigInteger` object is allocated. 2. **Inflated form:** When the unscaled value exceeds `long` range, a `BigInteger` object is allocated and stored in `intVal`. The `intCompact` field is set to `INFLATED` (sentinel value `Long.MIN_VALUE`). **Why this matters:** Compact `BigDecimal` operations are significantly faster (long arithmetic) than inflated operations (BigInteger with int[] arrays). Most real-world `BigDecimal` values stay compact. **Performance impact:** Compact `BigDecimal.add()` is ~3-5x faster than inflated.Q20: What is the difference between Math and StrictMath?¶
Answer
| Aspect | `Math` | `StrictMath` | |--------|--------|-------------| | **Implementation** | May use platform-native hardware | Always uses fdlibm (C software library) | | **Speed** | Potentially faster (hardware-optimized) | Slower (pure software) | | **Reproducibility** | Results may vary across platforms | Bit-for-bit identical on all platforms | | **Intrinsics** | JIT can replace with CPU instructions | Less likely to be intrinsified | **Note:** Since Java 17, `strictfp` semantics are the default (JEP 306), so `Math` and `StrictMath` produce identical results for basic operations. The difference remains for transcendental functions (`sin`, `cos`, `log`). **Use `StrictMath` when:** Deterministic simulations, reproducible test results, financial regulation requiring cross-platform consistency.Coding Challenges¶
Challenge 1: Implement Integer Square Root Without Math.sqrt¶
Write a method that computes the integer square root of a non-negative integer (the largest integer whose square is <= n) without using Math.sqrt().
Solution
public class Main {
// Binary search approach — O(log n)
public static int intSqrt(int n) {
if (n < 0) throw new IllegalArgumentException("Negative input");
if (n < 2) return n;
long low = 1, high = n / 2 + 1;
while (low <= high) {
long mid = low + (high - low) / 2;
long square = mid * mid;
if (square == n) return (int) mid;
else if (square < n) low = mid + 1;
else high = mid - 1;
}
return (int) high;
}
// Newton's method — converges faster
public static int intSqrtNewton(int n) {
if (n < 2) return n;
long x = n;
while (x * x > n) {
x = (x + n / x) / 2;
}
return (int) x;
}
public static void main(String[] args) {
System.out.println(intSqrt(144)); // 12
System.out.println(intSqrt(10)); // 3
System.out.println(intSqrtNewton(144)); // 12
}
}
Challenge 2: Implement Power Function Without Math.pow¶
Implement power(base, exp) that handles negative exponents and returns double.
Solution
public class Main {
// Fast exponentiation — O(log n)
public static double power(double base, int exp) {
if (exp == 0) return 1.0;
if (exp < 0) {
base = 1.0 / base;
exp = -exp;
}
double result = 1.0;
while (exp > 0) {
if ((exp & 1) == 1) {
result *= base;
}
base *= base;
exp >>= 1;
}
return result;
}
public static void main(String[] args) {
System.out.println(power(2, 10)); // 1024.0
System.out.println(power(3, -2)); // 0.1111...
System.out.println(power(5, 0)); // 1.0
}
}
Diagram: Interview Question Categories¶
mindmap root((Math Operations<br/>Interview Topics)) Junior Arithmetic operators Integer vs float division Pre/post increment Math class methods Operator precedence Middle BigDecimal usage Integer overflow NaN behavior floorMod vs % Rounding modes Senior Fixed-point architecture LongAdder vs AtomicLong Kahan summation JIT intrinsics BigDecimal internals
graph TD A["Interview Preparation Path"] --> B["Know the basics"] B --> C["Understand float precision"] C --> D["Master BigDecimal"] D --> E["Learn overflow detection"] E --> F["Understand JVM optimizations"] F --> G["Design numeric architectures"]