`cispi` is not accurate

In a package of mine, I replaced every occurrence of exp(1im*pi*z) with cispi(z). Then one of my unit tests has failed, and this test is a comparison of the evaluation of a special function to the exact value. There were differences after the sixth or seventh decimal digit. Then I believe that cispi is not accurate.

An example, but this is less striking on this example:

julia> cispi(1im)
0.04321391826377052 + 0.0im

julia> exp(-pi)
0.04321391826377226

The second one is closer to Wolfram:

0.04321391826377224977...

3 Likes

cis may not as accurate as exp(im*z), in circstats.jl, cis could make acos domain error.

Interestingly, you get the Wolfram figure if you work with BigFloat. Not sure if the pi digits are right, didn’t find unspaced text for comparison.
Round 2 per @longemen3000’s fix:

julia> typeof(pi), typeof(-pi)  # need to watch out for conversions
(Irrational{:π}, Float64)

julia> setprecision(1000) # must do this to avoid precision loss in methods
1000

julia> bigpi = BigFloat(pi) # prints only 302 digits
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412736

julia> exp(-bigpi) # prints only 305 digits
0.0432139182637722497744177371717280112757281098106330829807196874010507657570179676981399599619010843870168069645976620563265198317796586642654589470487654217430533893968290178108479426940587436021700979589304669505133081686070687502355832976249027608734841817238797966968412751519595753314335315085890095

julia> precision(bigpi), precision(-bigpi), precision(exp(-bigpi))
(1000, 1000, 1000)

Wolfram Alpha> N[Exp[-Pi], 143] # evaluates expression with 143-digit precision
0.0432139182637722497744177371717280112757281098106330829807196874010507657570179676981399599619010843870168069645976620563265198

julia> cis(pi*im) # real part is exp(-pi)
0.04321391826377226 + 0.0im

julia> cispi(1im)
0.04321391826377052 + 0.0im

the precision on BigFloat needs to be set on a global level, via setprecision:

julia> setprecision(1000)
1000
julia> bigpi = big(pi)
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412736
julia> precision(-bigpi)
1000
2 Likes

Indeed, cis and cispi don’t match in how they’re computed for complex z. cis(z) factors out the imaginary part and calls cis on real(z), while cispi(z) calls sincospi on the complex z directly, which here incurs a loss of precision by cancellation. I’ve submitted a fix here: Better precision for cispi(::Complex) by antoine-levitt · Pull Request #45945 · JuliaLang/julia · GitHub

9 Likes

I thought cis/cispi was only supposed to be an advantage for Real inputs. Why use them on complex data?

1 Like

Should be faster as it computes sines and cosines at the same time.

1 Like