Search code examples
javascriptscientific-notationparsefloat

Javascript parseFloat '1.23e-7' gives 1.23e-7 when need 0.000000123


parseFloat(1.51e-6);
// returns 0.00000151

parseFloat(1.23e-7);
// returns 1.23e-7
// required 0.000000123

I am sorting table columns containing a wide range of floating-point numbers, some represented in scientific notation.

I am using the jQuery tablesorter2.0 plugin which is using 'parseFloat' for cells that start with a digit. The issue is that parseFloat returns very small numbers represented as 1.23e-7 as a string and is not expanding this to 0.000000123. As a result tablesorter sorts the content of the column as text instead of numerics.

**Column To Sort**
2.34
1.01
13.56
1.23e-7

**After Sort Now**
1.01
1.23e-7
13.56
2.34

**Expect**
1.23e-7
1.01
2.34
13.56

Is there an efficient way of representing very small scientific notation numbers as expanded floating-point numbers?

Solution:

tablesorter determines how to sort a column based on the first of tablesorters automatic parsers to return true for the content of a cell in that column. If the cell contained 1.23e-7 than it defaulted to sort by text because the 'digit' parser does not interpret this as a number.

So to workaround, the following code represents the scientific notation number as a string that tablesorter can interpret/parse as a digit and so ensures numerical sorting on the column. @bitplitter - thanks for the toFixed() tip.

var s = "1.23e-7";
// Handle exponential numbers.
if (s.match(/^[-+]?[1-9]\.[0-9]+e[-]?[1-9][0-9]*$/)) {
  s = (+s).toFixed(getPrecision(s));
}
//returns 0.000000123

// Get a nice decimal place precision for the scientific notation number.
// e.g. 1.23e-7 yields 7+2 places after the decimal point
// e.g. 4.5678e-11 yields 11+4 places after the decimal point
function getPrecision(scinum) {
  var arr = new Array();
  // Get the exponent after 'e', make it absolute.  
  arr = scinum.split('e');
  var exponent = Math.abs(arr[1]);

  // Add to it the number of digits between the '.' and the 'e'
  // to give our required precision.
  var precision = new Number(exponent);
  arr = arr[0].split('.');
  precision += arr[1].length;

  return precision;
}

Solution

  • Even though the OP has posted his solution, I'd like to share a rather simpler solution I stumbled upon, which is based on the parsers in the tablesorter source code and the regex given by JasonS on another question.

    // add parser through the tablesorter addParser method 
    $.tablesorter.addParser({ 
    // set a unique id
    id: 'scinot', 
    is: function(s) { 
        return /[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?/.test(s); 
    }, 
    format: function(s) { 
        return $.tablesorter.formatFloat(s);
    }, 
    type: 'numeric' 
    });
    

    It works on my tables with pretty much all values given in scientific notation. It auto-detects (the is: part) and correctly sorts multiple fields. Hope it helps others who might stumble upon this question.