Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/add initial commit #1

Merged
merged 6 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Python application test with GitHub Actions

on:
push:
pull_request:

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
python-version: [3.11]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r dev-requirements.txt
- name: Test with pytest
run: |
pytest
25 changes: 25 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -----------------------------------------------------------------------------
# The default Musicfox Pipfile.
#
# This should be customized per application requirements; uncomment or add
# those packages required. This should be used for datascience, web, and
# most other Python-based projects, replacing raw venv or anaconda usage.
# -----------------------------------------------------------------------------

[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"

[dev-packages]
ipython = "*"
black = "*"
pytest = "*"
pytest-cov = "*"
pynvim = "*"

[packages]
typer = {extras = ["all"], version = "*"}

[requires]
python_version = "3.11"
512 changes: 512 additions & 0 deletions Pipfile.lock

Large diffs are not rendered by default.

36 changes: 35 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,36 @@
# pi
Using the Gauss-Legendre Algorithm to calculate Pi

Using the Gauss-Legendre Algorithm to calculate Pi.

## Usage

```
Usage: pi.py [OPTIONS] COMMAND [ARGS]...

╭─ Options ─────────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy it │
│ or customize the installation. │
│ --help Show this message and exit. │
╰───────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ────────────────────────────────────────────────────────────────────────╮
│ calculate-pi Returns the correct value of Pi up to the given │
│ digits. │
│ calculate-pi-gauss-legendre This implements the Gauss-Legendre algorithm to │
│ calculate the value of Pi. Because it is memory │
│ intensive, practitioners typically do not implement │
│ this algorithm for actually calculating Pi. │
│ truncate-decimal Truncates a Decimal value to a specified number of │
│ decimal places. │
╰───────────────────────────────────────────────────────────────────────────────────╯
```

To calcualte Pi to 39 digits:

```bash
python pi.py calculate-pi 39
```

## Happy Pi Day 2024

[tincre.com](https://tincre.com) made this to represent Pi day 2024 (March 14th, 2024). This library is entirely inconsequential but we're happy to accept contributions.
38 changes: 38 additions & 0 deletions dev-requirements.txt

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions lock-dependencies.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
echo "Locking dependencies using Python $(python --version)."

echo "Generating requirements.txt..."
pipenv requirements --hash > requirements.txt
echo "Now generating dev-requirements.txt..."
pipenv requirements --dev --hash > dev-requirements.txt
echo "All dependencies generated with hashes. You should probably commit the changes."
echo "You may do so via the following command:"
echo "ga && gc ':heavy_plus_sign: <dependencyName> added'"
52 changes: 52 additions & 0 deletions pi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from decimal import Decimal, getcontext
import typer

app = typer.Typer(name="π")


@app.command()
def calculate_pi_gauss_legendre(digits: int):
"""
This implements the Gauss-Legendre algorithm to calculate the
value of Pi. Because it is memory intensive, practitioners typically
do not implement this algorithm for actually calculating Pi.

https://en.wikipedia.org/wiki/Gauss%E2%80%93Legendre_algorithm
"""
getcontext().prec = digits + 2

a = Decimal(1) # a_0
b = Decimal(1) / Decimal(2).sqrt() # b_0
t = Decimal(1) / Decimal(4) # t_0
p = Decimal(1) # p_0

for _ in range(digits):
a_next = (a + b) / 2
b = (a * b).sqrt()
t -= p * (a - a_next) ** 2
a = a_next
p *= 2

return (a + b) ** 2 / (4 * t)


@app.command()
def truncate_decimal(value, places: int):
"""Truncates a Decimal value to a specified number of decimal places."""
value_str = f"{value}"
dot_position = value_str.find(".")
return Decimal(
value_str[: dot_position + places + 1]
if dot_position != -1
else value_str
)


@app.command()
def calculate_pi(digits: int):
"""Returns the correct value of Pi up to the given digits."""
return truncate_decimal(calculate_pi_gauss_legendre(digits), digits)


if __name__ == "__main__":
app()
10 changes: 10 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-i https://pypi.org/simple
click==8.1.7 ; python_version >= '3.7' --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
colorama==0.4.6 --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
markdown-it-py==3.0.0 ; python_version >= '3.8' --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
mdurl==0.1.2 ; python_version >= '3.7' --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
pygments==2.17.2 ; python_version >= '3.7' --hash=sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c --hash=sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367
rich==13.7.1 --hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 --hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
shellingham==1.5.4 --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
typer[all]==0.9.0 --hash=sha256:50922fd79aea2f4751a8e0408ff10d2662bd0c8bbfa84755a699f3bada2978b2 --hash=sha256:5d96d986a21493606a358cae4461bd8cdf83cbf33a5aa950ae629ca3b51467ee
typing-extensions==4.10.0 ; python_version >= '3.8' --hash=sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475 --hash=sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb
49 changes: 49 additions & 0 deletions test_pi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from pi import calculate_pi_gauss_legendre, truncate_decimal, calculate_pi
from decimal import Decimal, getcontext
import math


def test_calculate_pi_gauss_legendre():
digits = 3
pi_approximation = calculate_pi_gauss_legendre(digits)
getcontext().prec = digits + 1
assert isinstance(pi_approximation, Decimal)
assert pi_approximation == Decimal(
"3.1416"
) # the last digit should be wrong


def test_truncate_decimal():
digits = 3
truncated = truncate_decimal(Decimal("1.1111"), digits)
assert len(f"{truncated}") == digits + 2 # for the decimal point and "1"


def test_calculate_pi():
digits = 3
pi_approximation = calculate_pi(digits)
assert (
len(f"{pi_approximation}") == digits + 2
) # for the decimal point and "3"
assert pi_approximation == Decimal("3.141")
digits = 39
pi_approximation = calculate_pi(digits)
assert (
len(f"{pi_approximation}") == digits + 2
) # for the decimal point and "3"
assert pi_approximation == Decimal(
"3.141592653589793238462643383279502884197"
)
digits = 100
pi_approximation = calculate_pi(digits)
assert (
len(f"{pi_approximation}") == digits + 2
) # for the decimal point and "3"
assert pi_approximation == Decimal(
"3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"
)

# check against standard library
digits = 15
pi_approximation = calculate_pi(digits)
assert f"{pi_approximation}" == f"{math.pi}"
Loading