diff --git a/README.md b/README.md
index 7d7b881..c27d845 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@ One module per article. This repository currently holds:
| [`junit-mockito`](junit-mockito/) | Top 30 JUnit 6 and Mockito Interview Questions (2026) | this commit |
| [`hashmap-vs-concurrenthashmap`](hashmap-vs-concurrenthashmap/) | HashMap vs ConcurrentHashMap in Java: Internals, Thread Safety and Interview Answers | this commit |
| [`multithreading`](multithreading/) | Java Multithreading Programs for Interviews: Odd-Even Printing, Ping-Pong, Ordered Threads, Deadlock | this commit |
+| [`disarium-number`](disarium-number/) | Disarium Number in Java: Program, Algorithm and All Disarium Numbers from 1 to 1000 | this commit |
## `collections` module
diff --git a/disarium-number/README.md b/disarium-number/README.md
new file mode 100644
index 0000000..1483218
--- /dev/null
+++ b/disarium-number/README.md
@@ -0,0 +1,25 @@
+# disarium-number
+
+Disarium number checks in plain Java 25: the original `Math.pow` loop, an integer-power loop, a
+String version, a Streams version and a `log10` digit-count variant. A test proves they agree, and
+`output/` holds the transcripts quoted in the post. Companion to
+[Disarium Number in Java: Program, Algorithm and All Disarium Numbers from 1 to 1000](https://ankurm.com/disarium-number-in-java/).
+
+## Versions
+
+| Component | Version |
+|---|---|
+| JDK | 25.0.5+8 (Temurin LTS), `--release 25` |
+| JUnit Jupiter | 6.1.3 |
+| Maven | 3.9.11 |
+
+## Run it
+
+```bash
+cd disarium-number
+./scripts/run.sh check # also: list | dryrun | approaches | digits | count
+mvn test # 6 tests
+./scripts/run-all.sh # regenerates output/*.txt (count takes ~2 minutes)
+```
+
+`count` brute-forces every int up to 10^8; the timing depends on your machine.
diff --git a/disarium-number/output/01-check-and-series.txt b/disarium-number/output/01-check-and-series.txt
new file mode 100644
index 0000000..7837d2a
--- /dev/null
+++ b/disarium-number/output/01-check-and-series.txt
@@ -0,0 +1,9 @@
+ 89 -> Disarium
+ 135 -> Disarium
+ 175 -> Disarium
+ 518 -> Disarium
+ 598 -> Disarium
+ 24 -> NOT Disarium
+ 100 -> NOT Disarium
+
+Disarium numbers up to 1000: 1 2 3 4 5 6 7 8 9 89 135 175 518 598
diff --git a/disarium-number/output/02-list-1-to-1000.txt b/disarium-number/output/02-list-1-to-1000.txt
new file mode 100644
index 0000000..f8af0e1
--- /dev/null
+++ b/disarium-number/output/02-list-1-to-1000.txt
@@ -0,0 +1,2 @@
+count=14
+1 2 3 4 5 6 7 8 9 89 135 175 518 598
diff --git a/disarium-number/output/03-dry-run.txt b/disarium-number/output/03-dry-run.txt
new file mode 100644
index 0000000..1f9cd3b
--- /dev/null
+++ b/disarium-number/output/03-dry-run.txt
@@ -0,0 +1,5 @@
+175 = 1^1 + 7^2 + 5^3 = 1 + 49 + 125 = 175 -> Disarium
+89 = 8^1 + 9^2 = 8 + 81 = 89 -> Disarium
+135 = 1^1 + 3^2 + 5^3 = 1 + 9 + 125 = 135 -> Disarium
+24 = 2^1 + 4^2 = 2 + 16 = 18 -> NOT Disarium (18 != 24)
+100 = 1^1 + 0^2 + 0^3 = 1 + 0 + 0 = 1 -> NOT Disarium (1 != 100)
diff --git a/disarium-number/output/04-approaches-agree.txt b/disarium-number/output/04-approaches-agree.txt
new file mode 100644
index 0000000..4063d26
--- /dev/null
+++ b/disarium-number/output/04-approaches-agree.txt
@@ -0,0 +1 @@
+compared original, loop, String, stream, log10 for 1..1000000: disagreements=0
diff --git a/disarium-number/output/05-log10-digit-count.txt b/disarium-number/output/05-log10-digit-count.txt
new file mode 100644
index 0000000..408ae72
--- /dev/null
+++ b/disarium-number/output/05-log10-digit-count.txt
@@ -0,0 +1 @@
+log10 vs loop digit count around every power of ten: mismatches=0
diff --git a/disarium-number/output/06-count-to-10-pow-8.txt b/disarium-number/output/06-count-to-10-pow-8.txt
new file mode 100644
index 0000000..f6aae0f
--- /dev/null
+++ b/disarium-number/output/06-count-to-10-pow-8.txt
@@ -0,0 +1,9 @@
+up to 10^1: 9
+up to 10^2: 10
+up to 10^3: 14
+up to 10^4: 17
+up to 10^5: 17
+up to 10^6: 17
+up to 10^7: 18
+up to 10^8: 18
+found at or above 1000: 1306 1676 2427 2646798
diff --git a/disarium-number/output/07-test-results.txt b/disarium-number/output/07-test-results.txt
new file mode 100644
index 0000000..cb6c992
--- /dev/null
+++ b/disarium-number/output/07-test-results.txt
@@ -0,0 +1,7 @@
+PASS DisariumTest.allApproachesAgreeUpTo200000
+PASS DisariumTest.dryRunOf175
+PASS DisariumTest.dryRunOf24
+PASS DisariumTest.zeroAndNegativesAreNotDisarium
+PASS DisariumTest.biggerKnownOnes
+PASS DisariumTest.listUpTo1000
+6 tests, 0 failures
diff --git a/disarium-number/pom.xml b/disarium-number/pom.xml
new file mode 100644
index 0000000..57502ab
--- /dev/null
+++ b/disarium-number/pom.xml
@@ -0,0 +1,27 @@
+
+
+ 4.0.0
+
+ com.ankurm.interviewlab
+ disarium-number
+ 1.0.0
+ disarium-number
+ Disarium number checks in Java: loop, String and stream approaches, with a dry run and counts
+
+
+ 25
+ UTF-8
+ 6.1.3
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit.version}
+ test
+
+
+
diff --git a/disarium-number/scripts/run-all.sh b/disarium-number/scripts/run-all.sh
new file mode 100755
index 0000000..ea24fdd
--- /dev/null
+++ b/disarium-number/scripts/run-all.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# Regenerates every transcript in output/. Needs JDK 25 and Maven 3.9+.
+set -euo pipefail
+cd "$(dirname "$0")/.."
+mkdir -p output
+./scripts/run.sh check > output/01-check-and-series.txt
+./scripts/run.sh list > output/02-list-1-to-1000.txt
+./scripts/run.sh dryrun > output/03-dry-run.txt
+./scripts/run.sh approaches > output/04-approaches-agree.txt
+./scripts/run.sh digits > output/05-log10-digit-count.txt
+./scripts/run.sh count > output/06-count-to-10-pow-8.txt
+mvn -B -q test > /dev/null 2>&1
+python3 - <<'PY' > output/07-test-results.txt
+import glob, xml.etree.ElementTree as ET
+total = fail = 0
+for f in sorted(glob.glob("target/surefire-reports/TEST-*.xml")):
+ for tc in ET.parse(f).getroot().iter("testcase"):
+ bad = tc.find("failure") is not None or tc.find("error") is not None
+ total += 1; fail += bad
+ print(("FAIL " if bad else "PASS ") + tc.get("classname").split(".")[-1] + "." + tc.get("name"))
+print(f"{total} tests, {fail} failures")
+PY
diff --git a/disarium-number/scripts/run.sh b/disarium-number/scripts/run.sh
new file mode 100755
index 0000000..d35db50
--- /dev/null
+++ b/disarium-number/scripts/run.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+# Runs one demo: ./scripts/run.sh check | list | dryrun | approaches | count | digits
+set -euo pipefail
+cd "$(dirname "$0")/.."
+mvn -B -q compile 2>&1 | grep -E 'ERROR' || true
+java -cp target/classes com.ankurm.disarium.Main "$@"
diff --git a/disarium-number/src/main/java/com/ankurm/disarium/Disarium.java b/disarium-number/src/main/java/com/ankurm/disarium/Disarium.java
new file mode 100644
index 0000000..8099cad
--- /dev/null
+++ b/disarium-number/src/main/java/com/ankurm/disarium/Disarium.java
@@ -0,0 +1,108 @@
+package com.ankurm.disarium;
+
+import java.util.List;
+import java.util.stream.IntStream;
+
+/** Three independent ways to test a Disarium number. All must agree (see DisariumTest). */
+public final class Disarium {
+ private Disarium() {}
+
+ /** The program from the original post, kept as-is (uses Math.pow). */
+ public static boolean isDisariumOriginal(int number) {
+ int original = number;
+ int len = countDigits(number);
+ int sum = 0;
+ int n = number;
+ while (n > 0) {
+ int digit = n % 10;
+ sum += (int) Math.pow(digit, len);
+ len--;
+ n /= 10;
+ }
+ return sum == original;
+ }
+
+ public static int countDigits(int n) {
+ int count = 0;
+ while (n > 0) {
+ count++;
+ n /= 10;
+ }
+ return count;
+ }
+
+ /** Approach 1: loop over the digits right to left; integer power, no floating point. */
+ public static boolean isDisariumLoop(int number) {
+ if (number <= 0) return false;
+ int len = countDigits(number);
+ long sum = 0;
+ for (int n = number; n > 0; n /= 10, len--) {
+ sum += intPow(n % 10, len);
+ }
+ return sum == number;
+ }
+
+ /** Approach 2: String of digits, left to right, position = index + 1. */
+ public static boolean isDisariumString(int number) {
+ if (number <= 0) return false;
+ String s = Integer.toString(number);
+ long sum = 0;
+ for (int i = 0; i < s.length(); i++) {
+ sum += intPow(s.charAt(i) - '0', i + 1);
+ }
+ return sum == number;
+ }
+
+ /** Approach 3: Streams over the characters of the String. */
+ public static boolean isDisariumStream(int number) {
+ if (number <= 0) return false;
+ String s = Integer.toString(number);
+ long sum = IntStream.range(0, s.length())
+ .mapToLong(i -> intPow(s.charAt(i) - '0', i + 1))
+ .sum();
+ return sum == number;
+ }
+
+ /** Digit count via log10 instead of a loop (used by the maths variant). */
+ public static int digitsLog10(int n) {
+ return (int) Math.log10(n) + 1;
+ }
+
+ /** Approach 1b: same as the loop, but the digit count comes from log10. */
+ public static boolean isDisariumLog10(int number) {
+ if (number <= 0) return false;
+ int len = digitsLog10(number);
+ long sum = 0;
+ for (int n = number; n > 0; n /= 10, len--) {
+ sum += intPow(n % 10, len);
+ }
+ return sum == number;
+ }
+
+ static long intPow(int base, int exp) {
+ long r = 1;
+ for (int i = 0; i < exp; i++) r *= base;
+ return r;
+ }
+
+ public static List upTo(int limit) {
+ return IntStream.rangeClosed(1, limit).filter(Disarium::isDisariumLoop).boxed().toList();
+ }
+
+ /** Human-readable dry run: "175 = 1^1 + 7^2 + 5^3 = 1 + 49 + 125 = 175". */
+ public static String dryRun(int number) {
+ String s = Integer.toString(number);
+ StringBuilder terms = new StringBuilder(), values = new StringBuilder();
+ long sum = 0;
+ for (int i = 0; i < s.length(); i++) {
+ int d = s.charAt(i) - '0';
+ long v = intPow(d, i + 1);
+ sum += v;
+ if (i > 0) { terms.append(" + "); values.append(" + "); }
+ terms.append(d).append('^').append(i + 1);
+ values.append(v);
+ }
+ return number + " = " + terms + " = " + values + " = " + sum
+ + (sum == number ? " -> Disarium" : " -> NOT Disarium (" + sum + " != " + number + ")");
+ }
+}
diff --git a/disarium-number/src/main/java/com/ankurm/disarium/Main.java b/disarium-number/src/main/java/com/ankurm/disarium/Main.java
new file mode 100644
index 0000000..bab2759
--- /dev/null
+++ b/disarium-number/src/main/java/com/ankurm/disarium/Main.java
@@ -0,0 +1,65 @@
+package com.ankurm.disarium;
+
+import java.util.List;
+
+/** Usage: Main check | list | dryrun | count | digits */
+public final class Main {
+ public static void main(String[] args) {
+ String mode = args.length > 0 ? args[0] : "list";
+ switch (mode) {
+ case "check" -> {
+ for (int n : new int[] {89, 135, 175, 518, 598, 24, 100}) {
+ System.out.printf("%4d -> %s%n", n, Disarium.isDisariumOriginal(n) ? "Disarium" : "NOT Disarium");
+ }
+ System.out.println();
+ System.out.println("Disarium numbers up to 1000: " + join(Disarium.upTo(1000)));
+ }
+ case "list" -> {
+ List l = Disarium.upTo(1000);
+ System.out.println("count=" + l.size());
+ System.out.println(join(l));
+ }
+ case "dryrun" -> {
+ for (int n : new int[] {175, 89, 135, 24, 100}) System.out.println(Disarium.dryRun(n));
+ }
+ case "approaches" -> {
+ int bad = 0;
+ for (int n = 1; n <= 1_000_000; n++) {
+ boolean a = Disarium.isDisariumOriginal(n), b = Disarium.isDisariumLoop(n),
+ c = Disarium.isDisariumString(n), d = Disarium.isDisariumStream(n),
+ e = Disarium.isDisariumLog10(n);
+ if (a != b || b != c || c != d || d != e) { bad++; System.out.println("DISAGREE at " + n); }
+ }
+ System.out.println("compared original, loop, String, stream, log10 for 1..1000000: disagreements=" + bad);
+ }
+ case "count" -> {
+ // Brute force up to 10^8 with the loop approach, reporting when each power of ten is passed.
+ int found = 0;
+ long limit = 100_000_000L;
+ long mark = 10;
+ StringBuilder sb = new StringBuilder();
+ for (int n = 1; n <= limit; n++) {
+ if (Disarium.isDisariumLoop(n)) { found++; if (n >= 1000) sb.append(n).append(' '); }
+ if (n == mark) { System.out.println("up to 10^" + (int) Math.log10(mark) + ": " + found); mark *= 10; }
+ }
+ System.out.println("found at or above 1000: " + sb.toString().trim());
+ }
+ case "digits" -> {
+ // Where does Math.log10 digit counting go wrong? Compare with the loop for all ints near powers of ten.
+ int wrong = 0;
+ long p = 1;
+ for (int k = 0; k < 10; k++, p *= 10) {
+ for (long n = Math.max(1, p - 2); n <= p + 2 && n <= Integer.MAX_VALUE; n++) {
+ if (Disarium.digitsLog10((int) n) != Disarium.countDigits((int) n)) { wrong++; System.out.println("log10 wrong at " + n); }
+ }
+ }
+ System.out.println("log10 vs loop digit count around every power of ten: mismatches=" + wrong);
+ }
+ default -> throw new IllegalArgumentException(mode);
+ }
+ }
+
+ private static String join(List l) {
+ return String.join(" ", l.stream().map(String::valueOf).toList());
+ }
+}
diff --git a/disarium-number/src/test/java/com/ankurm/disarium/DisariumTest.java b/disarium-number/src/test/java/com/ankurm/disarium/DisariumTest.java
new file mode 100644
index 0000000..2ad2cca
--- /dev/null
+++ b/disarium-number/src/test/java/com/ankurm/disarium/DisariumTest.java
@@ -0,0 +1,43 @@
+package com.ankurm.disarium;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class DisariumTest {
+ static final List TO_1000 = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 89, 135, 175, 518, 598);
+
+ @Test void listUpTo1000() { assertEquals(TO_1000, Disarium.upTo(1000)); }
+
+ @Test void allApproachesAgreeUpTo200000() {
+ for (int n = 1; n <= 200_000; n++) {
+ boolean e = Disarium.isDisariumLoop(n);
+ assertEquals(e, Disarium.isDisariumOriginal(n), "original " + n);
+ assertEquals(e, Disarium.isDisariumString(n), "string " + n);
+ assertEquals(e, Disarium.isDisariumStream(n), "stream " + n);
+ assertEquals(e, Disarium.isDisariumLog10(n), "log10 " + n);
+ }
+ }
+
+ @Test void dryRunOf175() {
+ assertEquals("175 = 1^1 + 7^2 + 5^3 = 1 + 49 + 125 = 175 -> Disarium", Disarium.dryRun(175));
+ }
+
+ @Test void dryRunOf24() {
+ assertEquals("24 = 2^1 + 4^2 = 2 + 16 = 18 -> NOT Disarium (18 != 24)", Disarium.dryRun(24));
+ }
+
+ @Test void zeroAndNegativesAreNotDisarium() {
+ assertFalse(Disarium.isDisariumLoop(0));
+ assertFalse(Disarium.isDisariumString(-5));
+ assertFalse(Disarium.isDisariumStream(0));
+ }
+
+ @Test void biggerKnownOnes() {
+ assertTrue(Disarium.isDisariumLoop(2646798));
+ assertTrue(Disarium.isDisariumStream(2646798));
+ assertFalse(Disarium.isDisariumStream(12157692));
+ assertFalse(Disarium.isDisariumString(2646799));
+ }
+}