.NET
BitArray
programming
C#
bit manipulation

Counting bits set in a .Net BitArray Class

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

BitArray is a compact way to store boolean flags, but it does not provide a built-in method that tells you how many bits are set to true. If you need that number, the usual choices are a direct loop over the bits or a faster block-based count using BitOperations.PopCount.

The direct loop is the simplest and easiest to maintain. The block-based version is useful when the bit array is large or counting happens often enough to matter in performance measurements.

Count Set Bits with a Simple Loop

For ordinary code, iterating through the bits is usually enough:

csharp
1using System;
2using System.Collections;
3
4static int CountSetBits(BitArray bits)
5{
6    int count = 0;
7
8    foreach (bool bit in bits)
9    {
10        if (bit)
11        {
12            count++;
13        }
14    }
15
16    return count;
17}
18
19var bits = new BitArray(new[] { true, false, true, true, false });
20Console.WriteLine(CountSetBits(bits));

This approach is clear, portable, and does not require you to care about how the bits are packed internally. If the code path is not hot, that simplicity is usually the right tradeoff.

Count Bits Faster with PopCount

If performance matters, copy the packed storage into integer blocks and count the 1 bits in each block:

csharp
1using System;
2using System.Collections;
3using System.Numerics;
4
5static int CountSetBitsFast(BitArray bits)
6{
7    int[] blocks = new int[(bits.Length + 31) / 32];
8    bits.CopyTo(blocks, 0);
9
10    int count = 0;
11    foreach (int block in blocks)
12    {
13        count += BitOperations.PopCount((uint)block);
14    }
15
16    return count;
17}

PopCount counts set bits in a numeric value, so this version processes 32 bits at a time instead of testing each bit individually in managed code. For large bit arrays, that can be a meaningful speedup.

Understand the Final Partial Block

When the BitArray length is not a multiple of 32, the last copied integer may contain unused high bits beyond the logical end of the array. In normal BitArray usage that is often harmless, but it is worth understanding if you mix BitArray with lower-level bit operations.

If you want to mask the final block explicitly, you can do this:

csharp
1static int MaskForLastBlock(int length)
2{
3    int usedBits = length % 32;
4    return usedBits == 0 ? -1 : (1 << usedBits) - 1;
5}

That detail only matters when you are working close to the storage representation. The simple loop does not have this concern at all.

Choose the Method for the Real Workload

A good rule is:

  • use the direct loop when clarity matters most
  • use block-based counting when profiling shows the count operation matters

It is easy to over-optimize this kind of code. If you count a small BitArray once in a while, the loop is perfectly fine. If you count large bit arrays repeatedly in a tight path, the extra code for PopCount can be justified.

Common Pitfalls

The biggest mistake is confusing Length with the number of set bits. Length tells you how many positions exist, not how many are true.

Another common issue is assuming BitArray already has a built-in popcount-style API. It does not.

It is also easy to optimize too early. A faster counting method only matters when the operation is actually part of a measured bottleneck.

Finally, remember that BitArray is mutable. If other code changes it, any previously computed count is immediately stale.

Summary

  • 'BitArray does not expose a built-in count of set bits.'
  • A foreach loop is the clearest solution for most code.
  • 'BitOperations.PopCount is a good optimization for larger packed bitsets.'
  • Be aware of the final partial block when counting copied storage.
  • Choose the simplest method that fits the actual performance needs.

Course illustration
Course illustration

All Rights Reserved.