/// <summary> /// Computes the Riemann zeta function for complex values. /// </summary> /// <param name="z">The argument.</param> /// <returns>The value of ζ(z).</returns> /// <remarks> /// <para>As the imaginary part of the argument increases, the computation of the zeta function becomes slower and more difficult. /// The computation time is approximately proprotional to the imaginary part of z. The result also slowly looses accuracy for arguments with /// very large imaginary parts; for arguments with z.Im of order 10^d, approximately the last d digits of the result are suspect.</para> /// <para>The image below shows the complex Γ function near the origin using domain coloring. You can see the first non-trivial /// zeros at (1/2, ±14.13...) as well as the trivial zeros along the negative real axis.</para> /// <img src="../images/ComplexRiemannZetaPlot.png" /> /// </remarks> public static Complex RiemannZeta(Complex z) { // Use conjugation and reflection symmetry to move to the first quadrant. if (z.Im < 0.0) { return(RiemannZeta(z.Conjugate).Conjugate); } if (z.Re < 0.0) { Complex zp = Complex.One - z; return(2.0 * ComplexMath.Pow(Global.TwoPI, -zp) * ComplexMath.Cos(Global.HalfPI * zp) * AdvancedComplexMath.Gamma(zp) * RiemannZeta(zp)); } // Close to pole, use Laurent series. Complex zm1 = z - Complex.One; if (ComplexMath.Abs(zm1) < 0.50) { return(RiemannZeta_LaurentSeries(zm1)); } // Fall back to Euler-Maclaurin summation. int n = RiemannZeta_EulerMaclaurin_N(z.Re, z.Im); return(RiemannZeta_EulerMaclaurin(z, n)); }