0

I am writing a function to round off numbers based on a given least count.

So for example,

1.2345 with a least count of 0.01 should becoume 1.23
1.23 with a least count of 0.5 should become 1
1.52 with a least count of 0.2 should become 1.4
etc...

Here is my solution, but it feels a bit contrived, could someone please give any suggestions on how to improve it? Follow up, can Regex be used and will that be a more stable implementation?

const round = (num, leastCount) => {
  const numDecimals = `${leastCount}`.split('.')?.[1]?.length || 0;

  const newNumber = Math.round(num * Math.pow(10, numDecimals) + Number.EPSILON - num * Math.pow(10, numDecimals) % (leastCount * Math.pow(10, numDecimals))) / Math.pow(10, numDecimals)


  return newNumber

}

console.log(round(1.2345, 0.01)) // Expected: 1.23
console.log(round(5.66, 1)) // Expected: 5
console.log(round(2.375, 0.005)) // Expected: 2.375
console.log(round(1.33, 0.1)); // Expected: 1.3
console.log(round(2, 0.001)); // Expected: 2
console.log(round(1.7512323, 0.0001)); // Expected: 1.7512
console.log(round(1.52, 0.2)); // Expected: 1.4
roy05
  • 381
  • 1
  • 2
  • 11

1 Answers1

1

A simple incrementing while loop would probably be the simplest solution.

Increment a multiplier n of leastCount until the resulting product would be larger than the target num:

const round = (num, leastCount) => {
  if (num == 0) return 0;
  let n = 0;
  while (n * leastCount <= Math.abs(num)) {
    n++;
  }
  return (n - 1) * leastCount * (num < 0 ? -1 : 1);
}

console.log(round(1.2345, 0.01)) // Expected: 1.23
console.log(round(5.66, 1)) // Expected: 5
console.log(round(2.375, 0.005)) // Expected: 2.375
console.log(round(1.33, 0.1)); // Expected: 1.3
console.log(round(2, 0.001)); // Expected: 2
console.log(round(1.7512323, 0.0001)); // Expected: 1.7512
console.log(round(1.52, 0.2)); // Expected: 1.4

Response to comments

The weird fractions are caused by the way JavaScript handles floating point values and can be handled in different ways, depending on your implementations and needs.

I have used this solution in the example below, as well as a different and even simpler mathematical approach:

const round = (num, leastCount) => {
  if (num == 0) return 0;
  let intermediate = Math.floor(num / leastCount) * leastCount; // Find value
  return parseFloat(intermediate.toPrecision(12)); // Round of excessive decimals
}

console.log(round(1.2345, 0.01)) // Expected: 1.23
console.log(round(5.66, 1)) // Expected: 5
console.log(round(2.375, 0.005)) // Expected: 2.375
console.log(round(1.33, 0.1)); // Expected: 1.3
console.log(round(2, 0.001)); // Expected: 2
console.log(round(1.7512323, 0.0001)); // Expected: 1.7512
console.log(round(1.52, 0.2)); // Expected: 1.4
Emil S. Jørgensen
  • 6,216
  • 1
  • 15
  • 28
  • Wow, clean and simple solution! Any idea why the last console log returns `1.4000...01` and not 1.4? And how can I get ride of it? – roy05 Jul 19 '21 at 09:20