2012-07-31 20:56:11 +00:00
|
|
|
<?php
|
|
|
|
|
2016-08-31 17:18:12 +00:00
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
|
2012-07-31 20:56:11 +00:00
|
|
|
|
2016-08-31 17:18:12 +00:00
|
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Financial;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
|
2017-11-08 15:48:01 +00:00
|
|
|
use PHPUnit\Framework\TestCase;
|
2016-08-14 04:08:43 +00:00
|
|
|
|
2017-11-08 15:48:01 +00:00
|
|
|
class FinancialTest extends TestCase
|
2012-07-31 20:56:11 +00:00
|
|
|
{
|
2020-04-27 10:28:36 +00:00
|
|
|
protected function setUp(): void
|
2012-07-31 20:56:11 +00:00
|
|
|
{
|
2016-08-14 04:08:43 +00:00
|
|
|
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerAMORDEGRC
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testAMORDEGRC($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::AMORDEGRC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerAMORDEGRC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/AMORDEGRC.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerAMORLINC
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testAMORLINC($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::AMORLINC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerAMORLINC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/AMORLINC.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPDAYBS
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPDAYBS($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPDAYBS(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPDAYBS()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPDAYBS.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPDAYS
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPDAYS($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPDAYS(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPDAYS()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPDAYS.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPDAYSNC
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPDAYSNC($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPDAYSNC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPDAYSNC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPDAYSNC.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPNCD
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPNCD($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPNCD(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPNCD()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPNCD.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPNUM
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPNUM($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPNUM(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPNUM()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPNUM.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCOUPPCD
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCOUPPCD($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::COUPPCD(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCOUPPCD()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/COUPPCD.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCUMIPMT
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCUMIPMT($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::CUMIPMT(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCUMIPMT()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/CUMIPMT.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerCUMPRINC
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testCUMPRINC($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::CUMPRINC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerCUMPRINC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/CUMPRINC.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerDB
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testDB($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::DB(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerDB()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/DB.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerDDB
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testDDB($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::DDB(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerDDB()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/DDB.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerDISC
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testDISC($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::DISC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerDISC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/DISC.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerDOLLARDE
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testDOLLARDE($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::DOLLARDE(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerDOLLARDE()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/DOLLARDE.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerDOLLARFR
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testDOLLARFR($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::DOLLARFR(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerDOLLARFR()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/DOLLARFR.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerEFFECT
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testEFFECT($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::EFFECT(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerEFFECT()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/EFFECT.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerFV
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testFV($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::FV(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerFV()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/FV.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerFVSCHEDULE
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testFVSCHEDULE($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::FVSCHEDULE(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerFVSCHEDULE()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/FVSCHEDULE.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerINTRATE
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testINTRATE($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::INTRATE(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerINTRATE()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/INTRATE.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerIPMT
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testIPMT($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::IPMT(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerIPMT()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/IPMT.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerIRR
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testIRR($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::IRR(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerIRR()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/IRR.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerISPMT
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testISPMT($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::ISPMT(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerISPMT()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/ISPMT.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerMIRR
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testMIRR($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::MIRR(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerMIRR()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/MIRR.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerNOMINAL
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testNOMINAL($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::NOMINAL(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerNOMINAL()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/NOMINAL.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerNPER
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testNPER($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::NPER(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerNPER()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/NPER.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerNPV
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testNPV($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::NPV(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerNPV()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/NPV.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerPRICE
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testPRICE($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::PRICE(...$args);
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-7);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerPRICE()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/PRICE.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider providerPRICE3
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testPRICE3($expectedResult, ...$args)
|
|
|
|
{
|
|
|
|
// These results (PRICE function with basis codes 2 and 3)
|
|
|
|
// agree with published algorithm, LibreOffice, and Gnumeric.
|
|
|
|
// They do not agree with Excel.
|
|
|
|
$result = Financial::PRICE(...$args);
|
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-7);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function providerPRICE3()
|
|
|
|
{
|
2020-05-17 10:52:34 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/PRICE3.php';
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-22 18:17:04 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider providerPRICEDISC
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testPRICEDISC($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::PRICEDISC(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerPRICEDISC()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/PRICEDISC.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerPV
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testPV($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::PV(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerPV()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/PV.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
2012-07-31 20:56:11 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider providerRATE
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2017-01-23 05:49:10 +00:00
|
|
|
public function testRATE($expectedResult, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::RATE(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerRATE()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/RATE.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerXIRR
|
2017-01-23 05:49:10 +00:00
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
2019-09-26 13:58:28 +00:00
|
|
|
* @param mixed $message
|
2012-07-31 20:56:11 +00:00
|
|
|
*/
|
2019-09-26 13:58:28 +00:00
|
|
|
public function testXIRR($expectedResult, $message, ...$args)
|
2015-05-17 13:00:02 +00:00
|
|
|
{
|
2017-01-23 05:49:10 +00:00
|
|
|
$result = Financial::XIRR(...$args);
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
if (is_numeric($result) && is_numeric($expectedResult)) {
|
|
|
|
if ($expectedResult != 0) {
|
|
|
|
$frac = $result / $expectedResult;
|
|
|
|
if ($frac > 0.999999 && $frac < 1.000001) {
|
|
|
|
$result = $expectedResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self::assertEquals($expectedResult, $result, $message);
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
|
|
|
|
public function providerXIRR()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/XIRR.php';
|
2015-05-17 13:00:02 +00:00
|
|
|
}
|
2018-07-22 18:17:04 +00:00
|
|
|
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider providerXNPV
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
* @param mixed $message
|
|
|
|
*/
|
|
|
|
public function testXNPV($expectedResult, $message, ...$args)
|
|
|
|
{
|
|
|
|
$result = Financial::XNPV(...$args);
|
|
|
|
if (is_numeric($result) && is_numeric($expectedResult)) {
|
|
|
|
if ($expectedResult != 0) {
|
|
|
|
$frac = $result / $expectedResult;
|
|
|
|
if ($frac > 0.999999 && $frac < 1.000001) {
|
|
|
|
$result = $expectedResult;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self::assertEquals($expectedResult, $result, $message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function providerXNPV()
|
|
|
|
{
|
2020-05-17 10:52:34 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/XNPV.php';
|
Fix RATE, PRICE, XIRR, and XNPV Functions (#1456)
There were about 20 skipped tests for RATE and PRICE marked
"This test should be fixed". This change does that by fixing
the code for those functions, validating the existing tests,
and adding new ones. XIRR and XNPV are also substantially changed.
As part of this change, the following functions also have minor changes:
- isValidFrequency
- COUPDAYBS
- COUPNUM (additional tests)
- DB
- DDB
PhpUnit reports 100% coverage for all the changed functions.
Since I was dealing with skipped tests, I also fixed
tests/PhpSpreadsheetTests/Writer/Xlsx/LocaleFloatsTest,
which was being skipped in Windows. I also delete the temporary
file which it creates.
There is now only one remaining test which is skipped -
ODS Reader is not complete enough to run some tests against it.
Unfortunately, that test is too complicated for me to deal with now.
In researching this change, I found several places in the code where special code was added for Gnumeric claiming:
- Gnumeric does not handle free-format string dates
- Gnumeric adds extra options, not available in Excel,
for the frequency parameter for functions such as YIELD
- Gnumeric rounds the results for DB and DDB to 2 decimal places
None of these claims is true, at least not on a recent version
of Gnumeric, and the code which supports these differences is removed.
There did not appear to be any tests targeted for
these supposed properties of Gnumeric.
The PRICE function needed relatively minor changes - mostly
additional tests for invalid input. The main problem with the PRICE
tests is that Excel appears to have a bug. The algorithm is published:
https://support.office.com/en-us/article/price-function-3ea9deac-8dfa-436f-a7c8-17ea02c21b0a
The results that Excel returns for basis codes 2 and 3 appear to be
incorrect in many cases. I have segregated these tests into a
new test PRICE3. The results of these tests agree with the published
algorithm, and to the results for LibreOffice and Gnumeric.
The results returned by Excel do not agree with them.
The tests which remain in the test PRICE all use basis codes other
than 2 or 3, and all agree with Excel, LibreOffice, and Gnumeric.
For the RATE function, there appears to be a problem with how the
secant method was implemented. I studied the implementation of RATE
in Python numpy, and adapted its implementation of secant method.
The results now agree with numpy, and, more important, with Excel.
XIRR, which calls XNPV, permits its dates to be earlier than the
start date, whereas XNPV does not. I dealt with this by renaming
the existing XNPV function to xnpvOrdered, adding a parameter to
indicate whether start date has to be earliest. XNPV calls the new
function with that parameter set to TRUE, and XIRR calls it with
the parameter set to FALSE. Some additional error checking was
added to xnpvOrdered, and also to XIRR. XIRR tests benefited
from increasing the value of FINANCIAL_MAX_ITERATIONS.
Finally, since this change is very test-related:
samples/Basic/13_CalculationCyclicFormulae
PhpUnit started reporting an error like "too much regression".
The test deals with an infinite cyclic formula, and allowed
the calculation engine to run for 100 cycles. The actual number of cycles
seems irrelevant for the purpose of this test. I changed it to 15,
and PhpUnit no longer complains.
2020-05-17 10:50:01 +00:00
|
|
|
}
|
|
|
|
|
2018-07-22 18:17:04 +00:00
|
|
|
/**
|
|
|
|
* @dataProvider providerPDURATION
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testPDURATION($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::PDURATION(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerPDURATION()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/PDURATION.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerRRI
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testRRI($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::RRI(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerRRI()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/RRI.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerSLN
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testSLN($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::SLN(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerSLN()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/SLN.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @dataProvider providerSYD
|
|
|
|
*
|
|
|
|
* @param mixed $expectedResult
|
|
|
|
*/
|
|
|
|
public function testSYD($expectedResult, array $args)
|
|
|
|
{
|
|
|
|
$result = Financial::SYD(...$args);
|
2020-04-27 10:28:36 +00:00
|
|
|
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function providerSYD()
|
|
|
|
{
|
2020-05-17 09:35:55 +00:00
|
|
|
return require 'tests/data/Calculation/Financial/SYD.php';
|
2018-07-22 18:17:04 +00:00
|
|
|
}
|
2012-07-31 20:56:11 +00:00
|
|
|
}
|