- Binary
1111— four ones
Check Evil Number in C#
What you’ll learn
- What evil means: an even count of
1bits in binary — and the opposite word odious when that count is odd. - Two C# styles: peel bits with
uintand shifts, or build a binary string withConvert.ToString(n, 2)and count'1'characters. - A range demo (
1–10) plus a live preview that prints binary, popcount, and why the verdict follows.
Overview
Computers store integers as bits. An evil number is just a nonnegative integer whose binary spelling uses an even number of 1s. Count those ones (sometimes called population count or Hamming weight), then check whether that count is divisible by 2.
Two programs
One checks 15 with bitwise counting; the other lists evil values from 1 to 10.
Live preview
Shows binary, how many ones, even-or-odd reasoning, and the evil vs odious verdict.
Interview polish
Mentions 0, nonnegative definitions, and optional BitOperations.PopCount on modern .NET.
Prerequisites
Comfortable with small C# programs, loops, and reading tiny binary examples like 1011.
- C# basics:
using System;,class Program,Main, string interpolation. - Operators
&,>>, and remainder%for parity. - Optional: casting nonnegative
inttouintfor bitwise walks.
What is an evil number?
A nonnegative integer n is evil when its binary representation contains an even number of 1 digits. If that count is odd, mathematicians say n is odious.
This is not about “good” or “bad” numbers — only about counting ones in base 2. Do not mix it up with “even” in decimal.
Hamming weight (population count)
Expand n in base 2 as n = ∑ bi 2i where each bi is 0 or 1. The sum of those bits s2(n) = ∑ bi is the Hamming weight. Then n is evil exactly when s2(n) is even.
1515 = 8 + 4 + 2 + 1, binary 1111, so s2(15) = 4 — four is even, hence evil.
Quick examples
- Binary
111— three ones
Pattern: flipping one bit toggles odd/even population count, so neighbours on the number line do not always share the same label.
Live preview
Nonnegative integers inside JavaScript’s safe range. You get binary, a plain count of ones, and why “evil” follows from even parity.
Algorithm
Goal: given nonnegative n, decide whether the number of 1-bits in binary is even.
Population count
Either peel the lowest bit with n & 1 and shift (uint recommended), or halve with n % 2 and n / 2, or scan a binary string.
Parity check
Evil means count % 2 == 0. Enumerating a range repeats the same test per index.
📜 Pseudocode
function popcount(n): // n >= 0
c ← 0
while n > 0:
c ← c + (n mod 2)
n ← floor(n / 2)
return c
function isEvil(n):
return (popcount(n) mod 2) = 0 Single value with bitwise counting
CountSetBits walks bits on a uint cast so shifts behave predictably. IsEvilNumber rejects negatives because the textbook definition uses nonnegative integers only.
using System;
class Program
{
static int CountSetBits(uint n)
{
int count = 0;
while (n != 0)
{
count += (int)(n & 1);
n >>= 1;
}
return count;
}
static bool IsEvilNumber(int number)
{
if (number < 0)
return false;
int setBitsCount = CountSetBits((uint)number);
return setBitsCount % 2 == 0;
}
static void Main()
{
int number = 15;
if (IsEvilNumber(number))
Console.WriteLine($"{number} is an evil number.");
else
Console.WriteLine($"{number} is not an evil number.");
}
} Explanation
Each loop trip looks only at the rightmost bit, adds 0 or 1, then shifts everything right.
count += (int)(n & 1);Mask. n & 1 is 1 when the lowest bit is set.
n >>= 1;Shift. Drops the bit you just counted so the next iteration sees the neighbor.
return setBitsCount % 2 == 0;Evil rule. Even popcount → evil; odd → odious.
Evil numbers from 1 to 10 (binary string)
Uses Convert.ToString(num, 2) so beginners can see 1 digits in a string before counting them — same evil list as the classic homework output.
using System;
class Program
{
static bool IsEvil(int num)
{
string binaryRepresentation = Convert.ToString(num, 2);
int countOnes = 0;
foreach (char digit in binaryRepresentation)
{
if (digit == '1')
countOnes++;
}
return countOnes % 2 == 0;
}
static void Main()
{
Console.WriteLine("Evil numbers in the range 1 to 10:");
for (int i = 1; i <= 10; i++)
{
if (IsEvil(i))
Console.Write(i + " ");
}
Console.WriteLine();
}
} Explanation
Base 2 conversion produces a text like "101"; counting '1' characters reproduces popcount for nonnegative inputs.
foreach (char digit in binaryRepresentation)Readable scan. Easy to debug because you can print the string beside the tally.
Optimization and APIs
BitOperations.PopCount (.NET 5+, System.Numerics): hardware-accelerated popcount when available — still remember the parity definition for interviews.
Kernighan trick. Repeatedly clearing the lowest set bit (n &= n - 1 on unsigned) counts iterations equal to popcount — handy when only the parity matters via XOR folding.
Interview: verbalize nonnegative definition, mention uint shifts, contrast evil vs decimal even.
❓ FAQ
🔄 Input / output examples
Swap the literal in Example 1 or widen the loop in Example 2. Reading from the console looks like int n = int.Parse(Console.ReadLine()); after validating input.
n | Binary | Popcount | Evil? |
|---|---|---|---|
0 | 0 | 0 | Yes |
3 | 11 | 2 | Yes |
7 | 111 | 3 | No (odious) |
15 | 1111 | 4 | Yes |
Edge cases and pitfalls
Most slips come from mixing definitions or forgetting how negatives look in binary strings.
n = 0
Popcount 0 is even — zero counts as evil under the usual convention.
Convert.ToString on negatives
For signed integers, two’s complement strings look huge and confusing for beginners — stick to n ≥ 0 or decide the rule up front.
Odious vs evil
Interviewers may ask you to print both labels or explain parity toggling under n XOR 1-style intuition.
Huge loops
Building strings per value in a giant range costs allocations — bitwise popcount is leaner at scale.
⏱️ Time and space complexity
| Operation | Time (one n) | Extra space |
|---|---|---|
| Bitwise popcount | O(log n) bits | O(1) |
| String conversion + scan | O(log n) | O(log n) for the string |
Range [1, U] | O(U log U) naive chain | depends on method |
BitOperations.PopCount still reflects bit-width work but hides the inner loop inside the runtime.
Summary
- Definition: evil = even popcount in binary; otherwise odious.
- Code paths: bitwise
uintloop vs binary string — both pair with% 2on the count. - Watch-outs: nonnegative convention; string tricks on negatives; optional hardware popcount.
The complementary class is odious numbers: nonnegative integers whose binary form has an odd number of 1 bits. The words “evil” and “odious” are playful math labels — they describe bit patterns, not character.
8 people found this page helpful
