foxmath 0.6.2__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {foxmath-0.6.2/src/foxmath.egg-info → foxmath-0.7.0}/PKG-INFO +16 -4
- {foxmath-0.6.2 → foxmath-0.7.0}/README.md +15 -3
- {foxmath-0.6.2 → foxmath-0.7.0}/pyproject.toml +2 -1
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath/foxmath.py +72 -0
- {foxmath-0.6.2 → foxmath-0.7.0/src/foxmath.egg-info}/PKG-INFO +16 -4
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath.egg-info/entry_points.txt +1 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/tests/test_cli.py +27 -1
- {foxmath-0.6.2 → foxmath-0.7.0}/tests/test_foxmath.py +43 -1
- {foxmath-0.6.2 → foxmath-0.7.0}/LICENSE +0 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/setup.cfg +0 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath/__init__.py +0 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath.egg-info/SOURCES.txt +0 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath.egg-info/dependency_links.txt +0 -0
- {foxmath-0.6.2 → foxmath-0.7.0}/src/foxmath.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foxmath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Minimalist CLI for math & cryptography exploration 🦊
|
|
5
5
|
Author-email: Abhrankan Chakrabarti <abhrankan@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -29,6 +29,7 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
29
29
|
|
|
30
30
|
## Features
|
|
31
31
|
- Legendre symbol
|
|
32
|
+
- Modular square root via Tonelli-Shanks (sqrtmod)
|
|
32
33
|
- Euler/Hermann Machin-like π approximation
|
|
33
34
|
- Elliptic curve point addition (over finite fields), including
|
|
34
35
|
named curves (secp256k1) with on-curve result validation
|
|
@@ -38,8 +39,8 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
38
39
|
- Continued fraction expansion and convergents
|
|
39
40
|
- Challenge/quiz mode — practice problems with scoring, or a
|
|
40
41
|
worksheet mode for self-study
|
|
41
|
-
- Symlink-friendly (foxmath-legendre, foxmath-
|
|
42
|
-
foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
42
|
+
- Symlink-friendly (foxmath-legendre, foxmath-sqrtmod, foxmath-pi,
|
|
43
|
+
foxmath-ecadd, foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
43
44
|
- JSON output mode
|
|
44
45
|
|
|
45
46
|
## Installation
|
|
@@ -60,7 +61,7 @@ Check which version you have installed:
|
|
|
60
61
|
foxmath --version
|
|
61
62
|
```
|
|
62
63
|
```
|
|
63
|
-
foxmath 0.
|
|
64
|
+
foxmath 0.7.0
|
|
64
65
|
```
|
|
65
66
|
|
|
66
67
|
## Usage Examples
|
|
@@ -79,6 +80,17 @@ foxmath legendre 5 17
|
|
|
79
80
|
Legendre (5/17) = -1
|
|
80
81
|
```
|
|
81
82
|
|
|
83
|
+
```bash
|
|
84
|
+
foxmath sqrtmod 10 13
|
|
85
|
+
```
|
|
86
|
+
```
|
|
87
|
+
sqrt(10) = +/-7 (mod 13)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`sqrtmod` uses the Tonelli-Shanks algorithm to find modular square roots
|
|
91
|
+
when they exist. It reports an error when the input is a quadratic
|
|
92
|
+
non-residue modulo the given odd prime.
|
|
93
|
+
|
|
82
94
|
```bash
|
|
83
95
|
# Symlinks (optional)
|
|
84
96
|
foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
@@ -10,6 +10,7 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
- Legendre symbol
|
|
13
|
+
- Modular square root via Tonelli-Shanks (sqrtmod)
|
|
13
14
|
- Euler/Hermann Machin-like π approximation
|
|
14
15
|
- Elliptic curve point addition (over finite fields), including
|
|
15
16
|
named curves (secp256k1) with on-curve result validation
|
|
@@ -19,8 +20,8 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
19
20
|
- Continued fraction expansion and convergents
|
|
20
21
|
- Challenge/quiz mode — practice problems with scoring, or a
|
|
21
22
|
worksheet mode for self-study
|
|
22
|
-
- Symlink-friendly (foxmath-legendre, foxmath-
|
|
23
|
-
foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
23
|
+
- Symlink-friendly (foxmath-legendre, foxmath-sqrtmod, foxmath-pi,
|
|
24
|
+
foxmath-ecadd, foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
24
25
|
- JSON output mode
|
|
25
26
|
|
|
26
27
|
## Installation
|
|
@@ -41,7 +42,7 @@ Check which version you have installed:
|
|
|
41
42
|
foxmath --version
|
|
42
43
|
```
|
|
43
44
|
```
|
|
44
|
-
foxmath 0.
|
|
45
|
+
foxmath 0.7.0
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
## Usage Examples
|
|
@@ -60,6 +61,17 @@ foxmath legendre 5 17
|
|
|
60
61
|
Legendre (5/17) = -1
|
|
61
62
|
```
|
|
62
63
|
|
|
64
|
+
```bash
|
|
65
|
+
foxmath sqrtmod 10 13
|
|
66
|
+
```
|
|
67
|
+
```
|
|
68
|
+
sqrt(10) = +/-7 (mod 13)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`sqrtmod` uses the Tonelli-Shanks algorithm to find modular square roots
|
|
72
|
+
when they exist. It reports an error when the input is a quadratic
|
|
73
|
+
non-residue modulo the given odd prime.
|
|
74
|
+
|
|
63
75
|
```bash
|
|
64
76
|
# Symlinks (optional)
|
|
65
77
|
foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "foxmath"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "Minimalist CLI for math & cryptography exploration 🦊"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -29,6 +29,7 @@ dependencies = [] # Pure stdlib for now
|
|
|
29
29
|
[project.scripts]
|
|
30
30
|
foxmath = "foxmath.foxmath:main"
|
|
31
31
|
foxmath-legendre = "foxmath.foxmath:main"
|
|
32
|
+
foxmath-sqrtmod = "foxmath.foxmath:main"
|
|
32
33
|
foxmath-pi = "foxmath.foxmath:main"
|
|
33
34
|
foxmath-ecadd = "foxmath.foxmath:main"
|
|
34
35
|
foxmath-ecmul = "foxmath.foxmath:main"
|
|
@@ -29,6 +29,54 @@ def legendre_symbol(a: int, p: int) -> int:
|
|
|
29
29
|
res = pow(a, (p - 1) // 2, p)
|
|
30
30
|
return 1 if res == 1 else (-1 if res == p - 1 else 0)
|
|
31
31
|
|
|
32
|
+
def sqrt_mod(a: int, p: int) -> tuple:
|
|
33
|
+
"""Return the square root(s) of a modulo an odd prime p."""
|
|
34
|
+
if p < 2 or p % 2 == 0:
|
|
35
|
+
raise ValueError("p must be an odd prime")
|
|
36
|
+
|
|
37
|
+
a %= p
|
|
38
|
+
symbol = legendre_symbol(a, p)
|
|
39
|
+
if symbol == 0:
|
|
40
|
+
return (0,)
|
|
41
|
+
if symbol == -1:
|
|
42
|
+
raise ValueError(f"{a} has no square root modulo {p}")
|
|
43
|
+
|
|
44
|
+
# For p ≡ 3 (mod 4), the root is a^(p+1)/4.
|
|
45
|
+
if p % 4 == 3:
|
|
46
|
+
root = pow(a, (p + 1) // 4, p)
|
|
47
|
+
else:
|
|
48
|
+
# Tonelli-Shanks: write p - 1 = q * 2^s with q odd.
|
|
49
|
+
q, s = p - 1, 0
|
|
50
|
+
while q % 2 == 0:
|
|
51
|
+
q //= 2
|
|
52
|
+
s += 1
|
|
53
|
+
|
|
54
|
+
non_residue = 2
|
|
55
|
+
while legendre_symbol(non_residue, p) != -1:
|
|
56
|
+
non_residue += 1
|
|
57
|
+
|
|
58
|
+
c = pow(non_residue, q, p)
|
|
59
|
+
root = pow(a, (q + 1) // 2, p)
|
|
60
|
+
t = pow(a, q, p)
|
|
61
|
+
m = s
|
|
62
|
+
|
|
63
|
+
while t != 1:
|
|
64
|
+
i = 1
|
|
65
|
+
t_squared = (t * t) % p
|
|
66
|
+
while t_squared != 1:
|
|
67
|
+
t_squared = (t_squared * t_squared) % p
|
|
68
|
+
i += 1
|
|
69
|
+
if i == m:
|
|
70
|
+
raise ValueError(f"{a} has no square root modulo {p}")
|
|
71
|
+
b = pow(c, 1 << (m - i - 1), p)
|
|
72
|
+
root = (root * b) % p
|
|
73
|
+
t = (t * b * b) % p
|
|
74
|
+
c = (b * b) % p
|
|
75
|
+
m = i
|
|
76
|
+
|
|
77
|
+
other = (-root) % p
|
|
78
|
+
return tuple(sorted({root, other}))
|
|
79
|
+
|
|
32
80
|
def _arctan_series(inv_n: Decimal, terms: int) -> Decimal:
|
|
33
81
|
"""arctan(1/n) via its Taylor series, evaluated to `terms` terms. `inv_n` is 1/n."""
|
|
34
82
|
total = Decimal(0)
|
|
@@ -283,6 +331,17 @@ def get_command():
|
|
|
283
331
|
return None
|
|
284
332
|
|
|
285
333
|
def main():
|
|
334
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
335
|
+
try:
|
|
336
|
+
sys.stdout.reconfigure(encoding="utf-8")
|
|
337
|
+
except Exception:
|
|
338
|
+
pass
|
|
339
|
+
if hasattr(sys.stderr, "reconfigure"):
|
|
340
|
+
try:
|
|
341
|
+
sys.stderr.reconfigure(encoding="utf-8")
|
|
342
|
+
except Exception:
|
|
343
|
+
pass
|
|
344
|
+
|
|
286
345
|
cmd = get_command()
|
|
287
346
|
|
|
288
347
|
# Handle --json independently of argparse subparser scoping: a subparser's
|
|
@@ -311,6 +370,10 @@ def main():
|
|
|
311
370
|
leg.add_argument("a", type=int, help="Integer a")
|
|
312
371
|
leg.add_argument("p", type=int, help="Odd prime p")
|
|
313
372
|
|
|
373
|
+
sqrt = subparsers.add_parser("sqrtmod", help="Square root(s) modulo an odd prime")
|
|
374
|
+
sqrt.add_argument("a", type=int, help="Integer a")
|
|
375
|
+
sqrt.add_argument("p", type=int, help="Odd prime p")
|
|
376
|
+
|
|
314
377
|
# Pi
|
|
315
378
|
pi_cmd = subparsers.add_parser("pi", help="Euler/Hermann Machin-like π approximation")
|
|
316
379
|
pi_cmd.add_argument("--terms", type=int, default=100)
|
|
@@ -366,6 +429,15 @@ def main():
|
|
|
366
429
|
if not json_output:
|
|
367
430
|
print(f"Legendre ({args.a}/{args.p}) = {ls}")
|
|
368
431
|
|
|
432
|
+
elif cmd == "sqrtmod" or args.command == "sqrtmod":
|
|
433
|
+
roots = sqrt_mod(args.a, args.p)
|
|
434
|
+
result.update({"command": "sqrtmod", "a": args.a, "p": args.p, "roots": list(roots)})
|
|
435
|
+
if not json_output:
|
|
436
|
+
if len(roots) == 1:
|
|
437
|
+
print(f"sqrt({args.a}) = {roots[0]} (mod {args.p})")
|
|
438
|
+
else:
|
|
439
|
+
print(f"sqrt({args.a}) = +/-{roots[1]} (mod {args.p})")
|
|
440
|
+
|
|
369
441
|
elif cmd == "pi" or args.command == "pi":
|
|
370
442
|
approx = euler_hermann_pi_approx(args.terms)
|
|
371
443
|
result.update({"command": "pi", "terms": args.terms, "approx": str(approx)})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: foxmath
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Minimalist CLI for math & cryptography exploration 🦊
|
|
5
5
|
Author-email: Abhrankan Chakrabarti <abhrankan@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -29,6 +29,7 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
29
29
|
|
|
30
30
|
## Features
|
|
31
31
|
- Legendre symbol
|
|
32
|
+
- Modular square root via Tonelli-Shanks (sqrtmod)
|
|
32
33
|
- Euler/Hermann Machin-like π approximation
|
|
33
34
|
- Elliptic curve point addition (over finite fields), including
|
|
34
35
|
named curves (secp256k1) with on-curve result validation
|
|
@@ -38,8 +39,8 @@ Built with curiosity — for students, tinkerers, and crypto/math enthusiasts.
|
|
|
38
39
|
- Continued fraction expansion and convergents
|
|
39
40
|
- Challenge/quiz mode — practice problems with scoring, or a
|
|
40
41
|
worksheet mode for self-study
|
|
41
|
-
- Symlink-friendly (foxmath-legendre, foxmath-
|
|
42
|
-
foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
42
|
+
- Symlink-friendly (foxmath-legendre, foxmath-sqrtmod, foxmath-pi,
|
|
43
|
+
foxmath-ecadd, foxmath-ecmul, foxmath-crt, foxmath-cf, foxmath-challenge)
|
|
43
44
|
- JSON output mode
|
|
44
45
|
|
|
45
46
|
## Installation
|
|
@@ -60,7 +61,7 @@ Check which version you have installed:
|
|
|
60
61
|
foxmath --version
|
|
61
62
|
```
|
|
62
63
|
```
|
|
63
|
-
foxmath 0.
|
|
64
|
+
foxmath 0.7.0
|
|
64
65
|
```
|
|
65
66
|
|
|
66
67
|
## Usage Examples
|
|
@@ -79,6 +80,17 @@ foxmath legendre 5 17
|
|
|
79
80
|
Legendre (5/17) = -1
|
|
80
81
|
```
|
|
81
82
|
|
|
83
|
+
```bash
|
|
84
|
+
foxmath sqrtmod 10 13
|
|
85
|
+
```
|
|
86
|
+
```
|
|
87
|
+
sqrt(10) = +/-7 (mod 13)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`sqrtmod` uses the Tonelli-Shanks algorithm to find modular square roots
|
|
91
|
+
when they exist. It reports an error when the input is a quadratic
|
|
92
|
+
non-residue modulo the given odd prime.
|
|
93
|
+
|
|
82
94
|
```bash
|
|
83
95
|
# Symlinks (optional)
|
|
84
96
|
foxmath-ecadd --x1 1 --y1 2 --x2 3 --y2 4 --p 17
|
|
@@ -16,7 +16,7 @@ SCRIPT = os.path.join(ROOT, "foxmath.py")
|
|
|
16
16
|
def run(*args, script=SCRIPT, stdin_input=None):
|
|
17
17
|
result = subprocess.run(
|
|
18
18
|
[sys.executable, script, *args],
|
|
19
|
-
capture_output=True, text=True, timeout=15, input=stdin_input,
|
|
19
|
+
capture_output=True, text=True, encoding="utf-8", timeout=15, input=stdin_input,
|
|
20
20
|
)
|
|
21
21
|
return result.returncode, result.stdout, result.stderr
|
|
22
22
|
|
|
@@ -38,6 +38,16 @@ class TestJsonFlag(unittest.TestCase):
|
|
|
38
38
|
self.assertEqual(code, 0)
|
|
39
39
|
self.assertNotIn("{", out)
|
|
40
40
|
|
|
41
|
+
def test_sqrtmod(self):
|
|
42
|
+
code, out, err = run("sqrtmod", "10", "13")
|
|
43
|
+
self.assertEqual(code, 0)
|
|
44
|
+
self.assertIn("sqrt(10) = +/-7 (mod 13)", out)
|
|
45
|
+
|
|
46
|
+
def test_sqrtmod_json(self):
|
|
47
|
+
code, out, err = run("sqrtmod", "10", "13", "--json")
|
|
48
|
+
self.assertEqual(code, 0)
|
|
49
|
+
self.assertIn('"roots": [', out)
|
|
50
|
+
|
|
41
51
|
def test_json_output_is_pure_json_no_preamble(self):
|
|
42
52
|
# Regression check: --json used to still print the human-readable
|
|
43
53
|
# line first, breaking anything piping stdout into a JSON parser.
|
|
@@ -66,6 +76,12 @@ class TestSymlinkInvocation(unittest.TestCase):
|
|
|
66
76
|
self.assertEqual(code, 0)
|
|
67
77
|
self.assertIn("Legendre (2/7) = 1", out)
|
|
68
78
|
|
|
79
|
+
def test_sqrtmod_symlink(self):
|
|
80
|
+
script = self._make_symlink_script("foxmath-sqrtmod")
|
|
81
|
+
code, out, err = run("10", "13", script=script)
|
|
82
|
+
self.assertEqual(code, 0)
|
|
83
|
+
self.assertIn("sqrt(10) = +/-7 (mod 13)", out)
|
|
84
|
+
|
|
69
85
|
def test_pi_symlink(self):
|
|
70
86
|
script = self._make_symlink_script("foxmath-pi")
|
|
71
87
|
code, out, err = run("--terms", "10", script=script)
|
|
@@ -275,6 +291,16 @@ class TestNormalUsage(unittest.TestCase):
|
|
|
275
291
|
self.assertEqual(code, 1)
|
|
276
292
|
self.assertIn("Error", err)
|
|
277
293
|
|
|
294
|
+
def test_sqrtmod_non_residue_errors(self):
|
|
295
|
+
code, out, err = run("sqrtmod", "5", "17")
|
|
296
|
+
self.assertEqual(code, 1)
|
|
297
|
+
self.assertIn("no square root", err)
|
|
298
|
+
|
|
299
|
+
def test_sqrtmod_zero(self):
|
|
300
|
+
code, out, err = run("sqrtmod", "0", "17")
|
|
301
|
+
self.assertEqual(code, 0)
|
|
302
|
+
self.assertIn("sqrt(0) = 0 (mod 17)", out)
|
|
303
|
+
|
|
278
304
|
|
|
279
305
|
if __name__ == "__main__":
|
|
280
306
|
unittest.main()
|
|
@@ -13,7 +13,7 @@ from decimal import Decimal
|
|
|
13
13
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
|
|
14
14
|
|
|
15
15
|
from foxmath.foxmath import (
|
|
16
|
-
legendre_symbol, euler_hermann_pi_approx, ec_point_add, ec_mul, crt_solve,
|
|
16
|
+
legendre_symbol, sqrt_mod, euler_hermann_pi_approx, ec_point_add, ec_mul, crt_solve,
|
|
17
17
|
continued_fraction, cf_convergents, CURVES, is_on_curve,
|
|
18
18
|
generate_problem,
|
|
19
19
|
)
|
|
@@ -52,6 +52,48 @@ class TestLegendreSymbol(unittest.TestCase):
|
|
|
52
52
|
legendre_symbol(3, 1)
|
|
53
53
|
|
|
54
54
|
|
|
55
|
+
class TestSqrtMod(unittest.TestCase):
|
|
56
|
+
def test_tonelli_shanks_returns_both_roots(self):
|
|
57
|
+
roots = sqrt_mod(10, 13)
|
|
58
|
+
self.assertEqual(roots, (6, 7))
|
|
59
|
+
self.assertTrue(all((root * root - 10) % 13 == 0 for root in roots))
|
|
60
|
+
|
|
61
|
+
def test_fast_path_for_prime_three_mod_four(self):
|
|
62
|
+
self.assertEqual(sqrt_mod(9, 11), (3, 8))
|
|
63
|
+
|
|
64
|
+
def test_zero_has_one_root(self):
|
|
65
|
+
self.assertEqual(sqrt_mod(0, 17), (0,))
|
|
66
|
+
|
|
67
|
+
def test_rejects_non_residue(self):
|
|
68
|
+
with self.assertRaises(ValueError):
|
|
69
|
+
sqrt_mod(5, 17)
|
|
70
|
+
|
|
71
|
+
def test_rejects_even_p(self):
|
|
72
|
+
with self.assertRaises(ValueError):
|
|
73
|
+
sqrt_mod(1, 2)
|
|
74
|
+
|
|
75
|
+
def test_rejects_p_less_than_2(self):
|
|
76
|
+
with self.assertRaises(ValueError):
|
|
77
|
+
sqrt_mod(1, 1)
|
|
78
|
+
with self.assertRaises(ValueError):
|
|
79
|
+
sqrt_mod(1, -5)
|
|
80
|
+
|
|
81
|
+
def test_normalizes_a_greater_than_p(self):
|
|
82
|
+
self.assertEqual(sqrt_mod(10 + 26, 13), (6, 7))
|
|
83
|
+
|
|
84
|
+
def test_negative_a(self):
|
|
85
|
+
self.assertEqual(sqrt_mod(-3, 13), (6, 7))
|
|
86
|
+
|
|
87
|
+
def test_larger_primes_tonelli_shanks(self):
|
|
88
|
+
roots_41 = sqrt_mod(8, 41)
|
|
89
|
+
self.assertEqual(roots_41, (7, 34))
|
|
90
|
+
self.assertTrue(all((r * r - 8) % 41 == 0 for r in roots_41))
|
|
91
|
+
|
|
92
|
+
roots_97 = sqrt_mod(2, 97)
|
|
93
|
+
self.assertEqual(roots_97, (14, 83))
|
|
94
|
+
self.assertTrue(all((r * r - 2) % 97 == 0 for r in roots_97))
|
|
95
|
+
|
|
96
|
+
|
|
55
97
|
class TestEulerHermannPiApprox(unittest.TestCase):
|
|
56
98
|
def test_converges_to_pi(self):
|
|
57
99
|
# Regression check: this used to converge to 16*arctan(1/2) =~ 7.418,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|