Code of the Day: Javascript Significant Figures

Did you know that JavaScript automatically trims off trailing zeros on numbers with decimals?
Well now you do, and in order to save precision you must wrap the number inside a string.
Example:

1
2
3
4
5
6
var a = "0.0100";
var b = 0.0100;                           // To save space the interpreter cuts off the last two zeros.
console.log( a === b.toString() );	// displays false because a = "0.0100" and b = 0.01
 
console.log( 1000 === 1000.000 );	// displays true
console.log( 0.1 === 0.1000 );		// displays true

Some might argue that you can use num.toPrecision() to save the trailing zeros. But what most are unaware of is that toPrecision() returns a string.

1
2
3
4
5
var num = (120.0).toPrecision(8);
console.log( num );                      // displays 120.00000
console.log( typeof num );            // displays string
console.log( +num );                    // displays 120
// +num is a shortcut for parseInt( num, 10);

Now let’s see what happens with leading zero’s.

1
2
3
4
5
6
7
//A leading 0 in front of a number converts it base 8.
// a.k.a. parseInt( num, 8);
console.log(0011);		// Displays 9
console.log( 010.1000 );		// Error! Octals can only be whole numbers.
console.log( 00000.1000 );	// Error for the same reason.
// The problem is that a leading zero will cause the number to be converted to octal.
// Thus, an error is generated because the decimal point is neither an operation nor semicolon.

Using numbers as strings can be useful when trying to find the Significant Digits, like in the following function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Returns the significant digits of a number.
// @param {Number|String} num
// @return Returns -1 if invalid input, otherwise will return a positive number.
var getSigFigs = function (num) {
  if (!isFinite(Number(num))) {
    return -1;
  }
  var n = String(num).trim(),
  FIND_FRONT_ZEROS_SIGN_DOT_EXP = /^[\D0]+|\.|([e][^e]+)$/g,
  FIND_RIGHT_ZEROS = /0+$/g;
 
  if (!/\./.test(num)) {
    n = n.replace(FIND_RIGHT_ZEROS, "");
  }
  return n.replace(FIND_FRONT_ZEROS_SIGN_DOT_EXP, "").length;
};

Usage:

1
console.log( getSigFigFromNum( "0.01230" ) == 5);

Test cases

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 
// Try using Qunit to run tests.
var assert = {};
assert.equal = function (a, b) {
  if (a != b) {
    console.error("FAIL: --> %s != %s", a, b);
  } else {
    console.log("Pass: %s == %s", a, b);
  }
};
var test = function (name, fn) {
  console.log("\n#Testing: %s", name);
  fn();
};
test("Invalid numbers", function () {
  assert.equal(getSigFigs("742400g"), -1);
  assert.equal(getSigFigs("g742400"), -1);
  assert.equal(getSigFigs("Infinity"), -1);
  assert.equal(getSigFigs("-Infinity"), -1);
  assert.equal(getSigFigs("NaN"), -1);
});
var testWithPrefixes = function (prefixes, nums, fn) {
  prefixes.forEach(function (prefix) {
    nums.forEach(function (num) {
      //assert.equal( "Testing " + expected + "" prefix+expected, fn(prefix+num));
    });
  });
};
test("Whole Numbers", function () {
  assert.equal(getSigFigs("742400"), 4);
  assert.equal(getSigFigs("742000"), 3);
  assert.equal(getSigFigs("740000"), 2);
  assert.equal(getSigFigs("700000"), 1);
});
test("Negative Whole Numbers", function () {
  assert.equal(getSigFigs("-742400"), 4);
  assert.equal(getSigFigs("-742000"), 3);
  assert.equal(getSigFigs("-740000"), 2);
  assert.equal(getSigFigs("-700000"), 1);
});
test("+Whole numbers", function () {
  assert.equal(getSigFigs("+742400"), 4);
  assert.equal(getSigFigs("+742000"), 3);
  assert.equal(getSigFigs("+740000"), 2);
  assert.equal(getSigFigs("+700000"), 1);
});
test("Decimals", function () {
  assert.equal(getSigFigs("0.07284"), 4);
  assert.equal(getSigFigs("0.0728"), 3);
  assert.equal(getSigFigs("0.072"), 2);
  assert.equal(getSigFigs("0.07"), 1);
  assert.equal(getSigFigs("123.07"), 5);
});
test("Negative Decimals", function () {
  assert.equal(getSigFigs("-0.07284"), 4);
  assert.equal(getSigFigs("-0.0728"), 3);
  assert.equal(getSigFigs("-0.072"), 2);
  assert.equal(getSigFigs("-0.07"), 1);
  assert.equal(getSigFigs("-10.07"), 4);
});
test("Decimals", function () {
  assert.equal(getSigFigs("+0.07284"), 4);
  assert.equal(getSigFigs("+0.0728"), 3);
  assert.equal(getSigFigs("+0.072"), 2);
  assert.equal(getSigFigs("+0.07"), 1);
});
test("Zero", function () {
  assert.equal(getSigFigs("0.0"), 0);
  assert.equal(getSigFigs("-0.0"), 0);
  assert.equal(getSigFigs("0"), 0);
  assert.equal(getSigFigs("+0"), 0);
  assert.equal(getSigFigs("-0"), 0);
});
 
test("E notated", function () {
  assert.equal(getSigFigs("1.3e32"), 2);
  assert.equal(getSigFigs("-1.23e-32"), 3);
  assert.equal(getSigFigs("-1.023e+120"), 4);
  assert.equal(getSigFigs("+5.023e+32"), 4);
  assert.equal(getSigFigs("+5.0230e+32"), 5);
});

Can you think of any other useful examples for number wrapped in strings?

(Page view Count: 674)