# reals

[![Build status](https://github.com/rubenvannieuwpoort/reals/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/rubenvannieuwpoort/reals/actions) [![PyPI version](https://badge.fury.io/py/reals.svg)](https://pypi.org/project/reals/)

A lightweight python3 library for arithmetic with real numbers.

Note that this library is still very experimental. It is not well tested and many important features are missing. I welcome users, but don't use this library in production code.


## Introduction

This library implements the `Real` datatype, which supports [arbitrary precision arithmetic](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) using [interval arithmetic](https://en.wikipedia.org/wiki/Interval_arithmetic) with [continued fractions](https://en.wikipedia.org/wiki/Continued_fraction). The bulk of this code is based on [Bill Gosper's notes on continued fractions](https://perl.plover.com/classes/cftalk/INFO/gosper.txt) in which he presents algorithms for doing arithmetic on continued fractions.


## Examples

Print [10000 digits](https://www.math.utah.edu/~pa/math/e.html) of Euler's number $e$:
```
from reals import e

print('{:.10000f}'.format(e))
```

Comparing the first 20 digits of `reals.pi` and `math.pi`:
```
from math import pi as math_pi
from reals import pi as real_pi

print('{:.20f}'.format(math_pi))
print('{:.20f}'.format(real_pi))
```


Get the first [10 best rational approximations](https://www.johndcook.com/blog/2018/05/22/best-approximations-for-pi/) to $\pi$:
```
from reals import pi
from reals.approximation import best_rational_approximations

print(best_rational_approximations(pi, 10))
```


Print the floating point number that is closest to $\frac{\pi}{e}$:
```
from reals import pi, e
from reals.approximation import Approximation

print(Approximation(pi / e).closest_float())
```


Print a rational approximation of $e^\pi$ that [has an error of less than $10^{-20}$](https://www.wolframalpha.com/input?i=231604552633%2F10008540207-e%5Epi):
```
from reals import pi, exp
from reals.approximation import Approximation

from fractions import Fraction


epsilon = Fraction(1, 10**20)

approximation = Approximation(exp(pi))
approximation.improve_epsilon(epsilon)

print(approximation.as_fraction())
```


Calculate a rational interval smaller than $10^{-10}$ that contains $\pi^2 - e^2$:
```
from reals import pi, e
from reals.approximation import Approximation

from fractions import Fraction


epsilon = Fraction(1, 10**10)

approximation = Approximation(pi * pi - e * e)
approximation.improve_epsilon(epsilon)

lower_bound, upper_bound = approximation.interval_fraction()
assert upper_bound - lower_bound < epsilon

print(lower_bound, upper_bound)
```


## Contributing

The reals library is very much in beta, much work is still to be done:
  - Manual testing
  - Add unit tests
  - Implement square roots, logarithms, trigonometric functions
  - Clean up the classes/functions
  - Write better introduction and documentation


### Exponentials and trigonometric functions

For a real number $x$, we compute $e^x$ as follows:
  1. Write $x = n + x_r$ with $n \in \mathbb{Z}$ and $-(1 + \epsilon) < x \leq 0$
  2. Calculate $e^x = e^n \cdot e^{x_r}$

We compute $e^k$ with the generalized continued fraction
$$ e^n = 1 + \frac{2n}{2 - n + \frac{n^2}{6 + \frac{n^2}{10 + \frac{n^2}{14 + ...}}}} $$

We calculate $e^{x_r}$ by using the power series for $e^x$:
$$ e^x = \sum_{k = 0}^\infty \frac{x^k}{k!} $$

Since $x_r$ is small, this power series converge well. Also, since $x_r$ is negative, truncation of the power series to $N$ terms is a lower bound for $e^{x_r}$ when $N$ is even, and an upper bound when $N$ is odd.

So, to calculate the terms of the continued fraction, we can calculate two truncations of the power series, one which gives a lower bound and one which gives an upper bound (this can be done by using the arbitrary precision arithmetic which is already implemented). Then, we calculate the terms of the truncations -- if both truncations give the same continued fraction term, we know the next term of the continued fraction of $e^{x_r}$. Otherwise, we need to increase the number $N$ of terms that the truncations uses, and repeat the process.

I think the same idea should work for the sine and cosine functions, but I haven't thought very hard about this yet.

> Continued fractions are not only perfectly amenable to arithmetic, they are
amenable to perfect arithmetic.

-- Bill Gosper