/
Decimal_round_specs.cs
160 lines (143 loc) · 4.93 KB
/
Decimal_round_specs.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
namespace Decimal_round_specs;
public class Rounds
{
[Test]
public void To_even_by_default_for_positive()
{
var rounded = 24.5m.Round();
rounded.Should().Be(24m);
}
[Test]
public void To_even_by_default_for_negative()
{
var rounded = -24.5m.Round();
rounded.Should().Be(-24m);
}
/// <remarks>Use strings as doubles lack precision.</remarks>
[TestCase("123456789.1234567890", +10)]
[TestCase("123456789.123456789", +9)]
[TestCase("123456789.12345679", +8)]
[TestCase("123456789.1234568", +7)]
[TestCase("123456789.123457", +6)]
[TestCase("123456789.12346", +5)]
[TestCase("123456789.1235", +4)]
[TestCase("123456789.123", +3)]
[TestCase("123456789.12", +2)]
[TestCase("123456789.1", +1)]
[TestCase("123456789", +0)]
[TestCase("123456790", -1)]
[TestCase("123456800", -2)]
[TestCase("123457000", -3)]
[TestCase("123460000", -4)]
[TestCase("123500000", -5)]
[TestCase("123000000", -6)]
[TestCase("120000000", -7)]
[TestCase("100000000", -8)]
[TestCase(0, -9)]
public void Takes_digits_into_account(decimal exp, int digits)
{
var act = 123456789.123456789m.Round(digits, DecimalRounding.AwayFromZero);
act.Should().Be(exp);
}
// Halfway/nearest rounding
[TestCase(-26, -25.5, DecimalRounding.AwayFromZero)]
[TestCase(+26, +25.5, DecimalRounding.AwayFromZero)]
[TestCase(-25, -25.5, DecimalRounding.TowardsZero)]
[TestCase(+25, +25.5, DecimalRounding.TowardsZero)]
[TestCase(+26, +25.5, DecimalRounding.ToEven)]
[TestCase(+24, +24.5, DecimalRounding.ToEven)]
[TestCase(+25, +25.5, DecimalRounding.ToOdd)]
[TestCase(+25, +24.5, DecimalRounding.ToOdd)]
[TestCase(-25, -25.5, DecimalRounding.Up)]
[TestCase(+26, +25.5, DecimalRounding.Up)]
[TestCase(-26, -25.5, DecimalRounding.Down)]
[TestCase(+25, +25.5, DecimalRounding.Down)]
// Direct rounding
[TestCase(-26, -25.1, DecimalRounding.DirectAwayFromZero)]
[TestCase(+26, +25.1, DecimalRounding.DirectAwayFromZero)]
[TestCase(-25, -25.1, DecimalRounding.DirectTowardsZero)]
[TestCase(+25, +25.1, DecimalRounding.DirectTowardsZero)]
[TestCase(-25, -25.1, DecimalRounding.Ceiling)]
[TestCase(+26, +25.1, DecimalRounding.Ceiling)]
[TestCase(-26, -25.1, DecimalRounding.Floor)]
[TestCase(+25, +25.1, DecimalRounding.Floor)]
[TestCase(-25, -25.1, DecimalRounding.Truncate)]
[TestCase(+25, +25.1, DecimalRounding.Truncate)]
public void Takes_strategy_into_account(decimal rounded, decimal value, DecimalRounding mode)
{
var act = value.Round(0, mode);
act.Should().Be(rounded);
}
[TestCase(17.1)]
[TestCase(17.3)]
[TestCase(17.6)]
[TestCase(17.8)]
public void Stochastic_within_margin(decimal value)
{
var runs = 10_000;
var sum = 0m;
for (var i = 0; i < runs; i++)
{
var rounded = value.Round(0, DecimalRounding.StochasticRounding);
(rounded == 17 || rounded == 18).Should().BeTrue();
sum += rounded;
}
var avg = sum / runs;
avg.Should().BeApproximately(value, 0.05m);
}
[Test]
public void Tie_breaking_within_margin()
{
var value = 17.5m;
var runs = 100_000;
var sum = 0m;
for (var i = 0; i < runs; i++)
{
var rounded = value.Round(0, DecimalRounding.RandomTieBreaking);
(rounded == 17 || rounded == 18).Should().BeTrue();
sum += rounded;
}
var avg = sum / runs;
avg.Should().BeApproximately(value, 0.05m);
}
[Test]
public void Supports_non_leading_decimal_zeros()
{
// initializes a decimal with scale of 4, instead of 0.
var value = decimal.Parse("1000.0000", CultureInfo.InvariantCulture);
var rounded = value.Round(-2);
rounded.Should().Be(1000m);
}
[Test]
public void Round_ALotOf3s_WithoutIssues()
{
var value = 9_876_543_210m + 1m / 3m;
var rounded = value.Round(-9);
var expected = 10_000_000_000m;
rounded.Should().Be(expected);
}
}
public class Rounds_to_multiple
{
[Test]
public void To_even_by_default_for_positive()
{
var rounded = 24.5m.RoundToMultiple(1m);
rounded.Should().Be(24m);
}
[Test]
public void To_even_by_default_for_negative()
{
var rounded = -26.5m.RoundToMultiple(1m);
rounded.Should().Be(-26m);
}
[TestCase(150.0, 125.0, 50, DecimalRounding.AwayFromZero)]
[TestCase(125.0, 123.0, 5, DecimalRounding.AwayFromZero)]
[TestCase(123.25, 123.3085, 0.25, DecimalRounding.AwayFromZero)]
[TestCase(666, 666, 3, DecimalRounding.AwayFromZero)]
public void Supports_rouding_stratgies(decimal rounded, decimal value, decimal factor, DecimalRounding mode)
{
var act = value.RoundToMultiple(factor, mode);
act.Should().Be(rounded);
}
}