Skip to content

Commit 9cee50e

Browse files
Dario-DClarymak
andauthored
feat(curriculum): add bisection method lab (freeCodeCamp#61253)
Co-authored-by: Hillary Nyakundi <[email protected]>
1 parent ae086af commit 9cee50e

File tree

4 files changed

+379
-2
lines changed

4 files changed

+379
-2
lines changed

client/i18n/locales/english/intro.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4420,8 +4420,10 @@
44204420
]
44214421
},
44224422
"lab-bisection-method": {
4423-
"title": "Build a Bisection Method",
4424-
"intro": [""]
4423+
"title": "Implement the Bisection Method",
4424+
"intro": [
4425+
"In this lab, you will implement the bisection method to find the square root of a number."
4426+
]
44254427
},
44264428
"workshop-merge-sort": {
44274429
"title": "Implement the Merge Sort Algorithm",
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
title: Introduction to the Implement the Bisection Method
3+
block: lab-bisection-method
4+
superBlock: full-stack-developer
5+
---
6+
7+
## Introduction to the Implement the Bisection Method
8+
9+
In this lab, you will implement the bisection method to find the square root of a number.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "Implement the Bisection Method",
3+
"isUpcomingChange": true,
4+
"dashedName": "lab-bisection-method",
5+
"superBlock": "full-stack-developer",
6+
"blockLayout": "link",
7+
"blockType": "lab",
8+
"helpCategory": "Python",
9+
"challengeOrder": [{ "id": "686ccc2c8b967e17ab18d593", "title": "Implement the Bisection Method" }],
10+
"usesMultifileEditor": true
11+
}
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
---
2+
id: 686ccc2c8b967e17ab18d593
3+
title: Implement the Bisection Method
4+
challengeType: 27
5+
dashedName: implement-the-bisection-method
6+
---
7+
8+
# --description--
9+
10+
The bisection method, also known as the binary search method, uses a binary search to find the roots of a real-valued function. It works by narrowing down an interval where the square root lies until it converges to a value within a specified tolerance.
11+
12+
For example, if the tolerance is `0.01`, the bisection method will keep halving the interval until the difference between the upper and lower bounds is less than or equal to `0.01`.
13+
14+
In this lab, you will implement a function that uses the bisection method to find the square root of a number.
15+
16+
**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.
17+
18+
**User stories**
19+
20+
1. You should define a function named `square_root_bisection` with three parameters:
21+
- The number for which you want to find the square root.
22+
- The tolerance being the acceptable error margin for the result. You should set a default tolerance value.
23+
- The maximum number of iterations to perform. You should set a default number of iterations.
24+
25+
1. The `square_root_bisection` function should:
26+
- Raise a `ValueError` with the message `Square root of negative number is not defined in real numbers` if the number passed to the function is negative.
27+
- For numbers `0` and `1`, print the message: `The square root of [number] is [number]` and return the number itself as the square root.
28+
- For any other positive number, print the approximate square root with the message: `The square root of [square_target] is approximately [root]` and return the computed root value.
29+
- If no value meets the tolerance condition, print a failure message: `Failed to converge within the [maximum] iterations` and return `None`.
30+
31+
**Note**: You cannot import any module for this lab.
32+
33+
# --hints--
34+
35+
You should not import any module.
36+
37+
```js
38+
({ test: () => assert(runPython(`len(_Node(_code).find_imports()) == 0`)) })
39+
```
40+
41+
You should have a function named `square_root_bisection`.
42+
43+
```js
44+
({ test: () => assert(runPython(`_Node(_code).has_function("square_root_bisection")`)) })
45+
```
46+
47+
Your `square_root_bisection` function should have three parameters.
48+
49+
```js
50+
({ test: () => runPython(`
51+
import inspect
52+
sig = inspect.signature(square_root_bisection)
53+
assert len(sig.parameters) == 3
54+
`) })
55+
```
56+
57+
You should set a default value for the tolerance and the maximum number of iterations.
58+
59+
```js
60+
({ test: () => runPython(`
61+
try:
62+
import inspect
63+
sig = inspect.signature(square_root_bisection)
64+
assert len(sig.parameters) == 3
65+
square_root_bisection(4)
66+
except TypeError:
67+
assert False
68+
`) })
69+
```
70+
71+
Your `square_root_bisection` function should raise a `ValueError` with the message `Square root of negative number is not defined in real numbers` when the number passed to the function is negative.
72+
73+
```js
74+
({ test: () => runPython(`
75+
try:
76+
square_root_bisection(-6)
77+
except ValueError as e:
78+
assert str(e) == "Square root of negative number is not defined in real numbers"
79+
else:
80+
assert False
81+
`) })
82+
```
83+
84+
`square_root_bisection(0)` should return `0`.
85+
86+
```js
87+
({ test: () => runPython(`assert square_root_bisection(0) == 0`) })
88+
```
89+
90+
`square_root_bisection(0)` should print `The square root of 0 is 0`.
91+
92+
```js
93+
({ test: () => runPython(`
94+
built_in_print = print
95+
_out = []
96+
97+
def custom_print(*args, **kwargs):
98+
call_args = [arg for arg in args]
99+
_out.extend(call_args)
100+
101+
print = custom_print
102+
square_root_bisection(0)
103+
assert "The square root of 0 is 0" in _out
104+
`) })
105+
```
106+
107+
`square_root_bisection(0.001, 1e-7, 50)` should return a number between `0.03162267660168379` and `0.031622876601683794`.
108+
109+
```js
110+
({ test: () => runPython(`assert 0.03162267660168379 <= square_root_bisection(0.001, 1e-7, 50) <= 0.031622876601683794`) })
111+
```
112+
113+
`square_root_bisection(0.001, 1e-7, 50)` should print `The square root of 0.001 is approximately X`, where `X` is a number between `0.03162267660168379` and `0.031622876601683794`.
114+
115+
```js
116+
({ test: () => runPython(`
117+
built_in_print = print
118+
_out = []
119+
120+
def custom_print(*args, **kwargs):
121+
call_args = [arg for arg in args]
122+
_out.extend(call_args)
123+
124+
print = custom_print
125+
126+
_root = square_root_bisection(0.001, 1e-7, 50)
127+
128+
assert 0.03162267660168379 <= _root <= 0.031622876601683794
129+
assert f"The square root of 0.001 is approximately {_root}" in _out
130+
`) })
131+
```
132+
133+
`square_root_bisection(0.25, 1e-7, 50)` should return a number between `0.4999999` and `0.5000001`.
134+
135+
```js
136+
({ test: () => runPython(`assert 0.4999999 <= square_root_bisection(0.25, 1e-7, 50) <= 0.5000001`) })
137+
```
138+
139+
`square_root_bisection(0.25, 1e-7, 50)` should print `The square root of 0.25 is approximately X`, where `X` is a number between `0.4999999` and `0.5000001`.
140+
141+
```js
142+
({ test: () => runPython(`
143+
built_in_print = print
144+
_out = []
145+
146+
def custom_print(*args, **kwargs):
147+
call_args = [arg for arg in args]
148+
_out.extend(call_args)
149+
150+
print = custom_print
151+
152+
_root = square_root_bisection(0.25, 1e-7, 50)
153+
154+
assert 0.4999999 <= _root <= 0.5000001
155+
assert f"The square root of 0.25 is approximately {_root}" in _out
156+
`) })
157+
```
158+
159+
`square_root_bisection(1)` should return `1`.
160+
161+
```js
162+
({ test: () => runPython(`assert square_root_bisection(1) == 1`) })
163+
```
164+
165+
`square_root_bisection(1)` should print `The square root of 1 is 1`.
166+
167+
```js
168+
({ test: () => runPython(`
169+
built_in_print = print
170+
_out = []
171+
172+
def custom_print(*args, **kwargs):
173+
call_args = [arg for arg in args]
174+
_out.extend(call_args)
175+
176+
print = custom_print
177+
square_root_bisection(1)
178+
assert "The square root of 1 is 1" in _out
179+
`) })
180+
```
181+
182+
`square_root_bisection(81, 1e-3, 50)` should return a number between `8.999` and `9.001`.
183+
184+
```js
185+
({ test: () => runPython(`assert 8.999 <= square_root_bisection(81, 1e-3, 50) <= 9.001`) })
186+
```
187+
188+
`square_root_bisection(81, 1e-3, 50)` should print `The square root of 81 is approximately X`, where `X` is a number between `8.999` and `9.001`.
189+
190+
```js
191+
({ test: () => runPython(`
192+
built_in_print = print
193+
_out = []
194+
195+
def custom_print(*args, **kwargs):
196+
call_args = [arg for arg in args]
197+
_out.extend(call_args)
198+
199+
print = custom_print
200+
201+
_root = square_root_bisection(81, 1e-3, 50)
202+
203+
assert 8.999 <= _root <= 9.001
204+
assert f"The square root of 81 is approximately {_root}" in _out
205+
`) })
206+
```
207+
208+
`square_root_bisection(225, 1e-3, 100)` should return a number between `14.999` and `15.001`.
209+
210+
```js
211+
({ test: () => runPython(`assert 14.999 <= square_root_bisection(225, 1e-3, 100) <= 15.001`) })
212+
```
213+
214+
`square_root_bisection(225, 1e-3, 100)` should print `The square root of 225 is approximately X`, where `X` is a number between `14.999` and `15.001`.
215+
216+
```js
217+
({ test: () => runPython(`
218+
built_in_print = print
219+
_out = []
220+
221+
def custom_print(*args, **kwargs):
222+
call_args = [arg for arg in args]
223+
_out.extend(call_args)
224+
225+
print = custom_print
226+
227+
_root = square_root_bisection(225, 1e-3, 100)
228+
229+
assert 14.999 <= _root <= 15.001
230+
assert f"The square root of 225 is approximately {_root}" in _out
231+
`) })
232+
```
233+
234+
`square_root_bisection(225, 1e-5, 100)` should return a number between `14.99999` and `15.00001`.
235+
236+
```js
237+
({ test: () => runPython(`assert 14.99999 <= square_root_bisection(225, 1e-5, 100) <= 15.00001`) })
238+
```
239+
240+
`square_root_bisection(225, 1e-5, 100)` should print `The square root of 225 is approximately X`, where `X` is a number between `14.99999` and `15.00001`.
241+
242+
```js
243+
({ test: () => runPython(`
244+
built_in_print = print
245+
_out = []
246+
247+
def custom_print(*args, **kwargs):
248+
call_args = [arg for arg in args]
249+
_out.extend(call_args)
250+
251+
print = custom_print
252+
253+
_root = square_root_bisection(225, 1e-5, 100)
254+
255+
assert 14.99999 <= _root <= 15.00001
256+
assert f"The square root of 225 is approximately {_root}" in _out
257+
`) })
258+
```
259+
260+
`square_root_bisection(225, 1e-7, 100)` should return a number between `14.9999999` and `15.0000001`.
261+
262+
```js
263+
({ test: () => runPython(`assert 14.9999999 <= square_root_bisection(225, 1e-7, 100) <= 15.0000001`) })
264+
```
265+
266+
`square_root_bisection(225, 1e-7, 100)` should print `The square root of 225 is approximately X`, where `X` is a number between `14.9999999` and `15.0000001`.
267+
268+
```js
269+
({ test: () => runPython(`
270+
built_in_print = print
271+
_out = []
272+
273+
def custom_print(*args, **kwargs):
274+
call_args = [arg for arg in args]
275+
_out.extend(call_args)
276+
277+
print = custom_print
278+
279+
_root = square_root_bisection(225, 1e-7, 100)
280+
281+
assert 14.9999999 <= _root <= 15.0000001
282+
assert f"The square root of 225 is approximately {_root}" in _out
283+
`) })
284+
```
285+
286+
`square_root_bisection(225, 1e-7, 10)` should return `None`.
287+
288+
```js
289+
({ test: () => runPython(`assert square_root_bisection(225, 1e-7, 10) is None`) })
290+
```
291+
292+
`square_root_bisection(225, 1e-7, 10)` should print `Failed to converge within 10 iterations`.
293+
294+
```js
295+
({ test: () => runPython(`
296+
built_in_print = print
297+
_out = []
298+
299+
def custom_print(*args, **kwargs):
300+
call_args = [arg for arg in args]
301+
_out.extend(call_args)
302+
303+
print = custom_print
304+
square_root_bisection(225, 1e-7, 10)
305+
assert "Failed to converge within 10 iterations" in _out
306+
`) })
307+
```
308+
309+
# --seed--
310+
311+
## --seed-contents--
312+
313+
```py
314+
315+
```
316+
317+
# --solutions--
318+
319+
```py
320+
def square_root_bisection(square_target, tolerance=1e-7, max_iterations=100):
321+
if square_target < 0:
322+
raise ValueError('Square root of negative number is not defined in real numbers')
323+
if square_target == 1:
324+
root = 1
325+
print(f'The square root of {square_target} is 1')
326+
elif square_target == 0:
327+
root = 0
328+
print(f'The square root of {square_target} is 0')
329+
330+
else:
331+
low = square_target if square_target < 1 else 1
332+
high = 1 if square_target < 1 else square_target
333+
root = None
334+
335+
for _ in range(max_iterations):
336+
mid = (low + high) / 2
337+
square_mid = mid**2
338+
339+
if high - low <= tolerance:
340+
root = mid
341+
break
342+
343+
elif square_mid < square_target:
344+
low = mid
345+
else:
346+
high = mid
347+
348+
if root is None:
349+
print(f"Failed to converge within {max_iterations} iterations")
350+
351+
else:
352+
print(f'The square root of {square_target} is approximately {root}')
353+
354+
return root
355+
```

0 commit comments

Comments
 (0)