Implement a popular pi-digit-extraction algorithm known as the Bailey-Borwein-Plouffe (BBP) formula to calculate the nth hex digit of pi. Wikipedia page: https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula @param digit_position: a positive integer repres
(digit_position: int, precision: int = 1000)
| 1 | def bailey_borwein_plouffe(digit_position: int, precision: int = 1000) -> str: |
| 2 | """ |
| 3 | Implement a popular pi-digit-extraction algorithm known as the |
| 4 | Bailey-Borwein-Plouffe (BBP) formula to calculate the nth hex digit of pi. |
| 5 | Wikipedia page: |
| 6 | https://en.wikipedia.org/wiki/Bailey%E2%80%93Borwein%E2%80%93Plouffe_formula |
| 7 | @param digit_position: a positive integer representing the position of the digit to |
| 8 | extract. |
| 9 | The digit immediately after the decimal point is located at position 1. |
| 10 | @param precision: number of terms in the second summation to calculate. |
| 11 | A higher number reduces the chance of an error but increases the runtime. |
| 12 | @return: a hexadecimal digit representing the digit at the nth position |
| 13 | in pi's decimal expansion. |
| 14 | |
| 15 | >>> "".join(bailey_borwein_plouffe(i) for i in range(1, 11)) |
| 16 | '243f6a8885' |
| 17 | >>> bailey_borwein_plouffe(5, 10000) |
| 18 | '6' |
| 19 | >>> bailey_borwein_plouffe(-10) |
| 20 | Traceback (most recent call last): |
| 21 | ... |
| 22 | ValueError: Digit position must be a positive integer |
| 23 | >>> bailey_borwein_plouffe(0) |
| 24 | Traceback (most recent call last): |
| 25 | ... |
| 26 | ValueError: Digit position must be a positive integer |
| 27 | >>> bailey_borwein_plouffe(1.7) |
| 28 | Traceback (most recent call last): |
| 29 | ... |
| 30 | ValueError: Digit position must be a positive integer |
| 31 | >>> bailey_borwein_plouffe(2, -10) |
| 32 | Traceback (most recent call last): |
| 33 | ... |
| 34 | ValueError: Precision must be a nonnegative integer |
| 35 | >>> bailey_borwein_plouffe(2, 1.6) |
| 36 | Traceback (most recent call last): |
| 37 | ... |
| 38 | ValueError: Precision must be a nonnegative integer |
| 39 | """ |
| 40 | if (not isinstance(digit_position, int)) or (digit_position <= 0): |
| 41 | raise ValueError("Digit position must be a positive integer") |
| 42 | elif (not isinstance(precision, int)) or (precision < 0): |
| 43 | raise ValueError("Precision must be a nonnegative integer") |
| 44 | |
| 45 | # compute an approximation of (16 ** (n - 1)) * pi whose fractional part is mostly |
| 46 | # accurate |
| 47 | sum_result = ( |
| 48 | 4 * _subsum(digit_position, 1, precision) |
| 49 | - 2 * _subsum(digit_position, 4, precision) |
| 50 | - _subsum(digit_position, 5, precision) |
| 51 | - _subsum(digit_position, 6, precision) |
| 52 | ) |
| 53 | |
| 54 | # return the first hex digit of the fractional part of the result |
| 55 | return hex(int((sum_result % 1) * 16))[2:] |
| 56 | |
| 57 | |
| 58 | def _subsum( |