forked from TheAlgorithms/Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfinding_kth_root.py
82 lines (65 loc) · 2.06 KB
/
finding_kth_root.py
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
"""
Finding the real root of a given degree of a given number
rounding to the nearest given number of decimal places without using ** or pow()
[Problem link]
https://www.geeksforgeeks.org/calculating-n-th-real-root-using-binary-search/
Input:
- number: 3
- deg: 2
- decimal_place: 5
Output:
- 1.73205
"""
def finding_kth_root(number: float, deg: int, decimal_place: int) -> float:
"""
Implementing binary search to find the kth root of a number.
Negative numbers are treated the same way as positive numbers,
with the minus sign added at the end.
>>> finding_kth_root(3, 2, 5)
1.73205
>>> finding_kth_root(122.683, 10, 7)
1.6176272
>>> finding_kth_root(5, 1, 3)
5.0
>>> finding_kth_root(0, 2, 2)
0.0
>>> finding_kth_root(125.7, 2, 0)
11.0
>>> finding_kth_root(-123, 5, 3)
-2.618
>>> finding_kth_root(-123, 4, 3)
Traceback (most recent call last):
...
ValueError: Cannot calculate real root of an even degree of a negative number.
>>> finding_kth_root(123, -1, 3)
Traceback (most recent call last):
...
ValueError: Degree of the root must be at least 1.
"""
if deg < 1:
raise ValueError("Degree of the root must be at least 1.")
if deg % 2 == 0 and number < 0:
raise ValueError(
"Cannot calculate real root of an even degree of a negative number."
)
hi, lo = number, 0.0
if number < 0:
hi = -number
error = 1.0
for _i in range(decimal_place + 1):
error /= 10
while hi - lo >= error: # Precision is not reached, continue looping
mid = (hi + lo) / 2
product = 1.0
for _i in range(deg):
product *= mid
if product > abs(number): # Overestimation, higher bound decreases to mid
hi = mid
else: # Underestimation, lower bound increases to mid
lo = mid
if number < 0:
return -round(lo, decimal_place)
return round(lo, decimal_place)
if __name__ == "__main__":
import doctest
doctest.testmod()