forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathproth_number.py
More file actions
125 lines (107 loc) · 3.21 KB
/
proth_number.py
File metadata and controls
125 lines (107 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""
Calculate the nth Proth number
Source:
https://handwiki.org/wiki/Proth_number
"""
import math
def proth(number: int) -> int:
"""
:param number: nth number to calculate in the sequence
:return: the nth number in Proth number
Note: indexing starts at 1 i.e. proth(1) gives the first Proth number of 3
>>> proth(6)
25
>>> proth(0)
Traceback (most recent call last):
...
ValueError: Input value of [number=0] must be > 0
>>> proth(-1)
Traceback (most recent call last):
...
ValueError: Input value of [number=-1] must be > 0
>>> proth(6.0)
Traceback (most recent call last):
...
TypeError: Input value of [number=6.0] must be an integer
"""
if not isinstance(number, int):
msg = f"Input value of [number={number}] must be an integer"
raise TypeError(msg)
if number < 1:
msg = f"Input value of [number={number}] must be > 0"
raise ValueError(msg)
elif number == 1:
return 3
elif number == 2:
return 5
else:
"""
+1 for binary starting at 0 i.e. 2^0, 2^1, etc.
+1 to start the sequence at the 3rd Proth number
Hence, we have a +2 in the below statement
"""
block_index = int(math.log(number // 3, 2)) + 2
proth_list = [3, 5]
proth_index = 2
increment = 3
for block in range(1, block_index):
for _ in range(increment):
proth_list.append(2 ** (block + 1) + proth_list[proth_index - 1])
proth_index += 1
increment *= 2
return proth_list[number - 1]
def is_proth_number(number: int) -> bool:
"""
:param number: positive integer number
:return: true if number is a Proth number, false otherwise
>>> is_proth_number(1)
False
>>> is_proth_number(2)
False
>>> is_proth_number(3)
True
>>> is_proth_number(4)
False
>>> is_proth_number(5)
True
>>> is_proth_number(34)
False
>>> is_proth_number(-1)
Traceback (most recent call last):
...
ValueError: Input value of [number=-1] must be > 0
>>> is_proth_number(6.0)
Traceback (most recent call last):
...
TypeError: Input value of [number=6.0] must be an integer
"""
if not isinstance(number, int):
message = f"Input value of [{number=}] must be an integer"
raise TypeError(message)
if number <= 0:
message = f"Input value of [{number=}] must be > 0"
raise ValueError(message)
if number == 1:
return False
number -= 1
n = 0
while number % 2 == 0:
n += 1
number //= 2
return number < 2**n
if __name__ == "__main__":
import doctest
doctest.testmod()
for number in range(11):
value = 0
try:
value = proth(number)
except ValueError:
print(f"ValueError: there is no {number}th Proth number")
continue
print(f"The {number}th Proth number: {value}")
for number in [1, 2, 3, 4, 5, 9, 13, 49, 57, 193, 241, 163, 201]:
if is_proth_number(number):
print(f"{number} is a Proth number")
else:
print(f"{number} is not a Proth number")