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