Kylie
Kylie

Reputation: 11749

Rounding large decimals to nearest decimals

So I have a function that rounds to certain decimal scales

const roundNumber = (num, scale) => {
   let n = num
   switch(scale){
    case 0.50:
        n = (Math.ceil(num*2)/2).toFixed(2)
    break;
    case 0.25:
        n = (Math.ceil(num*4)/4).toFixed(2)
    break;
    case 0.20:
        n = (Math.ceil(num*5)/5).toFixed(2)
    break;
    case 0.10:
        n =  (Math.ceil(num*10)/10).toFixed(2)
    break;
    case 0.05:
        n = (Math.ceil(num*20)/20).toFixed(2)
    break;
  }

  return n
}

How would I adapt this to round to even smaller amounts such as...

  0.000001, 0.000025, 0.000050, 0.0001,0.00025, 0.00050, 0.001 etc etc

So example.

  0.48675387

I want to be able to output any of these amounts from this one number

 0.48675000
 0.48680000
 0.48700000
 0.49000000
 0.50000000

Do I need to use a Big Number library for this? I can't think of how I would do this.

EDIT: Ive updated this with a table of values of inputs and outputs so you can see what I want to achieve. I basically want the number to snap to certain values, based on how close they are to them. Like normal rounding, but slightly different.

      Scale      Number         Output
      0.00025    0.45341000     0.45350
      0.0025     0.45341000     0.4525 (closer to 0.4525 than 0.4550
      0.005      0.45341000     0.455
      0.01       0.45341000     0.45

See how the values differ if I simply just use toPrecision or toFixed

      Number         Output
      0.45341000     0.45341
      0.45341000     0.4534
      0.45341000     0.453
      0.45341000     0.45

Upvotes: 0

Views: 76

Answers (3)

alexanderbird
alexanderbird

Reputation: 4198

I think the algorithm you're describing is:

  1. divide the number by the scale
  2. round that result to get an integer
  3. multiply the scale by the resulting integer

In other words: "If I split this number into chunks of size scale, then add one more chunk if the remainder is more than half of the scale amount, and then put the chunks back together, what is the sum?"

function roundTo(scale, number) {
  return Math.round(number / scale) * scale;
}

function roundTo(scale, number) {
  return Math.round(number / scale) * scale;
}

const examples = [
  { scale: 0.00025, number: 0.45341000, expected: 0.45350 },
  { scale: 0.0025,  number: 0.45341000, expected: 0.4525 },
  { scale: 0.005,   number: 0.45341000, expected: 0.455 },
  { scale: 0.01,    number: 0.45341000, expected: 0.45 },
]

examples.forEach(({ scale, number, expected }) => {
  const actual = roundTo(scale, number);
  const isExpectedResult = actual === expected ? '✅' : '❌';
  console.log({ scale, number, expected, actual, isExpectedResult });
});

Upvotes: 0

Kinglish
Kinglish

Reputation: 23654

This isn't pretty but I'll put it down here and maybe come back to refine it. This should get you there though. Update: removed toPrecision early in the function since we're not using normal rounding.

   function roundTo(num, scale) {
        let arr, places, ref, lastx, remainder, thenum
        arr = scale.toString().split(".")
        places = arr[1].length; // get number decimal places
        num = Number(num).toFixed(places); // get our starting number in the right format
        ref=scale * Math.pow(10, places); // get our scale to the right format
        lastx = Number(num.toString().substr(-(ref.toString().length))) // get the scale increment
        remainder  = lastx%ref; // modulus
        if (remainder>=ref/2) thenum= Number((ref-remainder)*Math.pow(.1, places)) // if we need to add an amt
        else thenum = Number(remainder*Math.pow(.1, places)) * -1 ; // if we need to substract an amt
        thenum = thenum.toFixed(places) // fix our value
//        console.log(places,num,ref,lastx,remainder,thenum);

        num=(Number(num) + Number(thenum)).toFixed(places) // final calculation
        return num;
    }


console.log(roundTo(0.8946, 0.001));
console.log(roundTo(1.8946, 0.001));

Upvotes: 1

Bert
Bert

Reputation: 2244

Use Number.prototype.toPrecision()

let n  =   0.48675387

n.toPrecision(5)
"0.48675"
n.toPrecision(4)
"0.4868"
n.toPrecision(3)
"0.487"
n.toPrecision(2)
"0.49"
n.toPrecision(1)
"0.5"

Upvotes: 1

Related Questions