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.
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.
Delaying the conversion of π
to a float results in precise mathematical expressions such as
Using π | Using Pi |
---|---|
julia> (1//3)π + (4//3)π == (5//3)π
false
julia> float(sqrt(pi)^2) == float(pi)
false |
julia> (1//3)Pi + (4//3)Pi == (5//3)Pi
true
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
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.
Using π | Using Pi |
---|---|
julia> cos(3π/2)
-1.8369701987210297e-16
julia> sin(-π)
-1.2246467991473532e-16
julia> tan(π/2)
1.633123935319537e16 |
julia> cos(3Pi/2)
0.0
julia> sin(-Pi)
-0.0
julia> tan(Pi/2)
Inf |
We may compute complex exponential exactly:
Using π | Using Pi |
---|---|
julia> exp(im*π/2)
6.123233995736766e-17 + 1.0im
# Euler's identity : exp(iπ) + 1 == 0
julia> exp(im*π) + 1
0.0 + 1.2246467991473532e-16im |
julia> exp(im*Pi/2)
0.0 + 1.0im
# Euler's identity : exp(iπ) + 1 == 0
julia> exp(im*Pi) + 1
0.0 + 0.0im |
Hyperbolic functions work as expected:
Using π | Using Pi |
---|---|
# cosh(ix) = cos(x)
# Should be exactly zero for x = π/2
julia> cosh(im*π/2)
6.123233995736766e-17 + 0.0im |
# cosh(ix) = cos(x)
# Should be exactly zero for x = π/2
julia> cosh(im*Pi/2)
0.0 + 0.0im |
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
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.
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.
Install the package using
pkg> add MultiplesOfPi