Skip to content

Instantly share code, notes, and snippets.

@davidselassie
Created October 5, 2012 07:18

Revisions

  1. davidselassie created this gist Oct 5, 2012.
    94 changes: 94 additions & 0 deletions uncertain_rounding.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    var roundAway = function(x) {
    // Rounds a number to the next integer away from 0.
    //
    // Args:
    // x - Number to round.
    // Returns:
    // rounded - Next integer from x away from 0.

    if (x >= 0) {
    return Math.ceil(x);
    } else {
    return Math.floor(x);
    }
    }

    var roundToIndex = function(x, index) {
    // Rounds a number to a given index around the decimal point.
    //
    // Args:
    // x - Number to round.
    // index - Index of the least significan digit; 0 is the decimal point.
    // Returns:
    // rounded - Number rounded using the least signficant digit.

    var power = Math.pow(10, -index);
    return Math.round(x * power) / power;
    }

    var toFixedUncertainty = function(x, dx) {
    // Returns the string representation of a number correctly rounded given
    // an uncertainty value.
    //
    // Args:
    // x - Number to print.
    // dx - Uncertainty in x.
    // Returns:
    // x_string - String with x properly rounded given dx.

    // If there is no uncertainty, return the entire number.
    if (dx === undefined || dx == 0) {
    return x.toString();
    }

    // Find out the least significant digit using the uncertainty.
    var roundingIndex = roundAway(Math.log(dx) / Math.log(10));
    // Round using that number of digits.
    var roundedString = roundToIndex(x, roundingIndex).toString();

    // Now we have to only show the digits that are significant.

    // If we're rounding a whole number.
    if (roundingIndex >= 0) {
    // Find out if we want more significant digits that we have.
    var overshot = roundingIndex - roundedString.length + 1;
    if (overshot <= 0) {
    return roundedString;
    // If so, add more 0s on the beginning.
    } else {
    return Array(overshot + 1).join('0') + roundedString;
    }
    // If we're rounding to a decimal place.
    } else {
    var decimalIndex = roundedString.indexOf('.');
    // If there isn't a '.', we're rounding to 0 if we got here.
    if (decimalIndex < 0) {
    roundedString = '0.';
    decimalIndex = 1;
    }

    // Find out if the least significant digit is off the end of the
    // number.
    var lastIndex = decimalIndex + 1 - roundingIndex;
    var overshot = lastIndex - roundedString.length;
    if (overshot <= 0) {
    return roundedString.slice(0, lastIndex);
    // If so, add more 0s to show the precision we have.
    } else {
    return roundedString + Array(overshot + 1).join('0');
    }
    }
    }

    console.log(ciPrint(-123.4567, 1000));
    console.log(ciPrint(-123.4567, 100));
    console.log(ciPrint(-123.4567, 10));
    console.log(ciPrint(-123.4567, 1));
    console.log(ciPrint(-123.4567, 0));
    console.log(ciPrint(-123.4567, 0.1));
    console.log(ciPrint(-123.4567, 0.01));
    console.log(ciPrint(-123.4567, 0.001));
    console.log(ciPrint(-123.4567, 0.0001));
    console.log(ciPrint(-123.4567, 0.00001));

    console.log(ciPrint(0.0069, 0.0069));