npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

brent-zero-generator

v1.1.1

Published

Brent's root finding algorithm, as a generator function.

Downloads

3,358

Readme

brent-zero-generator

This module implements Brent's algorithm to find a root of a function f(). The module provides 3 functions: zero(), zero_generator(), and zero_generator2(). The functions zero_generator() and zero_generator2() facilitate solving asynchronous functions, and provide a lot of flexibility (see example below). For typical use, the simpler zero() function should be sufficient.

WARNING: the Ignorant Suffer

Before you consider using another similar code, have a look at the README.md of my BrentZeroTester.JS repository, where several alternative codes are compared. Both horrible performances, and wrong results happen in some of these codes.

TIP: T.R. Chandrupatla's zero

The package chandrupatla-zero contains my JavaScript implementation of T.R. Chandrupatla's algorithm. The repository compare-zeros, in my opinion, shows it is a bit better than Brent's algorithm.

Usage

The JavaScript code in this module follows Brent's original code of the Algol 60 procedure zero() very closely. In the first comment in that code, Brent describes procedure zero() as:

Procedure zero retuns a zero x of the function f in the given interval [a, b], to within a tolerance (4 macheps |x| + 2 t), where macheps is the relative machine precision and t is a positive tolerance. The procedure assumes that f(a) and f(b) have different signs

Parameters

|Parameter | Description |----------|------------ |f | the function f() for which the root is sought. Only for the utility function zero(). |a | the finite lowerbound of the interval in which to search the root |b | the finite upperbound of the interval in which to search the root |macheps | the relative tolerance. This parameter may be increased if a higher relative error is acceptable, but it should not be decreased, for then rounding errors might prevent convergence. (optional, default: Number.EPSILON) |t | the absolute tolerance. (optional, default: 0.0)

Functions

  • zero_generator2(a, b, macheps, t), and
  • zero_generator(a, b, macheps, t), and
  • zero(f, a, b, macheps, t).

Yields and returns

The generator functions zero_generator() and zero_generator2() only yield, the 'x' values, to request function evaluations. When the zero_generator2() function is 'done', it returns an array with the following contents:

  • res[0]: the x-value thought to be closest to the root,
  • res[1]: the corresponding y-value,
  • res[2]: the x-value closest to, but on the other side of the root,
  • res[3]: the corresponding y-value.

The functions zero_generator() and zero() only return the x-value, thought to be closest to the root.

Notes

  • f(a) and f(b) should have different signs.
  • the algorithm ends when f(x) == 0 is found, or the interval [a, b] has been sufficiently shrunk to be sure the x is within the tolerance. This says nothing about the value of f(x). For example the function x => x < 3 ? -1 : 2, will find a "root" close to 3, but f(x) will be -1.
  • the original comment in the Algol 60 code mentions 'a tolerance (6 macheps |x| + 2 t)'. The code of the algorithm limits the tolerance to 4 macheps |x| + 2 t. Brent adds '2 macheps |x|' due to inprecision in the calculation of the function values. I think this is confusing, so I changed the quote.

Some Examples

The following examples shows simple usage. Given a function f(x) = x² - 5.

1. Simplest zero() example

const brents = require('brent-zero-generator');

const f = x => x * x - 5;

console.log( brents.zero(f, 1, 4).toFixed(6) );
// expect 2.236068

2. Simple zero_generator2() example

const gen = brents.zero_generator2(-3, -2);

let result = gen.next();
while ( ! result.done ) {
    const x = result.value;
    const y = f(x);

    result = gen.next(y)    
}
console.log( result.value.toFixed(6) );
// expect [ -2.236068, 8.8e-16, -2.236068, -3.5e-15 ]

3. Modified zero_generator() example

Often implementations have additional parameters for maximum number of iterations (max_iter), or an allowed tolerance for the root's function value (yTol). Brent's original code does not have these options, and I am fairly sure he would not agree with them. However, using the generator function, they are easily implemented, as the following example function shows:

function myZero(f, a, b, max_iter, yTol) {
    const gen = zero_generator(a, b);

    let result = gen.next();
    for (let i=0; i<max_iter && ! result.done; ++i) {
        const x = result.value;
        const y = f(x);
        if (Math.abs(y) < yTol) break;

        result = gen.next(y)    
    }

    return result.value;
}

API changes

  • 1.1 Added zero_generator2() as an export.

Further Documentation

The ultimate documentation on this algorithm can be found on Emeritus Professor Richard P. Brent's page dedicated to his book Algorithms for Minimization Without Derivatives.
On that page, not only the errata for the different editions of the book are available, but also a scanned copy of the Prentice-Hall edition is also available for download.

C, C++, Fortran66/Fortran77 and Fortran90 codes can be found on John Burkardt's homepage.

A Wolfram-MathWorld page explains the way in which the inverse quadratic interpolation, which is important for the numerical stability, is implemented.

License

ISC