summaryrefslogtreecommitdiff
path: root/finance
diff options
context:
space:
mode:
authorxengineering <me@xengineering.eu>2024-09-04 21:09:42 +0200
committerxengineering <me@xengineering.eu>2024-09-08 17:21:32 +0200
commit226f5afa968ead223baa5a1b0fafb481f9761f0f (patch)
treeed54889c22ee43596b48085485a6985189d574dd /finance
parent877b50ef8802f8b59d81ccabcab22fe185e898d7 (diff)
downloadfinance-py-226f5afa968ead223baa5a1b0fafb481f9761f0f.tar
finance-py-226f5afa968ead223baa5a1b0fafb481f9761f0f.tar.zst
finance-py-226f5afa968ead223baa5a1b0fafb481f9761f0f.zip
Refactor Flow.integrate()
This refactoring introduces a generator function supporting the integration. It creates datetime candidates where it can be checked if they are in the time interval given to the integration method. Furthermore a numerical improvement was made. The Flow.integrate() function now checks candidates from the helper function and sums the matching candidates up as an integer. After checking all candidates the integer is converted to a decimal and multiplied by Flow.amount. This is more accurate because in Python decimal calculation not numbers or calculations are rounded, just the result of a calculation. Looping over the candidates and adding amount each time thus involves a rounding operation per candidate. The new algorithm has exactly one rounding operation.
Diffstat (limited to 'finance')
-rw-r--r--finance/flow.py31
1 files changed, 16 insertions, 15 deletions
diff --git a/finance/flow.py b/finance/flow.py
index fb28228..a5817af 100644
--- a/finance/flow.py
+++ b/finance/flow.py
@@ -1,6 +1,7 @@
import dataclasses
from datetime import datetime
from decimal import Decimal
+from typing import Generator
@dataclasses.dataclass(kw_only=True, frozen=True)
@@ -12,22 +13,22 @@ class Flow:
def integrate(self, start: datetime, end: datetime) -> Decimal:
"""Integrate the flow between two dates to an amount of money"""
- retval = Decimal(0.0)
+ payments: int = 0
- current = datetime(start.year, start.month, 1)
-
- if start == current:
- retval += self.amount
+ for candidate in monthly_candidates(start):
+ if start <= candidate <= end:
+ payments += 1
+ if candidate > end:
+ break
- while True:
- if current.month == 12:
- current = datetime(current.year + 1, 1, 1)
- else:
- current = datetime(current.year, current.month + 1, 1)
+ return self.amount * Decimal(payments)
- if current <= end:
- retval += self.amount
- else:
- break
- return retval
+def monthly_candidates(start: datetime) -> Generator[datetime, None, None]:
+ current = datetime(start.year, start.month, 1)
+ while True:
+ yield current
+ if current.month == 12:
+ current = datetime(current.year + 1, 1, 1)
+ else:
+ current = datetime(current.year, current.month + 1, 1)