|
| 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