Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the fastest way to count the number of significant digits of a number?

Tags:

javascript

What is the fastest way to count the number of significant digits of a number?

I have the following function, which works, but is quite slow due to string operations.

/**
 * Count the number of significant digits of a number.
 *
 * For example:
 *   2.34 returns 3
 *   0.0034 returns 2
 *   120.5e+3 returns 4
 *
 * @param {Number} value
 * @return {Number} The number of significant digits
 */
function digits (value) {
  return value
      .toExponential()
      .replace(/e[\+\-0-9]*$/, '')  // remove exponential notation
      .replace( /^0\.?0*|\./, '')    // remove decimal point and leading zeros
      .length
};

Is there a faster way?

Update: here a list of assertions to test correct functioning:

assert.equal(digits(0), 0);
assert.equal(digits(2), 1);
assert.equal(digits(1234), 4);
assert.equal(digits(2.34), 3);
assert.equal(digits(3000), 1);
assert.equal(digits(0.0034), 2);
assert.equal(digits(120.5e50), 4);
assert.equal(digits(1120.5e+50), 5);
assert.equal(digits(120.52e-50), 5);
assert.equal(digits(Math.PI), 16);

My own method failed for digits(0), I fixed that by adding a ? to the second regexp.

like image 766
Jos de Jong Avatar asked Apr 05 '14 18:04

Jos de Jong


People also ask

What is the easiest way to identify significant figures?

To determine the number of significant figures in a number use the following 3 rules: Non-zero digits are always significant. Any zeros between two significant digits are significant. A final zero or trailing zeros in the decimal portion ONLY are significant.

How do you find most significant digits?

The number of significant figures is determined by starting with the leftmost non-zero digit. The leftmost non-zero digit is sometimes called the most significant digit or the most significant figure. For example, in the number 0.004205, the '4' is the most significant figure.


3 Answers

Here's a more mathematical way of doing the same operation (which appears to be significantly faster)

JSPerf comparing the three implementations

Accurate for integer n < +-(2^53) per http://ecma262-5.com/ELS5_HTML.htm#Section_8.5
Floats are converted to a string and then coerced to an int (by removing the decimal so similar rules apply)

var log10 = Math.log(10);
function getSignificantDigitCount(n) {
    n = Math.abs(String(n).replace(".", "")); //remove decimal and make positive
    if (n == 0) return 0;
    while (n != 0 && n % 10 == 0) n /= 10; //kill the 0s at the end of n

    return Math.floor(Math.log(n) / log10) + 1; //get number of digits
}
like image 74
megawac Avatar answered Oct 13 '22 01:10

megawac


Slight improvement of regular expression

function digits (value) {
  return value
      .toExponential()
      .replace(/^([0-9]+)\.?([0-9]+)?e[\+\-0-9]*$/g, "$1$2")
      .length
};
like image 22
Omer Arshad Avatar answered Oct 12 '22 23:10

Omer Arshad


And yet another approach, that uses string operations and handles some special cases for better performance:

function digits(value) {
    if (value === 0) {
        return 0;
    }
    //create absolute value and
    var t1 = ("" + Math.abs(value));
    //remove decimal point
    var t2 = t1.replace(".","");

    //if number is represented by scientific notation,
    //the places before "e" (minus "-" and ".") are the
    //significant digits. So here we can just return the index
    //"-234.3e+50" -> "2343e+50" -> indexOf("e") === 4
    var i = t2.indexOf("e");
    if (i > -1) {
        return i;
    } 

    //if the original number had a decimal point,
    //trailing zeros are already removed, since irrelevant
    //0.001230000.toString() -> "0.00123" -> "000123"
    if (t2.length < t1.length) {
        // -> remove only leading zeros
        return t2.replace(/^0+/,'').length;
    }

    //if number did not contain decimal point,
    //leading zeros are already removed
    //000123000.toString() -> "123000"
    // -> remove only trailing zeros
    return t2.replace(/0+$/,'').length;
}
like image 22
basilikum Avatar answered Oct 13 '22 01:10

basilikum