Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions maths/repunit_theorem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
Utilities related to repunits and a classical repunit divisibility theorem.

A repunit of length ``k`` is the number made of ``k`` ones:
``R_k = 11...1``.

For every positive integer ``n`` with ``gcd(n, 10) = 1``,
there exists a repunit ``R_k`` divisible by ``n``.
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module docstring introduces the repunit theorem but doesn’t include any reference URL. New algorithm modules in this repo typically include at least one Wikipedia (or similar) link; please add a reference (e.g., Repunit, multiplicative order, or the repunit divisibility theorem) to satisfy the project’s documentation expectations.

Suggested change
there exists a repunit ``R_k`` divisible by ``n``.
there exists a repunit ``R_k`` divisible by ``n``.
References:
- https://en.wikipedia.org/wiki/Repunit
- https://en.wikipedia.org/wiki/Multiplicative_order

Copilot uses AI. Check for mistakes.
"""

from math import gcd


def has_repunit_multiple(divisor: int) -> bool:
"""
Check whether a divisor admits a repunit multiple.

>>> has_repunit_multiple(7)
True
>>> has_repunit_multiple(13)
True
>>> has_repunit_multiple(2)
False
>>> has_repunit_multiple(25)
False
"""
if divisor <= 0:
raise ValueError("divisor must be a positive integer")
return gcd(divisor, 10) == 1


def least_repunit_length(divisor: int) -> int:
"""
Return the smallest length ``k`` such that repunit ``R_k`` is divisible by divisor.

Uses modular arithmetic to avoid constructing huge integers.

>>> least_repunit_length(3)
3
>>> least_repunit_length(7)
6
>>> least_repunit_length(41)
5
"""
if divisor <= 0:
raise ValueError("divisor must be a positive integer")
if not has_repunit_multiple(divisor):
raise ValueError("divisor must be coprime to 10")

remainder = 0
for length in range(1, divisor + 1):
remainder = (remainder * 10 + 1) % divisor
if remainder == 0:
return length

# Unreachable when gcd(divisor, 10) == 1 (pigeonhole principle theorem).
raise ArithmeticError("no repunit length found for divisor")


if __name__ == "__main__":
import doctest

doctest.testmod()
Loading