Search code examples
javascriptmath

How to make stepper function increment by fraction of a number every step in Javascript?


I have this function, but it gives me random values like 0.35000000000000003 every now and then:

function roundToFractionOfPercent(
  value: number,
  step: number,
): number {
  return Math.round(value / step) * step
}

You call it like this (in theory):

roundToFractionOfPercent(0.0163, 0.01) // => 0.02

How can you take a value which can be up to however many decimal places JS supports (6-8 is plenty), and have it increment by a random stepping value from as small as 0.00000001 to as large as 1, and anything in between like 0.0007 or 0.04 (increment by that amount).

Basically I am implementing a custom stepper input outside of HTML, and need to know how to handle it on decimal values.

enter image description here


Solution

  • The issue you're encountering with floating-point rounding errors is common in JavaScript due to the way numbers are represented internally. Here's an improved version of your function,

    Improved Function

    function roundToFractionOfPercent(value, step) {
      const multiplier = 1 / step; // Avoid division later
      return Math.round(value * multiplier) / multiplier;
    }
    

    Handling Very Small Steps: If you're dealing with extremely small steps (like 0.00000001), consider this approach:Temporarily multiply both the value and the step by a large enough number to avoid floating-point issues during the calculation. For example:

    function roundToFractionOfPercent(value, step) {
        const scalingFactor = 1e10; // 10 to the power of 10
        const scaledValue = value * scalingFactor;
        const scaledStep = step * scalingFactor;
        return Math.round(scaledValue / scaledStep) * scaledStep / scalingFactor;
    }