newton_raphson.js (3856B)
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_62_0/boost/math/tools/roots.hpp}. The implementation has been modified for JavaScript. 22 * 23 * ```text 24 * 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 sign = require( './../../../../base/special/signum' ); 37 var abs = require( './../../../../base/special/abs' ); 38 var ldexp = require( './../../../../base/special/ldexp' ); 39 var MAX_VALUE = require( '@stdlib/constants/float64/max' ); 40 41 42 // MAIN // 43 44 /** 45 * Performs root finding via second order Newton-Raphson iteration. 46 * 47 * @private 48 * @param {Array} fun - two-element array of the function and its first derivative 49 * @param {number} guess - initial starting value. 50 * @param {number} min - minimum possible value for the result,used as initial lower bracket. 51 * @param {number} max - maximum possible value for the result, used as initial upper bracket. 52 * @param {PositiveInteger} digits - desired number of binary digits 53 * @param {PositiveInteger} maxIter - maximum number of iterations 54 * @returns {number} function value 55 */ 56 function newtonRaphsonIterate( fun, guess, min, max, digits, maxIter ) { 57 var f0last; 58 var delta1; 59 var delta2; 60 var factor; 61 var result; 62 var count; 63 var delta; 64 var res; 65 var f0; 66 var f1; 67 68 f0 = 0.0; 69 f0last = 0.0; 70 result = guess; 71 72 factor = ldexp( 1.0, 1.0 - digits ); 73 delta = MAX_VALUE; 74 delta1 = MAX_VALUE; 75 delta2 = MAX_VALUE; 76 77 count = maxIter; 78 do { 79 f0last = f0; 80 delta2 = delta1; 81 delta1 = delta; 82 res = fun(result); 83 f0 = res[ 0 ]; 84 f1 = res[ 1 ]; 85 count -= 1; 86 if ( f0 === 0.0 ) { 87 break; 88 } 89 if ( f1 === 0.0 ) { 90 // Oops zero derivative!!! 91 if ( f0last === 0.0 ) { 92 // Must be the first iteration, pretend that we had a previous one at either min or max: 93 if ( result === min ) { 94 guess = max; 95 } else { 96 guess = min; 97 } 98 f0last = fun( guess ); 99 delta = guess - result; 100 } 101 if ( sign(f0last) * sign(f0) < 0 ) { 102 // We've crossed over so move in opposite direction to last step: 103 if ( delta < 0 ) { 104 delta = (result - min) / 2.0; 105 } else { 106 delta = (result - max) / 2.0; 107 } 108 } else if ( delta < 0 ) { 109 delta = (result - max) / 2.0; 110 } else { 111 delta = (result - min) / 2.0; 112 } 113 } else { 114 delta = f0 / f1; 115 } 116 if ( abs(delta * 2.0) > abs(delta2) ) { 117 // Last two steps haven't converged, try bisection: 118 delta = ( delta > 0.0 ) ? (result-min) / 2.0 : (result-max) / 2.0; 119 } 120 guess = result; 121 result -= delta; 122 if ( result <= min ) { 123 delta = 0.5 * (guess - min); 124 result = guess - delta; 125 if ( result === min || result === max ) { 126 break; 127 } 128 } else if ( result >= max ) { 129 delta = 0.5 * (guess - max); 130 result = guess - delta; 131 if ( result === min || result === max ) { 132 break; 133 } 134 } 135 // Update brackets: 136 if ( delta > 0.0 ) { 137 max = guess; 138 } else { 139 min = guess; 140 } 141 } 142 while ( count && ( abs(result * factor) < abs(delta) ) ); 143 144 return result; 145 } 146 147 148 // EXPORTS // 149 150 module.exports = newtonRaphsonIterate;