The total price should be rounded to 5 cents according to following rules.
- If number ends with 0.01 to 0.04 cents, round number down, e.g. 15.52 to 15.50
- If number ends with 0.06 to 0.09 cents, round up, e.g. 15.57 to 15.60
- If number is less than 5 cents then number price is 5 cents, e.g. 0.04 to 0.05
- If number ends with 0 or 5 cents then don't round.
I have come up with following approach but seems to heavy and wonder if someone has a better idea?
var divisionValue = 0.05;
if (number > 0 && number < divisionValue) {
return divisionValue;
}
var roundedNumber = number;
var division = roundedNumber / divisionValue;
var divisionFormatted = (division).toFixed(2);
var moduloRemainder = divisionFormatted % 1;
var divisionRemainderFormatted = (moduloRemainder).toFixed(2);
// When there is no remainder, the value ends with 0.05 or 0.1
if (divisionRemainderFormatted === 0) {
return roundedNumber;
} else if (divisionRemainderFormatted !== 0) {
var diff = divisionFormatted - divisionRemainderFormatted;
if (diff % 2) {
// For values ending with 0.06 to 0.09 round up
roundedNumber = Math.ceil(number * 10) / 10;
} else {
// For values ending with 0.01 to 0.04 round up
roundedNumber = Math.floor(number * 10) / 10;
}
}
return (roundedNumber).toFixed(2
Test
it('Slovak rounding to 5 eurocents', function () {
// not round
expect(MathService.roundToFiveEurocent(23)).toBe(23);
expect(MathService.roundToFiveEurocent(23.1)).toBe(23.10);
expect(MathService.roundToFiveEurocent(23.15)).toBe(23.15);
// round down
expect(MathService.roundToFiveEurocent(23.11)).toBe(23.10);
expect(MathService.roundToFiveEurocent(23.12)).toBe(23.10);
expect(MathService.roundToFiveEurocent(23.13)).toBe(23.10);
expect(MathService.roundToFiveEurocent(23.14)).toBe(23.10);
// round up
expect(MathService.roundToFiveEurocent(23.17)).toBe(23.20);
expect(MathService.roundToFiveEurocent(23.18)).toBe(23.20);
expect(MathService.roundToFiveEurocent(23.19)).toBe(23.20);
// round to 0.05
expect(MathService.roundToFiveEurocent(0.01)).toBe(0.05);
expect(MathService.roundToFiveEurocent(0.02)).toBe(0.05);
expect(MathService.roundToFiveEurocent(0.03)).toBe(0.05);
expect(MathService.roundToFiveEurocent(0.04)).toBe(0.05);
});
CodePudding user response:
Here's a one liner...
function rt5( x ) {return x < 0 ? null : 0 < x && x < 0.05 ? 0.05 : x * 20 % 1 === 0 ? x : Math.floor( ( x 0.05 ) / 0.1 ) * 2 / 20 }
console.log( `rt5( 0.02 ) = ${rt5(0.02)}` );
console.log( `rt5( 0.14 ) = ${rt5(0.14)}` );
console.log( `rt5( 0.15 ) = ${rt5(0.15)}` );
console.log( `rt5( 0.16 ) = ${rt5(0.16)}` );
console.log( `rt5( 999999999999.94 ) = ${rt5(999999999999.94)}` );
console.log( `rt5( 999999999999.95 ) = ${rt5(999999999999.95)}` );
console.log( `rt5( 999999999999.96 ) = ${rt5(999999999999.96)}` );
console.log( `rt5( -1.05 ) = ${rt5(-1.05)}` );
CodePudding user response:
So basically you need to play with adding 0.05 and defining your exceptions
// not round
values = [
[23, 23],
[23.1, 23.10],
[23.15, 23.15],
// round down
[23.11, 23.10],
[23.12, 23.10],
[23.13, 23.10],
[23.14, 23.10],
// round up
[23.17, 23.20],
[23.18, 23.20],
[23.19, 23.20],
// round to 0.05
[0.01, 0.05],
[0.02, 0.05],
[0.03, 0.05],
[0.04, 0.05]
]
function test_round(val) {
to_round = parseFloat(val).toFixed(2)
if (to_round < 0.05)
return 0.05
ref = to_round * 10
if (ref - parseInt(ref) == 0.5)
return to_round
temp = parseFloat(to_round) 0.05;
clean = parseFloat(parseInt(temp * 10) / 10)
return clean
}
function test(_vals) {
for (v of _vals) {
if (v[1] != test_round(v[0])) {
console.log(['Failed rounding', '-', v, '-', test_round(v[0])].join(' '))
}
}
}
test(values)