# MultiplesOfPi

# Introduction

This package exports the type `PiExpTimes`

that satisfies `PiExpTimes(x, n) = x*π^n`

. It also provides the constant `Pi`

for convenience, defined as `PiExpTimes(1, 1)`

, that behaves like `π`

except it produces results with higher accuracy in certain trigonometric and algebraic contexts. In most scenarios the numbers `Pi`

and `π`

are interchangable. Expressing mathematical relations in terms of `Pi`

instead of the more cumbersome `PiExpTimes`

is usually cleaner, and is recommended unless it's specifically necessary to do otherwise.

## Rationale

The number `π`

is represented as an `Irrational`

type in julia, and may be computed to an arbitrary degree of precision. In normal course of events it is converted to a float when it encounters another number, for example `2π`

is computed by converting both `2`

and `π`

to floats and subsequently carrying out a floating-point multiplication. This is lossy, as both `2`

and `π`

may be represented with arbitrary precision. This package delays the conversion of the `π`

to a float, treating it as a common factor in algebraic simplifications. This limits floating-point inaccuracies, especially if the terms multiplying `π`

are exactly representable in binary. As an added advantage, it uses `sinpi`

and `cospi`

wherever possible to avoid having to convert `π`

to a float altogether.

# Features

## Arithmetic

Delaying the conversion of `π`

to a float results in precise mathematical expressions such as

```
julia> (1//3)π + (4//3)π == (5//3)π
false
julia> (1//3)Pi + (4//3)Pi == (5//3)Pi
true
julia> float(sqrt(pi)^2) == float(pi)
false
julia> float(sqrt(Pi)^2) == float(Pi)
true
```

We may also simplify algebraic expressions involving powers of `Pi`

as

```
julia> (2Pi^2//3) // (4Pi//5)
(5//6)Pi
julia> Pi^-2 / 4Pi^3
0.25*Pi^-5
```

Expressions involving `Pi`

are automatically promoted to `Complex`

as necessary, eg.

```
julia> (1+im)Pi^3 / 2Pi^2
0.5*Pi + 0.5*Pi*im
julia> (1+im)Pi^3 / 2Pi^2 * 2/Pi
Pi^0 + Pi^0*im
```

## Trigonometric functions

The type `PiTimes`

uses `sinpi`

and `cospi`

under the hood when it is used as an argument to `sin`

and `cos`

. This results in exact results in several contexts where the inaccuracies arise from floating-point conversions.

```
julia> cos(3π/2)
-1.8369701987210297e-16
julia> cos(3Pi/2)
0.0
julia> sin(-π)
-1.2246467991473532e-16
julia> sin(-Pi)
-0.0
julia> tan(π/2)
1.633123935319537e16
julia> tan(Pi/2)
Inf
```

We may compute complex exponential exactly:

```
julia> exp(im*π/2)
6.123233995736766e-17 + 1.0im
julia> exp(im*Pi/2)
0.0 + 1.0im
# Euler's identity : exp(iπ) + 1 == 0
julia> exp(im*π) + 1
0.0 + 1.2246467991473532e-16im
julia> exp(im*Pi) + 1
0.0 + 0.0im
```

Hyperbolic functions work as expected:

```
# cosh(ix) = cos(x)
# Should be exactly zero for x = π/2
julia> cosh(im*π/2)
6.123233995736766e-17 + 0.0im
julia> cosh(im*Pi/2)
0.0 + 0.0im
```

### Interactions with π

The irrational number `π`

is usually aggressively converted to `Pi`

, eg:

```
julia> π * Pi
Pi^2
```

This ensures that subsequent calculation would not get promoted to a floating-point type. However if this behavior is not desired then one may specify the type explicitly while constructing the object as

```
julia> PiExpTimes{Irrational{:π}}(π)
π*Pi^0
```

### Floating-point promotion

Addition and subtraction involving mixed exponents of `Pi`

will involve floating-point conversions, and the resulting expression will have the minimum exponent out of the terms being summed.

```
julia> Pi + 3Pi
4Pi
julia> Pi + 3Pi^2
10.42477796076938*Pi
```

This fits with the intuition of the expression being factorized as `Pi + 3Pi^2 == Pi*(1 + 3Pi)`

.

Note that `π`

is promoted to `Pi`

in such operations, so we obtain

```
julia> Pi + π
2Pi
```

Note that addition and subtraction are not type-stable at present by design.

# Performance

In general using `Pi`

instead of `pi`

will be less performant, as `pi`

is aggressively promoted to a floating-point value in most calculations. The use of `Pi`

is mainly intended for tests where exact fractions of `Pi`

are desirable.

# Installation

Install the package using

`pkg> add MultiplesOfPi`