Skip to content

Commit 402610e

Browse files
committed
Add pentagonal number algorithm
1 parent 6c04620 commit 402610e

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
== Pentagonal Numbers ==
3+
A pentagonal number is a figurate number that represents a pentagon. The nth
4+
pentagonal number P(n) counts the dots in a pattern of nested pentagons that
5+
share a common corner, where the outermost pentagon has n dots on each side.
6+
7+
The nth pentagonal number is given by the formula:
8+
9+
P(n) = (3 * n * n - n) / 2
10+
11+
The sequence begins 1, 5, 12, 22, 35, 51, 70, ... for n = 1, 2, 3, ...
12+
13+
Reference: https://en.wikipedia.org/wiki/Pentagonal_number
14+
"""
15+
16+
from math import isqrt
17+
18+
19+
def is_pentagonal(number: int) -> bool:
20+
"""
21+
Return True if ``number`` is a pentagonal number, otherwise False.
22+
23+
A positive integer x is pentagonal if and only if (1 + sqrt(24x + 1)) / 6
24+
is a positive integer. This is the inverse of the pentagonal-number formula
25+
solved for n. The check is performed with integer arithmetic (math.isqrt)
26+
to avoid floating-point rounding errors for large inputs.
27+
28+
>>> is_pentagonal(1)
29+
True
30+
>>> is_pentagonal(5)
31+
True
32+
>>> is_pentagonal(12)
33+
True
34+
>>> is_pentagonal(35)
35+
True
36+
>>> is_pentagonal(2)
37+
False
38+
>>> is_pentagonal(10)
39+
False
40+
>>> is_pentagonal(0)
41+
False
42+
>>> is_pentagonal(-5)
43+
False
44+
"""
45+
if number < 1:
46+
return False
47+
discriminant = 24 * number + 1
48+
root = isqrt(discriminant)
49+
if root * root != discriminant:
50+
return False
51+
return (1 + root) % 6 == 0
52+
53+
54+
def pentagonal(position: int) -> int:
55+
"""
56+
Return the pentagonal number at the given 1-based ``position`` using the
57+
closed-form formula P(n) = (3 * n * n - n) / 2.
58+
59+
>>> pentagonal(1)
60+
1
61+
>>> pentagonal(2)
62+
5
63+
>>> pentagonal(3)
64+
12
65+
>>> pentagonal(10)
66+
145
67+
>>> pentagonal(0)
68+
Traceback (most recent call last):
69+
...
70+
ValueError: position must be a positive integer
71+
>>> pentagonal(-3)
72+
Traceback (most recent call last):
73+
...
74+
ValueError: position must be a positive integer
75+
>>> pentagonal(1.5)
76+
Traceback (most recent call last):
77+
...
78+
TypeError: position must be an integer
79+
"""
80+
if not isinstance(position, int):
81+
raise TypeError("position must be an integer")
82+
if position < 1:
83+
raise ValueError("position must be a positive integer")
84+
return (3 * position * position - position) // 2
85+
86+
87+
if __name__ == "__main__":
88+
import doctest
89+
90+
doctest.testmod()
91+
92+
print("The first 10 pentagonal numbers are:")
93+
print([pentagonal(n) for n in range(1, 11)])

0 commit comments

Comments
 (0)