70 lines
1.6 KiB
Python
70 lines
1.6 KiB
Python
|
#!/usr/bin/env python3
|
||
|
# implementing: https://web.media.mit.edu/~crtaylor/calculator.html
|
||
|
|
||
|
import numpy as np
|
||
|
|
||
|
# from math import factorial
|
||
|
_factorials = ( # all the factorials that fit into 53 bits
|
||
|
1,
|
||
|
1,
|
||
|
2,
|
||
|
6,
|
||
|
24,
|
||
|
120,
|
||
|
720,
|
||
|
5040,
|
||
|
40320,
|
||
|
362880,
|
||
|
3628800,
|
||
|
39916800,
|
||
|
479001600,
|
||
|
6227020800,
|
||
|
87178291200,
|
||
|
1307674368000,
|
||
|
20922789888000,
|
||
|
355687428096000,
|
||
|
6402373705728000,
|
||
|
)
|
||
|
|
||
|
__noisy = False
|
||
|
|
||
|
|
||
|
def fd(offsets, degree):
|
||
|
if degree < 0:
|
||
|
raise RuntimeError("the degree must be greater than or equal to zero")
|
||
|
elif degree > 18:
|
||
|
raise RuntimeError("degrees greater than 18 are unsupported")
|
||
|
if len(offsets) <= degree:
|
||
|
raise RuntimeError("the number of offsets must be greater than the degree")
|
||
|
mat = np.array([[o**n for o in offsets] for n in range(len(offsets))])
|
||
|
vec = np.array([_factorials[i] if i == degree else 0 for i in range(len(offsets))])
|
||
|
if __noisy:
|
||
|
print("mat:", mat, "vec:", vec, sep="\n")
|
||
|
res = np.linalg.lstsq(mat, vec, rcond=None)[0]
|
||
|
return res
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
__noisy = True
|
||
|
assert np.allclose(fd([-2, 0, 2], 1), [-1 / 4, 0, 1 / 4])
|
||
|
|
||
|
# + A * f(x - 2 * h)
|
||
|
# + B * f(x - 1 * h)
|
||
|
# + C * f(x)
|
||
|
# + D * f(x + 1 * h)
|
||
|
# + E * f(x + 2 * h)
|
||
|
assert np.allclose(fd([-2, -1, 0, 1, 2], 4), [1, -4, 6, -4, 1])
|
||
|
|
||
|
print("", "#" * 40, "", sep="\n")
|
||
|
|
||
|
ans = fd([-2, 7], 1)
|
||
|
print("ans:", ans)
|
||
|
|
||
|
ans = fd([-2, 0, 7], 1)
|
||
|
print("ans:", ans)
|
||
|
|
||
|
ans = fd([-0.2, 0.0, 0.7], 1)
|
||
|
print("ans:", ans)
|
||
|
|
||
|
__all__ = ("fd",)
|