Skip to content

Instantly share code, notes, and snippets.

@mastermatt
Last active August 29, 2015 13:56
Show Gist options
  • Save mastermatt/8870098 to your computer and use it in GitHub Desktop.
Save mastermatt/8870098 to your computer and use it in GitHub Desktop.

Revisions

  1. Matt R. Wilson revised this gist Feb 7, 2014. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions precisionRound.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    /**
    * Returns the value of a float rounded using the number of decimal points provided as precision.
    *
    @@ -39,7 +38,7 @@ Math.precisionRound = function( number, precision ) {
    return NaN;
    }

    // In case the number is already in scientific when casted to string, eSplit off the exponent
    // In case the number is already in scientific when casted to string, split off the exponent
    eSplit = ("" + castNumber).split( "e" );

    // Increase the exponent by the given precision and create a scientific notion string
  2. Matt R. Wilson created this gist Feb 7, 2014.
    56 changes: 56 additions & 0 deletions precisionRound.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,56 @@

    /**
    * Returns the value of a float rounded using the number of decimal points provided as precision.
    *
    * Fixes binary rounding issues eg. Math.round(1.005 * 100) / 100 === 1 that present
    * problems for accounting and finance-related software.
    *
    * The normal technique for rounding with decimals is to multiply the number by the log10 of the
    * precision, round then divide by the same log eg. for 2 decimal points `round(num * 100) / 100`.
    * The binary rounding issue, however, causes this: 1.005 * 100 === 100.49999999999999.
    *
    * This method plays on the use of converting scientific notation to a number,
    * eg 1.005e2 === 100.5 so casting: `round(num + "e2") + "e-2"` to a number will result
    * in the desired result.
    *
    * @param {number} number The value to round
    * @param {int} precision The optional number of decimal digits to round to
    *
    * @returns {number} The adjusted value
    *
    * Based on MDN function
    * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
    */
    Math.precisionRound = function( number, precision ) {
    "use strict";

    var nativeRound = Math.round,
    castNumber = +number,
    castPrecision = +precision,
    scaledNumber, eSplit, eString;

    // If the exp is undefined or zero, just use native rounding
    if( typeof precision === "undefined" || 0 === castPrecision ) {
    return nativeRound( number );
    }

    // If the value is not a number or the exp is not an integer...
    if( isNaN( castNumber ) || !(typeof castPrecision === "number" && 0 === castPrecision % 1) ) {
    return NaN;
    }

    // In case the number is already in scientific when casted to string, eSplit off the exponent
    eSplit = ("" + castNumber).split( "e" );

    // Increase the exponent by the given precision and create a scientific notion string
    eString = (eSplit[0] + "e" + (eSplit[1] ? (+eSplit[1] + castPrecision) : castPrecision));

    // Cast to number and round
    scaledNumber = nativeRound( +eString );

    // Do the same as before, backwards
    eSplit = ("" + scaledNumber).split( "e" );
    eString = (eSplit[0] + "e" + (eSplit[1] ? (+eSplit[1] - castPrecision) : -castPrecision));

    return +eString;
    };