Check Evil Number in JavaScript

Beginner
⏱️ 8 min read
📚 Updated: May 2026
🎯 2 Code examples + Try it
Popcount parity

What you’ll learn

  • The definition of an evil number: even count of 1-bits in binary (nonnegative integers).
  • A bitwise popcount using >>> after >>> 0 plus a division-by-two variant for a small range.
  • Live preview, edge cases (0, negatives), and links to related topics.

Overview

Evil numbers classify integers by the parity of their Hamming weight in base 2. The check is: count 1 bits, then test whether that count is divisible by 2.

Two programs

One value (15) and evils in 1–10 matching the classic output.

Live preview

Nonnegative safe integers; shows popcount and evil vs odious.

Rigor

>>> unsigned shifts after >>> 0; nonnegative definition.

Prerequisites

Loops, % and division, basic bitwise &, and >>>.

  • console.log, Number.isSafeInteger, and nonnegative conventions.
  • Comfort reading small binary expansions (e.g. 15 = 11112 in prose as 1111).

What is an evil number?

A nonnegative integer n is evil if the binary representation of n contains an even number of 1 digits. If the count is odd, n is odious.

This is pure bit-level parity, unrelated to divisibility by 2 in decimal. The smallest evil numbers are 0, 3, 5, 6, 9, 10, 12, 15, ….

Evil popcount(n) % 2 === 0
Odious popcount(n) % 2 === 1
Zero evil (0 ones)

Hamming weight

Write n = ∑ b_i 2^i with b_i ∈ {0,1}. The Hamming weight is s_2(n) = ∑ b_i. Then n is evil iff s_2(n) ≡ 0 (mod 2).

15

15 = 8+4+2+1 = 11112, so s_2(15)=4 and 15 is evil.

Intuition

15 Evil
Binary
1111 — four ones
7 Odious
Binary
111 — three ones

Takeaway: flip one bit toggles parity, so consecutive numbers are not always both evil or both odious.

Live preview

Nonnegative integers in the JavaScript safe range. Popcount matches the division-by-two mental model.

Try 0, 7, or 10.

Live result
Press “Classify” to see popcount and verdict.

Algorithm

Goal: decide whether n ≥ 0 has an even number of 1-bits.

Popcount

Peel the least significant bit with n & 1 and n >>>= 1 after n >>> 0, or emulate binary digits with n % 2 and Math.floor(n / 2) for n ≥ 0.

Parity of the count

Evil iff count % 2 === 0. Range listing applies the predicate per index.

📜 Pseudocode

Pseudocode
function popcount(n):  // assume n >= 0
    c = 0
    while n > 0:
        c += (n mod 2)
        n = floor(n / 2)
    return c

function isEvil(n):
    return (popcount(n) mod 2) = 0
1

Bitwise popcount with >>>

Same verdict as the reference for 15. Coerces to unsigned 32-bit with >>> 0 before shifting so each step matches an unsigned right shift.

JavaScript
function countSetBitsU(n) {
  let count = 0;
  let x = n >>> 0;

  while (x !== 0) {
    count += x & 1;
    x >>>= 1;
  }

  return count;
}

function isEvilU(n) {
  return countSetBitsU(n) % 2 === 0;
}

const number = 15;

if (number < 0) {
  console.log("Evil/odious here are defined for nonnegative n only.");
} else if (!Number.isSafeInteger(number)) {
  console.log("Use a JavaScript safe integer.");
} else if (isEvilU(number)) {
  console.log(number + " is an Evil Number.");
} else {
  console.log(number + " is not an Evil Number.");
}
Try it Yourself

Explanation

countSetBitsU clears bits from the right until the value is zero. 15 has four 1 bits, so the count is even. Values larger than 232-1 truncate modulo 232 when using >>> 0; use the division loop if you need full safe integers.

2

Evil numbers in [1, 10]

Matches the reference output: 3 5 6 9 10. Uses the division-and-modulo loop (equivalent for nonnegative n).

JavaScript
function isEvilNonNeg(num) {
  let ones = 0;

  while (num > 0) {
    if (num % 2 === 1) {
      ones++;
    }
    num = Math.floor(num / 2);
  }

  return ones % 2 === 0;
}

console.log("Evil numbers in the range 1 to 10:");

let line = "";
for (let i = 1; i <= 10; i++) {
  if (isEvilNonNeg(i)) {
    line += i + " ";
  }
}

console.log(line.trim());
Try it Yourself

Explanation

Each iteration reads the least significant binary digit of num via num % 2, then shifts right with Math.floor(num / 2).

Optimization

Kernighan trick. On unsigned 32-bit math, repeatedly set x = x & (x - 1) after x >>> 0; each step clears one 1.

Built-ins. Engines optimize bitwise ops heavily; for BigInts you still loop or use ad hoc popcount.

Interview: define the nonnegative convention, mention 0, and contrast >> vs >>>.

❓ FAQ

A nonnegative integer n is evil if its base-2 representation contains an even number of digit 1 (equivalently, the Hamming weight or population count is even).
If the count of 1-bits is odd, n is called odious. Every nonnegative integer is either evil or odious.
Yes. Zero has no 1-bits, so the count is 0, which is even.
15 is 1111 in binary: four 1-bits. Four is even, so 15 is evil.
>> keeps the sign bit for negative numbers (arithmetic shift), while >>> zero-fills, matching an unsigned right-shift chain after coercing with >>> 0. For nonnegative safe integers, dividing by 2 in a loop is equally clear and avoids 32-bit truncation.
Counting bits for one n costs O(log n) in the value of n (number of bits). Scanning [a,b] costs O((b-a+1) log U) where U is the largest value in the range.

🔄 Input / output examples

Change number in Example 1 or extend the loop bounds in Example 2.

nBinaryOnesVerdict
000Evil
3112Evil
71113Odious
1511114Evil

Edge cases and pitfalls

The mathematical definition is for nonnegative integers. Negative numbers use two's complement encodings; mixing naive >> on negatives with counting semantics needs an explicit convention.

Zero

n = 0

Popcount 0 is even, so 0 is evil.

Sign

Negative numbers

Example 1 rejects n < 0 for clarity. If you must classify negatives, map them with >>> 0 or BigInt and document which bits you count.

Width

Leading zeros

Infinitely many leading zeros do not change the finite count of 1 bits in the minimal binary form.

Range

1 ≤ i ≤ 10

Example 2 omits 0 by loop start; include 0 if the problem asks for nonnegative evils in the interval.

⏱️ Time and space complexity

OperationTimeExtra space
Popcount of nO(log n) bit stepsO(1)
Kernighan variantO(popcount(n))O(1)
Scan [a,b]O((b-a+1) log U)O(1)

Here U = max(|n|, 1) for a single value, or the largest value in the scanned range.

Summary

  • Definition: evil iff the binary digit sum is even; otherwise odious.
  • Code: bitwise with >>> after >>> 0, or % 2 with Math.floor(n / 2) for n ≥ 0.
  • Watch-outs: define nonnegative scope; avoid mixing >> sign extension when you want unsigned walks.
Did you know?

The complementary class is odious numbers: nonnegative integers whose binary expansion has an odd number of 1 bits. The name “evil” vs “odious” is mathematical wordplay, not moral judgment.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful