Skip to content

Commit

Permalink
#2250 Fixed rounding bug
Browse files Browse the repository at this point in the history
  • Loading branch information
skoshelev committed Sep 26, 2017
1 parent afd57b4 commit 130bf67
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 18 deletions.
38 changes: 20 additions & 18 deletions src/Libraries/Nop.Services/Catalog/RoundingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,53 +46,55 @@ public static decimal Round(this decimal value, RoundingType roundingType)
{
//default round (Rounding001)
var rez = Math.Round(value, 2);
decimal t;
var fractionPart = (rez - Math.Truncate(rez)) * 10;

//cash rounding not needed
if (fractionPart == 0)
return rez;

//Cash rounding (details: https://en.wikipedia.org/wiki/Cash_rounding)
switch (roundingType)
{
//rounding with 0.05 or 5 intervals
case RoundingType.Rounding005Up:
case RoundingType.Rounding005Down:
t = (rez - Math.Truncate(rez)) * 10;
t = (t - Math.Truncate(t)) * 10;
fractionPart = (fractionPart - Math.Truncate(fractionPart)) * 10;

if (roundingType == RoundingType.Rounding005Down)
t = t >= 5 ? 5 - t : t * -1;
fractionPart = fractionPart >= 5 ? 5 - fractionPart : fractionPart * -1;
else
t = t >= 5 ? 10 - t : 5 - t;
fractionPart = fractionPart >= 5 ? 10 - fractionPart : 5 - fractionPart;

rez += t / 100;
rez += fractionPart / 100;
break;
//rounding with 0.10 intervals
case RoundingType.Rounding01Up:
case RoundingType.Rounding01Down:
t = (rez - Math.Truncate(rez)) * 10;
t = (t - Math.Truncate(t)) * 10;
fractionPart = (fractionPart - Math.Truncate(fractionPart)) * 10;

if (roundingType == RoundingType.Rounding01Down && t == 5)
t = -5;
if (roundingType == RoundingType.Rounding01Down && fractionPart == 5)
fractionPart = -5;
else
t = t < 5 ? t * -1 : 10 - t;
fractionPart = fractionPart < 5 ? fractionPart * -1 : 10 - fractionPart;

rez += t / 100;
rez += fractionPart / 100;
break;
//rounding with 0.50 intervals
case RoundingType.Rounding05:
t = (rez - Math.Truncate(rez)) * 100;
t = t < 25 ? t * -1 : t < 50 || t < 75 ? 50 - t : 100 - t;
fractionPart *= 10;
fractionPart = fractionPart < 25 ? fractionPart * -1 : fractionPart < 50 || fractionPart < 75 ? 50 - fractionPart : 100 - fractionPart;

rez += t / 100;
rez += fractionPart / 100;
break;
//rounding with 1.00 intervals
case RoundingType.Rounding1:
case RoundingType.Rounding1Up:
t = (rez - Math.Truncate(rez)) * 100;
fractionPart *= 10;

if (roundingType == RoundingType.Rounding1Up && t > 0)
if (roundingType == RoundingType.Rounding1Up && fractionPart > 0)
rez = Math.Truncate(rez) + 1;
else
rez = t < 50 ? Math.Truncate(rez) : Math.Truncate(rez) + 1;
rez = fractionPart < 50 ? Math.Truncate(rez) : Math.Truncate(rez) + 1;

break;
case RoundingType.Rounding001:
Expand Down
4 changes: 4 additions & 0 deletions src/Tests/Nop.Services.Tests/Catalog/RoundingHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ public class RoundingHelperTests : ServiceTest
[TestCase(12.363, 12.36, RoundingType.Rounding001)]
[TestCase(12.34, 12.35, RoundingType.Rounding005Up)]
[TestCase(12.36, 12.40, RoundingType.Rounding005Up)]
[TestCase(27.00, 27.00, RoundingType.Rounding005Up)]
[TestCase(27.001, 27.00, RoundingType.Rounding005Up)]
[TestCase(12.34, 12.30, RoundingType.Rounding005Down)]
[TestCase(12.36, 12.35, RoundingType.Rounding005Down)]
[TestCase(12.35, 12.40, RoundingType.Rounding01Up)]
[TestCase(12.36, 12.40, RoundingType.Rounding01Up)]
[TestCase(12.00, 12.00, RoundingType.Rounding01Up)]
[TestCase(12.35, 12.30, RoundingType.Rounding01Down)]
[TestCase(12.36, 12.40, RoundingType.Rounding01Down)]
[TestCase(12.24, 12.00, RoundingType.Rounding05)]
Expand All @@ -26,6 +29,7 @@ public class RoundingHelperTests : ServiceTest
[TestCase(12.50, 13.00, RoundingType.Rounding1)]
[TestCase(12.01, 13.00, RoundingType.Rounding1Up)]
[TestCase(12.99, 13.00, RoundingType.Rounding1Up)]
[TestCase(12.00, 12.00, RoundingType.Rounding1Up)]
public void can_round(decimal valueToRoundig, decimal roundedValue, RoundingType roundingType)
{
valueToRoundig.Round(roundingType).ShouldEqual(roundedValue);
Expand Down

0 comments on commit 130bf67

Please sign in to comment.