2

Without jQuery, how can I round a float number to 2 non-zero decimals (but only when needed - 1.5 instead of 1.50)?

Just like this:

2.50000000004 -> 2.5
2.652 -> 2.65
2.655 -> 2.66
0.00000204 -> 0.000002
0.00000205 -> 0.0000021

I tried this code:

var r = n.toFixed(1-Math.floor(Math.log10(n)));

but n=0.00000205 implies r=0.0000020, which is in conflict with conditions above. But n=0.0000020501 implies r=0.0000021, which is OK, so the error is only for 5 as a last decimal, which should be rounded up.

core4096
  • 101
  • 12
  • 5
    Possible duplicate of [Round to at most 2 decimal places in JavaScript](http://stackoverflow.com/questions/11832914/round-to-at-most-2-decimal-places-in-javascript) – Tot Zam Aug 08 '16 at 20:06
  • 1
    @PrasadShinde This will round the last 2 examples to 0, which is not what the OP wants. – Arnauld Aug 08 '16 at 20:10
  • It is not a duplicate. I don't want to round to 2 decimal places, I want to round to 2 NON-ZERO decimal places. – core4096 Aug 08 '16 at 20:42
  • 1
    The term you're looking for is "rounding to precision". See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toPrecision – JJJ Aug 08 '16 at 20:49
  • @Juhana `n=0.00000205` and `n.toPrecision(2)` is equal to `0.0000020`. How can I achieve rounding 5 up? – core4096 Aug 08 '16 at 21:07
  • 2
    The reason you get `0.000020` for that is related to the imprecision of the floating point representation. `0.0000205` cannot be represented as *exactly* that value in floating point. For numbers that can, the result is as you would expect. NB: Ad-hoc coded functions that try to do this will probably all suffer from the same problem. – trincot Aug 08 '16 at 21:40

2 Answers2

8

This should do what you want:

function twoDecimals(n) {
  var log10 = n ? Math.floor(Math.log10(n)) : 0,
      div = log10 < 0 ? Math.pow(10, 1 - log10) : 100;

  return Math.round(n * div) / div;
}

var test = [
  2.50000000004,
  2.652,
  2.655,
  0.00000204,
  0.00000205,
  0.00000605
];

test.forEach(function(n) {
  console.log(n, '->', twoDecimals(n));
});
Arnauld
  • 5,847
  • 2
  • 15
  • 32
  • `n = 0.00000305` is rounded correctly to `0.0000031`, but `n = 0.00000605` is rounded to `0.000006`, not to `0.0000061`. – core4096 Aug 08 '16 at 21:18
  • Yeah, a bit better. Idk why, but there are still some values that ain't rounded properly, like `0.00000105` and `0.00000805`. – core4096 Aug 08 '16 at 21:36
  • 1
    Alas, these ones are the result of the inevitable approximation performed by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point) encoding. `console.log(0.00000105 * 1E7) -> 10.499999999999998` – Arnauld Aug 08 '16 at 21:44
  • Yeah, I can see it. `0.000008050000000000001` is rounded correctly....several very particular values just don't matter. Thank you! – core4096 Aug 08 '16 at 21:48
0

Thank's for the @Arnauld answer. Just added decimals parameter.

function roundToDecimals(n, decimals) {
  var log10 = n ? Math.floor(Math.log10(n)) : 0,
      div = log10 < 0 ? Math.pow(10, decimals - log10 - 1) : Math.pow(10, decimals);

  return Math.round(n * div) / div;
}

var numDecimals = 2
var test = [
  2.50000000004,
  2.652,
  2.655,
  0.00000204,
  0.00000205,
  0.00000605
];

test.forEach(function(n) {
  console.log(n, '->', roundToDecimals(n, numDecimals));
});
sergis4ake
  • 21
  • 3