Gaussian/banker's rounding in JavaScript

后端 未结 6 1667
天涯浪人
天涯浪人 2020-11-27 02:51

I have been using Math.Round(myNumber, MidpointRounding.ToEven) in C# to do my server-side rounding, however, the user needs to know \'live\' what the result of

6条回答
  •  北荒
    北荒 (楼主)
    2020-11-27 03:21

    const isEven = (value: number) => value % 2 === 0;
    const isHalf = (value: number) => {
        const epsilon = 1e-8;
        const remainder = Math.abs(value) % 1;
    
        return remainder > .5 - epsilon && remainder < .5 + epsilon;
    };
    
    const roundHalfToEvenShifted = (value: number, factor: number) => {
        const shifted = value * factor;
        const rounded = Math.round(shifted);
        const modifier = value < 0 ? -1 : 1;
    
        return !isEven(rounded) && isHalf(shifted) ? rounded - modifier : rounded;
    };
    
    const roundHalfToEven = (digits: number, unshift: boolean) => {
        const factor = 10 ** digits;
    
        return unshift
            ? (value: number) => roundHalfToEvenShifted(value, factor) / factor
            : (value: number) => roundHalfToEvenShifted(value, factor);
    };
    
    const roundDollarsToCents = roundHalfToEven(2, false);
    const roundCurrency = roundHalfToEven(2, true);
    
    • If you do not like the overhead of calling toFixed()
    • Want to be able to supply an arbitrary scale
    • Don't want to introduce floating-point errors
    • Want to have readable, reusable code

    roundHalfToEven is a function that generates a fixed scale rounding function. I do my currency operations on cents, rather than dollars, to avoid introducing FPEs. The unshift param exists to avoid the overhead of unshifting and shifting again for those operations.

提交回复
热议问题