Last active
October 14, 2024 03:56
-
-
Save psiborg/1c25f74dfbf4b2087de5fa3245f290ef to your computer and use it in GitHub Desktop.
Calculate Pi in parallel using Gauss-Legendre, Chudnovsky, and Bailey-Borwein-Plouffe (BBP) algorithms
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| # ./pi_calc.py --digits 5000 | |
| import decimal | |
| from decimal import Decimal | |
| from math import factorial | |
| import multiprocessing | |
| import time | |
| import argparse | |
| # Set precision for Decimal calculations | |
| decimal.getcontext().prec = 1020 # Adjust for extra precision | |
| # Function to calculate Pi using Gauss-Legendre Algorithm | |
| def gauss_legendre(precision): | |
| decimal.getcontext().prec = precision + 2 # extra digits for rounding | |
| a = Decimal(1) | |
| b = Decimal(1) / Decimal(2).sqrt() | |
| t = Decimal(0.25) | |
| p = Decimal(1) | |
| for _ in range(int(precision**0.5)): | |
| a_next = (a + b) / 2 | |
| b = (a * b).sqrt() | |
| t -= p * (a - a_next) ** 2 | |
| a = a_next | |
| p *= 2 | |
| pi = (a + b) ** 2 / (4 * t) | |
| return +pi # unary plus applies the precision | |
| # Function to calculate Pi using Chudnovsky Algorithm | |
| def chudnovsky(precision): | |
| decimal.getcontext().prec = precision + 2 # extra digits for rounding | |
| C = 426880 * Decimal(10005).sqrt() | |
| K = 6 | |
| M = 1 | |
| X = 1 | |
| L = 13591409 | |
| S = L | |
| for k in range(1, precision): | |
| M = (K ** 3 - 16 * K) * M // k ** 3 | |
| L += 545140134 | |
| X *= -262537412640768000 | |
| S += Decimal(M * L) / X | |
| K += 12 | |
| pi = C / S | |
| return +pi # unary plus applies the precision | |
| # Function to calculate Pi using Bailey-Borwein-Plouffe (BBP) Algorithm | |
| def bbp(precision): | |
| decimal.getcontext().prec = precision + 2 # extra digits for rounding | |
| pi = Decimal(0) | |
| for k in range(precision): | |
| pi += (Decimal(1) / (16 ** k)) * ( | |
| Decimal(4) / (8 * k + 1) - | |
| Decimal(2) / (8 * k + 4) - | |
| Decimal(1) / (8 * k + 5) - | |
| Decimal(1) / (8 * k + 6) | |
| ) | |
| return +pi # unary plus applies the precision | |
| # Wrapper for multiprocessing | |
| def parallel_calculate(algorithm, precision, label): | |
| start = time.time() | |
| pi = algorithm(precision) | |
| duration = time.time() - start | |
| return label, pi, duration | |
| def display_result(result): | |
| label, pi, duration = result | |
| print(f"\n{label:<15} completed in {duration:<.4f} seconds.") | |
| print(f"First 100 digits: {str(pi)[:100]}...") | |
| # Function to find the first mismatch position between two strings | |
| def find_first_mismatch(str1, str2): | |
| mismatch_index = None | |
| for i in range(len(str1)): | |
| if str1[i] != str2[i]: | |
| mismatch_index = i | |
| break | |
| return mismatch_index | |
| def main(): | |
| # Argument parsing for command line arguments | |
| parser = argparse.ArgumentParser(description="Calculate Pi to a specified number of digits.") | |
| parser.add_argument('-d', '--digits', type=int, default=1000, help="Number of digits of Pi to calculate (default: 1000)") | |
| args = parser.parse_args() | |
| precision = args.digits | |
| print(f"Calculating Pi to {precision} digits...\n") | |
| algorithms = [ | |
| (gauss_legendre, precision, "Gauss-Legendre"), | |
| (chudnovsky, precision, "Chudnovsky"), | |
| (bbp, precision, "BBP") | |
| ] | |
| pool = multiprocessing.Pool(processes=3) | |
| # Trigger each calculation in parallel with real-time updates | |
| results = [] | |
| for algorithm, prec, label in algorithms: | |
| async_result = pool.apply_async(parallel_calculate, (algorithm, prec, label), callback=display_result) | |
| results.append(async_result) | |
| # Ensure all results are gathered and displayed | |
| for result in results: | |
| result.wait() | |
| pool.close() | |
| pool.join() | |
| # Final Summary using BBP as the reference for comparison | |
| print("\nSummary of Results:") | |
| print(f"{'Algorithm':<15} {'Time (s)':<10} {'Match to BBP':<12} {'First Mismatch (if any)'}") | |
| print("-" * 60) | |
| # Use BBP as the base for comparison | |
| bbp_result = [res for res in results if res.get()[0] == "BBP"][0].get()[1] | |
| bbp_str = str(bbp_result) | |
| for result in results: | |
| label, pi, duration = result.get() | |
| if label != "BBP": | |
| pi_str = str(pi) | |
| if pi_str == bbp_str: | |
| match = "Yes" | |
| mismatch_info = "N/A" | |
| else: | |
| match = "No" | |
| mismatch_index = find_first_mismatch(pi_str, bbp_str) | |
| mismatch_info = f"Position {mismatch_index}" if mismatch_index is not None else "Unknown" | |
| else: | |
| match = "N/A" # BBP is the reference | |
| mismatch_info = "N/A" | |
| print(f"{label:<15} {duration:<10.4f} {match:<12} {mismatch_info}") | |
| if __name__ == "__main__": | |
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Calculating Pi to 1000 digits... | |
| Gauss-Legendre completed in 0.5167 seconds. | |
| First 100 digits: 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825... | |
| Chudnovsky completed in 0.0318 seconds. | |
| First 100 digits: 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825... | |
| BBP completed in 0.1429 seconds. | |
| First 100 digits: 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825... | |
| Summary of Results: | |
| Algorithm Time (s) Match to BBP First Mismatch (if any) | |
| ------------------------------------------------------------ | |
| Gauss-Legendre 0.5167 Yes N/A | |
| Chudnovsky 0.0318 Yes N/A | |
| BBP 0.1429 N/A N/A | |
| -OR- | |
| Summary of Results: | |
| Algorithm Time (s) Match to BBP First Mismatch (if any) | |
| ------------------------------------------------------------ | |
| Gauss-Legendre 0.5167 No Position 948 | |
| Chudnovsky 0.0318 Yes N/A | |
| BBP 0.1429 N/A N/A |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment