Skip to content

Commit 4125d3a

Browse files
committed
Optimized Rounding
1 parent eb6e287 commit 4125d3a

21 files changed

+2531
-532
lines changed

satcfdi/create/compute.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ def __init__(self, decimals):
8787
self.exp = Decimal('0.' + '0' * decimals)
8888
self.offset_margin = Decimal('0.' + '0' * decimals + '5')
8989

90-
def round(self, value):
91-
rounded = self.peak(value)
92-
self.offset += value - rounded
93-
return rounded
94-
9590
def peak(self, value):
9691
if self.offset >= self.offset_margin:
9792
return value.quantize(self.exp, rounding=ROUND_CEILING)
@@ -100,7 +95,9 @@ def peak(self, value):
10095
return round(value, self.decimals)
10196

10297
def __call__(self, value):
103-
return self.round(value)
98+
rounded = self.peak(value)
99+
self.offset += value - rounded
100+
return rounded
104101

105102

106103
def group_impuestos(elements, pfx="", ofx=""):

tests/test_compute.py

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -29,63 +29,63 @@ def test_initialization_with_negative_decimals_raises_error(self):
2929
def test_basic_round_half_up(self):
3030
"""Test basic rounding behavior (ROUND_HALF_UP)"""
3131
rt = RoundTracker(2)
32-
assert rt.round(Decimal('1.234')) == Decimal('1.23')
33-
assert rt.round(Decimal('1.235')) == Decimal('1.24')
34-
assert rt.round(Decimal('1.236')) == Decimal('1.24')
35-
assert rt.round(Decimal('1.236')) == Decimal('1.23') # Repeated to check consistency
36-
assert rt.round(Decimal('1.236')) == Decimal('1.24')
32+
assert rt(Decimal('1.234')) == Decimal('1.23')
33+
assert rt(Decimal('1.235')) == Decimal('1.24')
34+
assert rt(Decimal('1.236')) == Decimal('1.24')
35+
assert rt(Decimal('1.236')) == Decimal('1.23') # Repeated to check consistency
36+
assert rt(Decimal('1.236')) == Decimal('1.24')
3737

3838
def test_round_zero_decimals(self):
3939
"""Test rounding with zero decimal places"""
4040
rt = RoundTracker(0)
41-
assert rt.round(Decimal('1.4')) == Decimal('1')
42-
assert rt.round(Decimal('1.5')) == Decimal('2')
43-
assert rt.round(Decimal('1.6')) == Decimal('2')
44-
assert rt.round(Decimal('1.6')) == Decimal('1') # Repeated to check consistency
45-
assert rt.round(Decimal('1.6')) == Decimal('2')
41+
assert rt(Decimal('1.4')) == Decimal('1')
42+
assert rt(Decimal('1.5')) == Decimal('2')
43+
assert rt(Decimal('1.6')) == Decimal('2')
44+
assert rt(Decimal('1.6')) == Decimal('1') # Repeated to check consistency
45+
assert rt(Decimal('1.6')) == Decimal('2')
4646

4747
def test_round_three_decimals(self):
4848
"""Test rounding with three decimal places"""
4949
rt = RoundTracker(3)
50-
assert rt.round(Decimal('2.3454')) == Decimal('2.345')
51-
assert rt.round(Decimal('2.3455')) == Decimal('2.346')
52-
assert rt.round(Decimal('2.3456')) == Decimal('2.346')
53-
assert rt.round(Decimal('2.3456')) == Decimal('2.345') # Repeated to check consistency
54-
assert rt.round(Decimal('2.3456')) == Decimal('2.346')
50+
assert rt(Decimal('2.3454')) == Decimal('2.345')
51+
assert rt(Decimal('2.3455')) == Decimal('2.346')
52+
assert rt(Decimal('2.3456')) == Decimal('2.346')
53+
assert rt(Decimal('2.3456')) == Decimal('2.345') # Repeated to check consistency
54+
assert rt(Decimal('2.3456')) == Decimal('2.346')
5555

5656
def test_offset_accumulation_positive(self):
5757
"""Test that offset accumulates correctly with positive values"""
5858
rt = RoundTracker(2)
5959
# First round: 0.005 rounds to 0.00, offset becomes 0.005
60-
result1 = rt.round(Decimal('0.005'))
60+
result1 = rt(Decimal('0.005'))
6161
assert result1 == Decimal('0.00')
6262
assert rt.offset == Decimal('0.005')
6363

6464
# Second round: 0.005 rounds to 0.01, offset becomes 0.00 (0.005 + 0.005 - 0.01)
65-
result2 = rt.round(Decimal('0.005'))
65+
result2 = rt(Decimal('0.005'))
6666
assert result2 == Decimal('0.01')
6767
assert rt.offset == Decimal('0.00')
6868

6969
def test_offset_accumulation_negative(self):
7070
"""Test that offset accumulates correctly with negative rounding errors"""
7171
rt = RoundTracker(2)
7272
# 1.994 rounds to 1.99, offset becomes 0.004 (1.994 - 1.99 = 0.004)
73-
result1 = rt.round(Decimal('1.994'))
73+
result1 = rt(Decimal('1.994'))
7474
assert result1 == Decimal('1.99')
7575
assert rt.offset == Decimal('0.004') # Fixed: offset calculation
7676

7777
# 1.994 rounds to 1.99, offset becomes 0.008
78-
result2 = rt.round(Decimal('1.994'))
78+
result2 = rt(Decimal('1.994'))
7979
assert result2 == Decimal('1.99')
8080
assert rt.offset == Decimal('0.008') # Fixed: offset accumulates
8181

8282
# 1.994 rounds to 1.99, offset becomes 0.002
83-
result2 = rt.round(Decimal('1.994'))
83+
result2 = rt(Decimal('1.994'))
8484
assert result2 == Decimal('2.00')
8585
assert rt.offset == Decimal('0.002') # Fixed: offset accumulates
8686

8787
# 1.994 rounds to 1.99, offset becomes 0.002
88-
result2 = rt.round(Decimal('1.996'))
88+
result2 = rt(Decimal('1.996'))
8989
assert result2 == Decimal('2.00')
9090
assert rt.offset == Decimal('-0.002') # Fixed: offset accumulates
9191

@@ -136,24 +136,24 @@ def test_call_method_equivalence(self):
136136
rt2 = RoundTracker(2)
137137

138138
value = Decimal('1.234')
139-
assert rt1(value) == rt2.round(value)
139+
assert rt1(value) == rt2(value)
140140

141141
# Test multiple calls
142142
values = [Decimal('0.005'), Decimal('0.005'), Decimal('1.994')]
143143
results1 = [rt1(v) for v in values]
144-
results2 = [rt2.round(v) for v in values]
144+
results2 = [rt2(v) for v in values]
145145
assert results1 == results2
146146

147147
def test_sequence_of_rounds_with_offset_correction(self):
148148
"""Test a sequence of rounds where offset triggers ceiling/floor rounding"""
149149
rt = RoundTracker(2)
150150

151151
# Accumulate positive offset
152-
rt.round(Decimal('0.004')) # rounds to 0.00, offset = 0.004
153-
rt.round(Decimal('0.004')) # rounds to 0.00, offset = 0.008
152+
rt(Decimal('0.004')) # rounds to 0.00, offset = 0.004
153+
rt(Decimal('0.004')) # rounds to 0.00, offset = 0.008
154154

155155
# Now offset > margin, next round should use ceiling
156-
result = rt.round(Decimal('1.001')) # Should round to 1.01 due to offset
156+
result = rt(Decimal('1.001')) # Should round to 1.01 due to offset
157157
assert result == Decimal('1.01')
158158

159159
# Offset should be adjusted
@@ -163,23 +163,23 @@ def test_sequence_of_rounds_with_offset_correction(self):
163163
def test_round_with_large_values(self):
164164
"""Test rounding with large decimal values"""
165165
rt = RoundTracker(2)
166-
assert rt.round(Decimal('999999.994')) == Decimal('999999.99')
167-
assert rt.round(Decimal('999999.995')) == Decimal('1000000.00')
166+
assert rt(Decimal('999999.994')) == Decimal('999999.99')
167+
assert rt(Decimal('999999.995')) == Decimal('1000000.00')
168168

169169
def test_round_with_negative_values(self):
170170
"""Test rounding with negative values"""
171171
rt = RoundTracker(2)
172-
assert rt.round(Decimal('-1.234')) == Decimal('-1.23')
173-
assert rt.round(Decimal('-1.235')) == Decimal('-1.24')
174-
assert rt.round(Decimal('-1.236')) == Decimal('-1.24')
172+
assert rt(Decimal('-1.234')) == Decimal('-1.23')
173+
assert rt(Decimal('-1.235')) == Decimal('-1.24')
174+
assert rt(Decimal('-1.236')) == Decimal('-1.24')
175175

176176
def test_offset_correction_over_multiple_rounds(self):
177177
"""Test that offset correction works correctly over many rounds"""
178178
rt = RoundTracker(2)
179179

180180
# Add values that would accumulate rounding errors
181181
values = [Decimal('0.333333')] * 3 # 0.333333 * 3 = 0.999999
182-
results = [rt.round(v) for v in values]
182+
results = [rt(v) for v in values]
183183

184184
# First two should round to 0.33, third might round to 0.34 due to offset
185185
assert sum(results) in [Decimal('0.99'), Decimal('1.00')]
@@ -192,9 +192,9 @@ def test_realistic_scenario_currency_rounding(self):
192192
total = Decimal('10.00')
193193
part = total / 3 # 3.333333...
194194

195-
p1 = rt.round(part) # 3.33
196-
p2 = rt.round(part) # 3.33
197-
p3 = rt.round(part) # Should be 3.34 to compensate
195+
p1 = rt(part) # 3.33
196+
p2 = rt(part) # 3.33
197+
p3 = rt(part) # Should be 3.34 to compensate
198198

199199
assert p1 == Decimal('3.33')
200200
assert p2 == Decimal('3.33')
@@ -204,8 +204,8 @@ def test_realistic_scenario_currency_rounding(self):
204204
def test_high_precision_decimals(self):
205205
"""Test with high precision decimal places"""
206206
rt = RoundTracker(6)
207-
assert rt.round(Decimal('1.2345674')) == Decimal('1.234567')
208-
assert rt.round(Decimal('1.2345675')) == Decimal('1.234568')
207+
assert rt(Decimal('1.2345674')) == Decimal('1.234567')
208+
assert rt(Decimal('1.2345675')) == Decimal('1.234568')
209209
assert rt.exp == Decimal('0.000000') # Fixed: exp is '0.' + '0' * 6
210210
assert rt.offset_margin == Decimal('0.0000005')
211211

@@ -227,6 +227,6 @@ def test_high_precision_decimals(self):
227227
def test_roundtracker_parametrized(decimals, value, expected):
228228
"""Parametrized test for various decimal places and values"""
229229
rt = RoundTracker(decimals)
230-
result = rt.round(value)
230+
result = rt(value)
231231
assert result == expected
232232

0 commit comments

Comments
 (0)