1
-
2
1
from decimal import Decimal
2
+ import math
3
3
4
4
# Don't use 'import numpy as np', to avoid accidentally testing
5
5
# the versions in numpy instead of numpy_financial.
6
6
import numpy
7
7
from numpy .testing import (
8
- assert_ , assert_almost_equal , assert_allclose , assert_equal , assert_raises
8
+ assert_ , assert_almost_equal , assert_allclose , assert_equal
9
9
)
10
10
import pytest
11
11
@@ -71,35 +71,6 @@ def test_pmt_decimal(self):
71
71
assert_equal (res [1 ][0 ], tgt [1 ][0 ])
72
72
assert_equal (res [1 ][1 ], tgt [1 ][1 ])
73
73
74
- def test_ppmt (self ):
75
- assert_equal (numpy .round (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 ), 2 ), - 710.25 )
76
-
77
- def test_ppmt_decimal (self ):
78
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
79
- Decimal ('60' ), Decimal ('55000' )),
80
- Decimal ('-710.2541257864217612489830917' ))
81
-
82
- # Two tests showing how Decimal is actually getting at a more exact result
83
- # .23 / 12 does not come out nicely as a float but does as a decimal
84
- def test_ppmt_special_rate (self ):
85
- assert_equal (numpy .round (npf .ppmt (0.23 / 12 , 1 , 60 , 10000000000 ), 8 ),
86
- - 90238044.232277036 )
87
-
88
- def test_ppmt_special_rate_decimal (self ):
89
- # When rounded out to 8 decimal places like the float based test,
90
- # this should not equal the same value as the float, substituted
91
- # for the decimal
92
- def raise_error_because_not_equal ():
93
- assert_equal (
94
- round (npf .ppmt (Decimal ('0.23' ) / Decimal ('12' ), 1 , 60 ,
95
- Decimal ('10000000000' )), 8 ),
96
- Decimal ('-90238044.232277036' ))
97
-
98
- assert_raises (AssertionError , raise_error_because_not_equal )
99
- assert_equal (npf .ppmt (Decimal ('0.23' ) / Decimal ('12' ), 1 , 60 ,
100
- Decimal ('10000000000' )),
101
- Decimal ('-90238044.2322778884413969909' ))
102
-
103
74
def test_npv (self ):
104
75
assert_almost_equal (
105
76
npf .npv (0.05 , [- 15000 , 1500 , 2500 , 3500 , 4500 , 6000 ]),
@@ -172,15 +143,6 @@ def test_when(self):
172
143
assert_equal (npf .pmt (0.08 / 12 , 5 * 12 , 15000. , 0 , 0 ),
173
144
npf .pmt (0.08 / 12 , 5 * 12 , 15000. , 0 , 'end' ))
174
145
175
- # begin
176
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 1 ),
177
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'begin' ))
178
- # end
179
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 ),
180
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'end' ))
181
- assert_equal (npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 0 ),
182
- npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , 'end' ))
183
-
184
146
# begin
185
147
assert_equal (npf .nper (0.075 , - 2000 , 0 , 100000. , 1 ),
186
148
npf .nper (0.075 , - 2000 , 0 , 100000. , 'begin' ))
@@ -224,86 +186,10 @@ def test_decimal_with_when(self):
224
186
npf .pv (Decimal ('0.07' ), Decimal ('20' ), Decimal ('12000' ),
225
187
Decimal ('0' ), 'end' ))
226
188
227
- # begin
228
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
229
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
230
- Decimal ('0' ), Decimal ('1' )),
231
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
232
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
233
- Decimal ('0' ), 'begin' ))
234
- # end
235
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
236
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
237
- Decimal ('0' )),
238
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
239
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
240
- Decimal ('0' ), 'end' ))
241
- assert_equal (npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
242
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
243
- Decimal ('0' ), Decimal ('0' )),
244
- npf .pmt (Decimal ('0.08' ) / Decimal ('12' ),
245
- Decimal ('5' ) * Decimal ('12' ), Decimal ('15000.' ),
246
- Decimal ('0' ), 'end' ))
247
-
248
- # begin
249
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ),
250
- Decimal ('1' ), Decimal ('60' ), Decimal ('55000' ),
251
- Decimal ('0' ), Decimal ('1' )),
252
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
253
- Decimal ('60' ), Decimal ('55000' ),
254
- Decimal ('0' ), 'begin' ))
255
- # end
256
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
257
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' )),
258
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
259
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
260
- 'end' ))
261
- assert_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
262
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
263
- Decimal ('0' )),
264
- npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ), Decimal ('1' ),
265
- Decimal ('60' ), Decimal ('55000' ), Decimal ('0' ),
266
- 'end' ))
267
-
268
189
def test_broadcast (self ):
269
190
assert_almost_equal (npf .nper (0.075 , - 2000 , 0 , 100000. , [0 , 1 ]),
270
191
[21.5449442 , 20.76156441 ], 4 )
271
192
272
- assert_almost_equal (npf .ppmt (0.1 / 12 , list (range (5 )), 24 , 2000 ),
273
- [numpy .nan , - 75.62318601 , - 76.25337923 ,
274
- - 76.88882405 , - 77.52956425 ], 4 )
275
-
276
- assert_almost_equal (npf .ppmt (0.1 / 12 , list (range (5 )), 24 , 2000 , 0 ,
277
- [0 , 0 , 1 , 'end' , 'begin' ]),
278
- [numpy .nan , - 75.62318601 , - 75.62318601 ,
279
- - 76.88882405 , - 76.88882405 ], 4 )
280
-
281
- def test_broadcast_decimal (self ):
282
- # Use almost equal because precision is tested in the explicit tests,
283
- # this test is to ensure broadcast with Decimal is not broken.
284
- assert_almost_equal (npf .ppmt (Decimal ('0.1' ) / Decimal ('12' ),
285
- list (range (1 , 5 )), Decimal ('24' ),
286
- Decimal ('2000' )),
287
- [Decimal ('-75.62318601' ),
288
- Decimal ('-76.25337923' ), Decimal ('-76.88882405' ),
289
- Decimal ('-77.52956425' )], 4 )
290
-
291
- result = npf .ppmt (
292
- Decimal ('0.1' ) / Decimal ('12' ),
293
- list (range (1 , 5 )),
294
- Decimal ('24' ),
295
- Decimal ('2000' ),
296
- Decimal ('0' ),
297
- [Decimal ('0' ), Decimal ('1' ), 'end' , 'begin' ]
298
- )
299
- desired = [
300
- Decimal ('-75.62318601' ),
301
- Decimal ('-75.62318601' ),
302
- Decimal ('-76.88882405' ),
303
- Decimal ('-76.88882405' )
304
- ]
305
- assert_almost_equal (result , desired , decimal = 4 )
306
-
307
193
308
194
class TestNper :
309
195
def test_basic_values (self ):
@@ -329,6 +215,129 @@ def test_no_interest(self):
329
215
assert_ (npf .nper (0 , - 100 , 1000 ) == 10 )
330
216
331
217
218
+ class TestPpmt :
219
+ def test_float (self ):
220
+ assert_allclose (
221
+ npf .ppmt (0.1 / 12 , 1 , 60 , 55000 ),
222
+ - 710.25 ,
223
+ rtol = 1e-4
224
+ )
225
+
226
+ def test_decimal (self ):
227
+ result = npf .ppmt (
228
+ Decimal ('0.1' ) / Decimal ('12' ),
229
+ Decimal ('1' ),
230
+ Decimal ('60' ),
231
+ Decimal ('55000' )
232
+ )
233
+ assert_equal (
234
+ result ,
235
+ Decimal ('-710.2541257864217612489830917' ),
236
+ )
237
+
238
+ @pytest .mark .parametrize ('when' , [1 , 'begin' ])
239
+ def test_when_is_begin (self , when ):
240
+ assert_allclose (
241
+ npf .ppmt (0.1 / 12 , 1 , 60 , 55000 , 0 , when ),
242
+ - 1158.929712 , # Computed using Google Sheet's PPMT
243
+ rtol = 1e-9 ,
244
+ )
245
+
246
+ @pytest .mark .parametrize ('when' , [None , 0 , 'end' ])
247
+ def test_when_is_end (self , when ):
248
+ args = (0.1 / 12 , 1 , 60 , 55000 , 0 )
249
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
250
+ assert_allclose (
251
+ result ,
252
+ - 710.254126 , # Computed using Google Sheet's PPMT
253
+ rtol = 1e-9 ,
254
+ )
255
+
256
+ @pytest .mark .parametrize ('when' , [Decimal ('1' ), 'begin' ])
257
+ def test_when_is_begin_decimal (self , when ):
258
+ result = npf .ppmt (
259
+ Decimal ('0.08' ) / Decimal ('12' ),
260
+ Decimal ('1' ),
261
+ Decimal ('60' ),
262
+ Decimal ('15000.' ),
263
+ Decimal ('0' ),
264
+ when
265
+ )
266
+ assert_almost_equal (
267
+ result ,
268
+ Decimal ('-302.131703' ), # Computed using Google Sheet's PPMT
269
+ decimal = 5 ,
270
+ )
271
+
272
+ @pytest .mark .parametrize ('when' , [None , Decimal ('0' ), 'end' ])
273
+ def test_when_is_end_decimal (self , when ):
274
+ args = (
275
+ Decimal ('0.08' ) / Decimal ('12' ),
276
+ Decimal ('1' ),
277
+ Decimal ('60' ),
278
+ Decimal ('15000.' ),
279
+ Decimal ('0' )
280
+ )
281
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
282
+ assert_almost_equal (
283
+ result ,
284
+ Decimal ('-204.145914' ), # Computed using Google Sheet's PPMT
285
+ decimal = 5 ,
286
+ )
287
+
288
+ @pytest .mark .parametrize ('args' , [
289
+ (0.1 / 12 , 0 , 60 , 15000 ),
290
+ (Decimal ('0.012' ), Decimal ('0' ), Decimal ('60' ), Decimal ('15000' ))
291
+ ])
292
+ def test_invalid_per (self , args ):
293
+ # Note that math.isnan() handles Decimal NaN correctly.
294
+ assert math .isnan (npf .ppmt (* args ))
295
+
296
+ @pytest .mark .parametrize ('when, desired' , [
297
+ (
298
+ None ,
299
+ [- 75.62318601 , - 76.25337923 , - 76.88882405 , - 77.52956425 ],
300
+ ), (
301
+ [0 , 1 , 'end' , 'begin' ],
302
+ [- 75.62318601 , - 75.62318601 , - 76.88882405 , - 76.88882405 ],
303
+ )
304
+ ])
305
+ def test_broadcast (self , when , desired ):
306
+ args = (0.1 / 12 , numpy .arange (1 , 5 ), 24 , 2000 , 0 )
307
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
308
+ assert_allclose (result , desired , rtol = 1e-5 )
309
+
310
+ @pytest .mark .parametrize ('when, desired' , [
311
+ (
312
+ None ,
313
+ [
314
+ Decimal ('-75.62318601' ),
315
+ Decimal ('-76.25337923' ),
316
+ Decimal ('-76.88882405' ),
317
+ Decimal ('-77.52956425' )
318
+ ],
319
+ ), (
320
+ [Decimal ('0' ), Decimal ('1' ), 'end' , 'begin' ],
321
+ [
322
+ Decimal ('-75.62318601' ),
323
+ Decimal ('-75.62318601' ),
324
+ Decimal ('-76.88882405' ),
325
+ Decimal ('-76.88882405' )
326
+ ]
327
+ )
328
+ ])
329
+ def test_broadcast_decimal (self , when , desired ):
330
+ args = (
331
+ Decimal ('0.1' ) / Decimal ('12' ),
332
+ numpy .arange (1 , 5 ),
333
+ Decimal ('24' ),
334
+ Decimal ('2000' ),
335
+ Decimal ('0' )
336
+ )
337
+ result = npf .ppmt (* args ) if when is None else npf .ppmt (* args , when )
338
+ assert_almost_equal (result , desired , decimal = 8 )
339
+
340
+
332
341
class TestIpmt :
333
342
def test_float (self ):
334
343
assert_allclose (
@@ -353,7 +362,6 @@ def test_when_is_end(self, when):
353
362
result = npf .ipmt (0.1 / 12 , 1 , 24 , 2000 , 0 , when )
354
363
assert_allclose (result , - 16.666667 , rtol = 1e-6 )
355
364
356
-
357
365
@pytest .mark .parametrize ('when' , [Decimal ('1' ), 'begin' ])
358
366
def test_when_is_begin_decimal (self , when ):
359
367
result = npf .ipmt (
0 commit comments