TrailingZeros (Trailing zeros v1.0.0)

A utility module for counting trailing zeros in the binary representation of integers.

This module provides efficient algorithms to count the number of consecutive zeros at the end of a number's binary representation. Trailing zeros are significant in various computational contexts, including:

  • Bit manipulation: Understanding the structure of binary numbers
  • Performance optimization: Some algorithms can be optimized based on trailing zero count
  • Mathematical analysis: Useful in number theory and discrete mathematics
  • Memory alignment: Important in low-level programming and system design

Examples

iex> TrailingZeros.of(0)
0

iex> TrailingZeros.of(8)  # 8 = 1000 in binary
3

iex> TrailingZeros.of(12) # 12 = 1100 in binary
2

iex> TrailingZeros.of(7)  # 7 = 111 in binary
0

Algorithm

The implementation uses an efficient bit manipulation approach:

  1. Base case: Return 0 for input 0
  2. Recursive counting: Use bitwise operations to check the least significant bit
  3. Bit shifting: Right-shift the number to examine the next bit
  4. Accumulation: Count consecutive zeros until a 1 is encountered

The algorithm has O(log n) time complexity where n is the input number.

Performance

  • Time Complexity: O(log n) - proportional to the number of bits
  • Space Complexity: O(1) - constant space usage
  • Bitwise Operations: Uses efficient Bitwise.band/2 and Bitwise.bsr/2

Use Cases

  • Power of 2 detection: Numbers with n trailing zeros are divisible by 2^n
  • Binary number analysis: Understanding the structure of binary representations
  • Algorithm optimization: Some divide-and-conquer algorithms benefit from this information
  • Memory alignment: Important for understanding data structure alignment requirements

Summary

Functions

Counts the number of trailing zeros in the binary representation of a non-negative integer.

Functions

of(x)

@spec of(non_neg_integer()) :: non_neg_integer()

Counts the number of trailing zeros in the binary representation of a non-negative integer.

Returns the count of consecutive zeros at the end of the number's binary representation. For example, the binary representation of 8 is 1000, which has 3 trailing zeros.

Parameters

  • n - A non-negative integer to analyze

Returns

  • non_neg_integer() - The number of trailing zeros in the binary representation

Examples

iex> TrailingZeros.of(0)
0

iex> TrailingZeros.of(1)  # 1 = 1 in binary
0

iex> TrailingZeros.of(2)  # 2 = 10 in binary
1

iex> TrailingZeros.of(4)  # 4 = 100 in binary
2

iex> TrailingZeros.of(8)  # 8 = 1000 in binary
3

iex> TrailingZeros.of(12) # 12 = 1100 in binary
2

iex> TrailingZeros.of(16) # 16 = 10000 in binary
4

iex> TrailingZeros.of(1024) # 1024 = 10000000000 in binary
10

Edge Cases

iex> TrailingZeros.of(0)  # Zero has no trailing zeros
0

iex> TrailingZeros.of(255) # 255 = 11111111 in binary
0

iex> TrailingZeros.of(256) # 256 = 100000000 in binary
8

Mathematical Properties

  • For any number n, if TrailingZeros.of(n) = k, then n is divisible by 2^k
  • Powers of 2 have trailing zero counts equal to their exponent
  • Odd numbers always have 0 trailing zeros
  • The maximum trailing zeros for a 32-bit integer is 31 (for 0)

Algorithm Details

The function uses a recursive approach with bitwise operations:

  1. Base case: Returns 0 for input 0
  2. Recursive step:
    • Check if the least significant bit is 1 using Bitwise.band(x, 1)
    • If 1 is found, return the accumulated count
    • If 0 is found, right-shift by 1 and increment the accumulator
  3. Termination: Guaranteed to terminate as the number decreases with each shift

Performance Characteristics

  • Time Complexity: O(log n) - proportional to the number of bits in the input
  • Space Complexity: O(1) - constant space usage (tail-recursive)
  • Bitwise Operations: Uses efficient bitwise AND and right shift operations