zeta.js (8087B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * 19 * ## Notice 20 * 21 * The original C++ code and copyright notice are from the [Boost library]{@link http://www.boost.org/doc/libs/1_60_0/boost/math/special_functions/zeta.hpp}. The implementation follows the original, but has been modified for JavaScript. 22 * 23 * ```text 24 * (C) Copyright John Maddock 2006. 25 * 26 * Use, modification and distribution are subject to the 27 * Boost Software License, Version 1.0. (See accompanying file 28 * LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) 29 * ``` 30 */ 31 32 'use strict'; 33 34 // MODULES // 35 36 var isnan = require( './../../../../base/assert/is-nan' ); 37 var isInteger = require( './../../../../base/assert/is-integer' ); 38 var abs = require( './../../../../base/special/abs' ); 39 var exp = require( './../../../../base/special/exp' ); 40 var floor = require( './../../../../base/special/floor' ); 41 var gamma = require( './../../../../base/special/gamma' ); 42 var gammaln = require( './../../../../base/special/gammaln' ); 43 var sinpi = require( './../../../../base/special/sinpi' ); 44 var pow = require( './../../../../base/special/pow' ); 45 var ln = require( './../../../../base/special/ln' ); 46 var PINF = require( '@stdlib/constants/float64/pinf' ); 47 var NINF = require( '@stdlib/constants/float64/ninf' ); 48 var TWO_PI = require( '@stdlib/constants/float64/two-pi' ); 49 var SQRT_EPSILON = require( '@stdlib/constants/float64/sqrt-eps' ); 50 var LN_SQRT_TWO_PI = require( '@stdlib/constants/float64/ln-sqrt-two-pi' ); 51 var ODD_POSITIVE_INTEGERS = require( './odd_positive_integers.json' ); 52 var EVEN_NONNEGATIVE_INTEGERS = require( './even_nonnegative_integers.json' ); 53 var BERNOULLI = require( './bernoulli.json' ); 54 var rateval1 = require( './rational_p1q1.js' ); 55 var rateval2 = require( './rational_p2q2.js' ); 56 var rateval3 = require( './rational_p3q3.js' ); 57 var rateval4 = require( './rational_p4q4.js' ); 58 var rateval5 = require( './rational_p5q5.js' ); 59 var rateval6 = require( './rational_p6q6.js' ); 60 61 62 // VARIABLES // 63 64 var MAX_BERNOULLI_2N = 129; 65 var MAX_FACTORIAL = 170; // TODO: consider making external constant 66 var MAX_LN = 709; // TODO: consider making external constant 67 var Y1 = 1.2433929443359375; 68 var Y3 = 0.6986598968505859375; 69 70 71 // MAIN // 72 73 /** 74 * Evaluates the Riemann zeta function. 75 * 76 * ## Method 77 * 78 * 1. First, we use the reflection formula 79 * 80 * ```tex 81 * \zeta(1-s) = 2 \sin\biggl(\frac{\pi(1-s)}{2}\biggr)(2\pi^{-s})\Gamma(s)\zeta(s) 82 * ``` 83 * 84 * to make \\(s\\) positive. 85 * 86 * 2. For \\(s \in (0,1)\\), we use the approximation 87 * 88 * ```tex 89 * \zeta(s) = \frac{C + \operatorname{R}(1-s) - s}{1-s} 90 * ``` 91 * 92 * with rational approximation \\(\operatorname{R}(1-z)\\) and constant \\(C\\). 93 * 94 * 3. For \\(s \in (1,4)\\), we use the approximation 95 * 96 * ```tex 97 * \zeta(s) = C + \operatorname{R}(s-n) + \frac{1}{s-1} 98 * ``` 99 * 100 * with rational approximation \\(\operatorname{R}(z-n)\\), constant \\(C\\), and integer \\(n\\). 101 * 102 * 4. For \\(s > 4\\), we use the approximation 103 * 104 * ```tex 105 * \zeta(s) = 1 + e^{\operatorname{R}(z-n)} 106 * ``` 107 * 108 * with rational approximation \\(\operatorname{R}(z-n)\\) and integer \\(n\\). 109 * 110 * 5. For negative odd integers, we use the closed form 111 * 112 * ```tex 113 * \zeta(-n) = \frac{(-1)^n}{n+1} B_{n+1} 114 * ``` 115 * 116 * where \\(B_{n+1}\\) is a Bernoulli number. 117 * 118 * 6. For negative even integers, we use the closed form 119 * 120 * ```tex 121 * \zeta(-2n) = 0 122 * ``` 123 * 124 * 7. For nonnegative even integers, we could use the closed form 125 * 126 * ```tex 127 * \zeta(2n) = \frac{(-1)^{n-1}2^{2n-1}\pi^{2n}}{(2n)!} B_{2n} 128 * ``` 129 * 130 * where \\(B_{2n}\\) is a Bernoulli number. However, to speed computation, we use precomputed values (Wolfram Alpha). 131 * 132 * 8. For positive negative integers, we use precomputed values (Wolfram Alpha), as these values are useful for certain infinite series calculations. 133 * 134 * 135 * ## Notes 136 * 137 * - \\(\[\approx 1.5\mbox{e-}8, 1)\\) 138 * 139 * - max deviation: \\(2.020\mbox{e-}18\\) 140 * - expected error: \\(-2.020\mbox{e-}18\\) 141 * - max error found (double): \\(3.994987\mbox{e-}17\\) 142 * 143 * - \\(\[1,2\]\\) 144 * 145 * - max deviation: \\(9.007\mbox{e-}20\\) 146 * - expected error: \\(9.007\mbox{e-}20\\) 147 * 148 * - \\((2,4\]\\) 149 * 150 * - max deviation: \\(5.946\mbox{e-}22\\) 151 * - expected error: \\(-5.946\mbox{e-}22\\) 152 * 153 * - \\((4,7\]\\) 154 * 155 * - max deviation: \\(2.955\mbox{e-}17\\) 156 * - expected error: \\(2.955\mbox{e-}17\\) 157 * - max error found (double): \\(2.009135\mbox{e-}16\\) 158 * 159 * - \\((7,15)\\) 160 * 161 * - max deviation: \\(7.117\mbox{e-}16\\) 162 * - expected error: \\(7.117\mbox{e-}16\\) 163 * - max error found (double): \\(9.387771\mbox{e-}16\\) 164 * 165 * - \\(\[15,36)\\) 166 * 167 * - max error (in interpolated form): \\(1.668\mbox{e-}17\\) 168 * - max error found (long double): \\(1.669714\mbox{e-}17\\) 169 * 170 * 171 * @param {number} s - input value 172 * @returns {number} function value 173 * 174 * @example 175 * var v = zeta( 1.1 ); 176 * // returns ~10.584 177 * 178 * @example 179 * var v = zeta( -4.0 ); 180 * // returns 0.0 181 * 182 * @example 183 * var v = zeta( 70.0 ); 184 * // returns 1.0 185 * 186 * @example 187 * var v = zeta( 0.5 ); 188 * // returns ~-1.46 189 * 190 * @example 191 * var v = zeta( 1.0 ); // pole 192 * // returns NaN 193 * 194 * @example 195 * var v = zeta( NaN ); 196 * // returns NaN 197 */ 198 function zeta( s ) { 199 var tmp; 200 var sc; 201 var as; 202 var is; 203 var r; 204 var n; 205 206 // Check for `NaN`: 207 if ( isnan( s ) ) { 208 return NaN; 209 } 210 // Check for a pole: 211 if ( s === 1.0 ) { 212 return NaN; 213 } 214 // Check for large value: 215 if ( s >= 56.0 ) { 216 return 1.0; 217 } 218 // Check for a closed form (integers): 219 if ( isInteger( s ) ) { 220 // Cast `s` to a 32-bit signed integer: 221 is = s|0; // asm type annotation 222 223 // Check that `s` does not exceed MAX_INT32: 224 if ( is === s ) { 225 if ( is < 0 ) { 226 as = (-is)|0; // asm type annotation 227 228 // Check if even negative integer: 229 if ( (as&1) === 0 ) { 230 return 0.0; 231 } 232 n = ( (as+1) / 2 )|0; // asm type annotation 233 234 // Check if less than max Bernoulli number: 235 if ( n <= MAX_BERNOULLI_2N ) { 236 return -BERNOULLI[ n ] / (as+1.0); 237 } 238 // fall through... 239 } 240 // Check if even nonnegative integer: 241 else if ( (is&1) === 0 ) { 242 return EVEN_NONNEGATIVE_INTEGERS[ is/2 ]; 243 } 244 // Must be a odd positive integer: 245 else { 246 return ODD_POSITIVE_INTEGERS[ (is-3)/2 ]; 247 } 248 } 249 // fall through... 250 } 251 if ( abs(s) < SQRT_EPSILON ) { 252 return -0.5 - (LN_SQRT_TWO_PI * s); 253 } 254 sc = 1.0 - s; 255 if ( s < 0.0 ) { 256 // Check if even negative integer: 257 if ( floor(s/2.0) === s/2.0 ) { 258 return 0.0; 259 } 260 // Swap `s` and `sc`: 261 tmp = s; 262 s = sc; 263 sc = tmp; 264 265 // Determine if computation will overflow: 266 if ( s > MAX_FACTORIAL ) { 267 tmp = sinpi( 0.5*sc ) * 2.0 * zeta( s ); 268 r = gammaln( s ); 269 r -= s * ln( TWO_PI ); 270 if ( r > MAX_LN ) { 271 return ( tmp < 0.0 ) ? NINF : PINF; 272 } 273 return tmp * exp( r ); 274 } 275 return sinpi( 0.5*sc ) * 2.0 * pow( TWO_PI, -s ) * gamma( s ) * zeta( s ); // eslint-disable-line max-len 276 } 277 if ( s < 1.0 ) { 278 tmp = rateval1( sc ); 279 tmp -= Y1; 280 tmp += sc; 281 tmp /= sc; 282 return tmp; 283 } 284 if ( s <= 2.0 ) { 285 sc = -sc; 286 tmp = 1.0 / sc; 287 return tmp + rateval2( sc ); 288 } 289 if ( s <= 4.0 ) { 290 tmp = Y3 + ( 1.0 / (-sc) ); 291 return tmp + rateval3( s-2.0 ); 292 } 293 if ( s <= 7.0 ) { 294 tmp = rateval4( s-4.0 ); 295 return 1.0 + exp( tmp ); 296 } 297 if ( s < 15.0 ) { 298 tmp = rateval5( s-7.0 ); 299 return 1.0 + exp( tmp ); 300 } 301 if ( s < 36.0 ) { 302 tmp = rateval6( s-15.0 ); 303 return 1.0 + exp( tmp ); 304 } 305 // s < 56 306 return 1.0 + pow( 2.0, -s ); 307 } 308 309 310 // EXPORTS // 311 312 module.exports = zeta;