mirror of
https://github.com/Dolibarr/dolibarr.git
synced 2025-02-20 13:46:52 +01:00
NEW : Library including math and financial functions (#25035)
This commit is contained in:
parent
9274f7f507
commit
9ef5d4ae2c
|
|
@ -26,6 +26,7 @@ PHP libraries:
|
|||
EvalMath 1.0 BSD Yes Safe math expressions evaluation
|
||||
Escpos-php 3.0 MIT License Yes Thermal receipt printer library, for use with ESC/POS compatible printers
|
||||
GeoIP2 0.2.0 Apache License 2.0 Yes Lib to make geoip convert
|
||||
MathPHP 2.8.1 MIT License Yes Modern math library for PHP
|
||||
Mobiledetect 2.8.41 MIT License Yes Detect mobile devices browsers
|
||||
NuSoap 0.9.5 LGPL 2.1+ Yes Library to develop SOAP Web services (not into rpm and deb package)
|
||||
PEAR Mail_MIME 1.8.9 BSD Yes NuSoap dependency
|
||||
|
|
|
|||
960
htdocs/includes/markrogoyski/math-php/CHANGELOG.md
Normal file
960
htdocs/includes/markrogoyski/math-php/CHANGELOG.md
Normal file
|
|
@ -0,0 +1,960 @@
|
|||
# MathPHP Change Log
|
||||
|
||||
## v2.8.1 - 2023-05-18
|
||||
|
||||
### Improvements
|
||||
* Internal improvements to improve conformance with static analysis tools
|
||||
|
||||
## v2.8.0 - 2023-05-07
|
||||
|
||||
### New Features
|
||||
* Matrix `rowAddVector`
|
||||
* Matrix `columnAddVector`
|
||||
|
||||
### Improvements
|
||||
* Better error handling and exception message in `Sequence\NonIntenger::hyperharmonic`
|
||||
* Internal code improvements to conform to static analysis checks
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Helper method names changed (public abstract methods but not part of published interface)
|
||||
* `NumericalDifferentiation::isTargetInPoints` changed to `assertTargetInPoints`
|
||||
* `NumericalDifferentiation::isSpacingConstant` changed to `assertSpacingConstant`
|
||||
|
||||
## v2.7.0 - 2022-12-31
|
||||
|
||||
### Improvements
|
||||
* Improved algorithm for `regularizedIncompleteBeta`: Addresses issue 458
|
||||
* Issue 456: Improved PHPDoc blocks: Changed "number" to "int|float"
|
||||
* Added PHP 8.2 for CI test target
|
||||
|
||||
## v2.6.0 - 2022-04-10
|
||||
|
||||
### Improvements
|
||||
* `Average::truncatedMean` behavior at 50% trim made consistent
|
||||
* PHP 8.1 compatibility improvements
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
# `Average::truncatedMean` throws exception if trim percent greater than 50% rather than error or unpredictable results.
|
||||
|
||||
## v2.5.0 - 2021-11-21
|
||||
|
||||
### New Features
|
||||
* Special function `logbeta`
|
||||
* Special function `logGamma`
|
||||
* Special function `logGammaCorr`
|
||||
* Special function `stirlingError`
|
||||
|
||||
### Improvements
|
||||
* Improvements in StudentT continuous distribution
|
||||
* Improvements in special function `gamma`
|
||||
* Improvements in special function `beta`
|
||||
|
||||
### Bug Fixes
|
||||
* Issue 393 (regularizedIncompleteBeta NAN)
|
||||
* Issue 429 (Linear regression CI division by zero)
|
||||
|
||||
## v2.4.0 - 2021-07-27
|
||||
|
||||
### New Features
|
||||
* Complex Exponential (`exp`)
|
||||
* Complex Exponentiation (`pow`)
|
||||
* Zipf's Law Discrete Distribution
|
||||
* Generalized harmonic non-integer sequence
|
||||
|
||||
### Improvements
|
||||
* Fixed Complex `polarForm` to compute the right values
|
||||
* Fixed `hyperharnomic` non-integer sequence. Previously was computing the wrong thing
|
||||
* Fixed how `ArbitraryInterger` handles `pow` of negative exponents
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Complex `polarForm` now returns an array rather than a Complex number, as the Complex return was incorrect
|
||||
* Interface to `hyperharmonic` non-integer sequence changed due to previous implementation being incorrect
|
||||
|
||||
## v2.3.0 - 2021-07-14
|
||||
|
||||
### New Features
|
||||
* Matrix SVD (Singular Value Decomposition)
|
||||
* Polynomial companion matrix
|
||||
|
||||
## v2.2.0 - 2021-07-11
|
||||
|
||||
### New Features
|
||||
* PLS (Partial Least Squares Regression)
|
||||
|
||||
### Improvements
|
||||
* Add custom `__debugInfo` to `NumericMatrix`
|
||||
|
||||
## v2.1.0 - 2021-07-07
|
||||
|
||||
### New Features
|
||||
* Quaternion numbers
|
||||
|
||||
## v2.0.0 - 2021-05-09
|
||||
|
||||
### New Features
|
||||
* Matrix Improvements
|
||||
* `walk` method to map a function to all values without mutation or returning a value
|
||||
* `MatrixFactory` creates more matrix types
|
||||
* `MatrixFactory::createNumeric` to create `NumericMatrix` types
|
||||
* `MatrixFactory::createFromRowVector`
|
||||
* `MatrixFactory::createFromColumnVector`
|
||||
* Internal `ObjectMatrix` improvements
|
||||
* Add `trace`
|
||||
* Add `scalarMultiply`
|
||||
* Add initial `ComplexMatrix`
|
||||
* Sample data People
|
||||
|
||||
### Improvements
|
||||
* Bug fixes
|
||||
* Issue 414 fixed - PCA/Eigenvalue convergence
|
||||
* Issue 413 fixed - matrix solve with singular matrix using RREF
|
||||
|
||||
## Migration - Upgrading to v2.0 from v1.0
|
||||
* PHP minimum version now 7.2 (was 7.0)
|
||||
* Deprecated code removed (backwards-incompatible change)
|
||||
* `MathPHP\Statistics\Distance::kullbackLeiblerDivergence` removed (Use `MathPHP\Statistics\Divergence::kullbackLeibler` instead)
|
||||
* `MathPHP\Statistics\Distance::jensenShannonDivergence` removed (Use `MathPHP\Statistics\Divergence::jensenShannon` instead)
|
||||
* Matrix Decompositions no longer implement `\ArrayAccess` interface to access decomposition matrixes. Use properties instead.
|
||||
* `MathPHP\LinearAlgebra\Decomposition\Cholesky`
|
||||
* `$cholesky['L']`, `$cholesky['Lᵀ']`, `$cholesky['LT']` removed, use `$cholesky->L`, `$cholesky->Lᵀ`, `$cholesky->LT` instead.
|
||||
* `MathPHP\LinearAlgebra\Decomposition\Crout`
|
||||
* `$crout['L']`, `$crout['U']` removed, use `$crout->L`, `$crout->U` instead.
|
||||
* `MathPHP\LinearAlgebra\Decomposition\LU`
|
||||
* `$LU['L']`, `LU['U']`, `LU['P']` removed, use `$LU->L`, `$LU->U`, `$LU->P` instead.
|
||||
* `MathPHP\LinearAlgebra\Decomposition\QR`
|
||||
* `$QR['Q']`, `$QR['R']` removed, use `$QR->Q`, `$QR->R` instead.
|
||||
* Methods renamed (backwards-incompatible change)
|
||||
* `MathPHP\Statistics\Distance::bhattacharyyaDistance` renamed to `MathPHP\Statistics\Distance::bhattacharyya`
|
||||
* `MathPHP\Statistics\Distance::hellingerDistance` renamed to `MathPHP\Statistics\Distance::hellinger`
|
||||
* Moved Functionality (backwards-incompatible change)
|
||||
* `MathPHP\Functions\Polynomial` moved to `MathPHP\Expression\Polynomial`
|
||||
* `MathPHP\Functions\Piecewise` moved to `MathPHP\Expression\Piecewise`
|
||||
* Matrix internal refactoring
|
||||
* Note: These changes will not affect any client code as long as matrices were created using `MatrixFactory`.
|
||||
* `Matrix` is not a base abstract class for all matrix classes to extend
|
||||
* `Matrix` renamed `NumericMatrix`
|
||||
* `Matrix` base method `createZeroValue`
|
||||
* Use case is various `ObjectMatrix` classes that implement `ObjectArithmetic`
|
||||
* `RowVector` removed. Use `MatrixFactory::createFromRowVector` instead
|
||||
* `ColumnVector` removed. Use `MatrixFactory::createFromColumnVector` instead
|
||||
|
||||
## v1.11.0 - 2021-05-09
|
||||
|
||||
### Improvements
|
||||
* Bugfix (Issue 413): Matrix solve with singular matrix using RREF
|
||||
* Bugfix (Issue 414): PCA/Eigenvalue convergence
|
||||
|
||||
## v1.10.0 - 2020-12-19
|
||||
|
||||
### Improvements
|
||||
* Bugfix (Issue 356): Fix Finance IRR NANs
|
||||
|
||||
## v1.9.0 - 2020-12-13
|
||||
|
||||
### New Features
|
||||
* Vector min and max
|
||||
* Arithmetic isqrt (integer square root)
|
||||
|
||||
### Improvements
|
||||
* Remove Travis CI (Moved CI to Github Actions in v1.8.0 release)
|
||||
* Rearrange non-code files
|
||||
|
||||
## v1.8.0 - 2020-12-11
|
||||
|
||||
### Improvements
|
||||
* Improve permutations algorithm to be more efficient and more numerically stable
|
||||
* Qualify PHP function names with root namespace
|
||||
* Move CI to Github Actions
|
||||
|
||||
## v1.7.0 - 2020-11-15
|
||||
|
||||
### New Features
|
||||
* Algebra linear equation of one variable
|
||||
* Rational number inverse
|
||||
* Rational number pow
|
||||
|
||||
### Improvements
|
||||
* Improve combinations algorithm to be more efficient and more numerically stable
|
||||
* Internal Matrix class reorganization
|
||||
|
||||
## v1.6.0 - 2020-10-22
|
||||
|
||||
### New Features
|
||||
* Special function regularized lower incomplete gamma
|
||||
* Cereal sample data set
|
||||
|
||||
### Improvements
|
||||
* Define boundary condition for lower incomplete gamma function
|
||||
|
||||
## v1.5.0 - 2020-10-12
|
||||
|
||||
### New Features
|
||||
* Matrix LU solve
|
||||
* Matrix QR solve
|
||||
|
||||
### Improvements
|
||||
* Bugfix (Issue 386) Matrix solve improvements
|
||||
* Matrix solve has optional method parameter to force a solve method
|
||||
* Bugfix ArbitraryInteger multiplication sign not taken into account
|
||||
|
||||
## v1.4.0 - 2020-10-02
|
||||
|
||||
### New Features
|
||||
* Multivariate Regular Grid Interpolation
|
||||
* Jensen-Shannon Distance
|
||||
* Canberra Distance
|
||||
* Search Sorted
|
||||
* Search ArgMax
|
||||
* Search NanArgMax
|
||||
* Search ArgMin
|
||||
* Search NanArgMin
|
||||
* Search NonZero
|
||||
|
||||
### Improvements
|
||||
* Divergence factored out of Distance into new Divergence class
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Legacy Distance divergences marked as deprecated (To be removed in v2.0.0)
|
||||
|
||||
## v1.3.0 - 2020-08-24
|
||||
|
||||
### New Features
|
||||
* LinearAlgebra\Vector
|
||||
* Angle between two vectors
|
||||
* L¹ distance of two vectors
|
||||
* L² distance of two vectors
|
||||
* Minkowski distance of two vectors
|
||||
* Statistics\Distance
|
||||
* Minkowski distance
|
||||
* Euclidean distance (L² distance)
|
||||
* Manhattan distance (Taxicab geometry, L¹ distance, etc.)
|
||||
* Cosine distance
|
||||
* Cosine similarity
|
||||
|
||||
## v1.2.0 - 2020-07-24
|
||||
|
||||
### New Features
|
||||
* Ranking
|
||||
* Ordinal ranking
|
||||
* Standard competition ranking
|
||||
* Modified competition ranking
|
||||
* Fractional ranking
|
||||
|
||||
### Improvements
|
||||
* (Issue 380) Fixed Spearman's Rho calculation when there are rank ties
|
||||
|
||||
## v1.1.0 - 2020-04-19
|
||||
|
||||
### New Features
|
||||
- Arithmetic modulo
|
||||
|
||||
### Improvements
|
||||
- Improved matrix multiplication performance using cache-oblivious algorithm optimization
|
||||
|
||||
## v1.0.0 - 2020-04-14
|
||||
|
||||
Initial version 1.0.0 release!
|
||||
|
||||
## v0.62.0 - 2020-04-08
|
||||
|
||||
### Improvements
|
||||
- Internal improvements
|
||||
|
||||
## v0.61.0 - 2020-03-22
|
||||
|
||||
### New Features
|
||||
* Multivariate Hypergeometric distribution
|
||||
|
||||
## v0.60.0 - 2020-02-27
|
||||
|
||||
### New Features
|
||||
- Sample Data
|
||||
- MtCars
|
||||
- Iris
|
||||
- ToothGrowth
|
||||
- PlantGrowth
|
||||
- UsArrests
|
||||
|
||||
## v0.59.0 - 2020-02-19
|
||||
|
||||
### New Features
|
||||
- Add population and sample kurtosis
|
||||
- Changed default kurtosis algorithm to the more common population kurtosis
|
||||
- kurtosis now takes an optional parameter to set the kurtosis type algorithm
|
||||
|
||||
## v0.58.0 - 2020-02-06
|
||||
|
||||
### Improvements
|
||||
* Changed default skewness algorithm to the more common sample skewness
|
||||
* skewness now takes an optional parameter to set the skewness type algorithm
|
||||
* Improvements to skewness algorithms
|
||||
|
||||
## v0.57.0 - 2020-01-07
|
||||
|
||||
### New Features
|
||||
* Number\Rational basic getters
|
||||
* getWholePart
|
||||
* getNumerator
|
||||
* getDenominator
|
||||
* Set Theory n-ary Cartesian product
|
||||
|
||||
### Improvements
|
||||
* Data direction control for Matrix meanDeviation and covarianceMatrix
|
||||
* Algebra factors performance improvement
|
||||
|
||||
## v0.56.0 - 2019-12-03
|
||||
|
||||
### New Features
|
||||
* Number Theory
|
||||
* isDeficientNumber
|
||||
* isAbundantNumber
|
||||
* aliquotSum
|
||||
* radical
|
||||
* totient
|
||||
* cototient
|
||||
* reducedTotient
|
||||
* mobius
|
||||
* isSquarefree
|
||||
* isRefactorableNumber
|
||||
* isSphenicNumber
|
||||
* numberOfDivisors
|
||||
* sumOfDivisors
|
||||
|
||||
### Improvements
|
||||
* Optimization of prime factorization algorithm
|
||||
|
||||
## v0.55.0 - 2019-11-19
|
||||
|
||||
### New Features
|
||||
- Arbitrary length integers
|
||||
|
||||
### Improvements
|
||||
- Factorial optimization
|
||||
|
||||
## v0.54.0 - 2019-10-12
|
||||
|
||||
### New Features
|
||||
- Matrix isNilpotent
|
||||
- Matrix isRectangularDiagonal
|
||||
- Matrix mapRows
|
||||
- MathPHP logo
|
||||
|
||||
### Improvements
|
||||
* MatrixFactory random matrix custom lower and upper bounds for random number
|
||||
* PSR-12 style compliance
|
||||
* Bugfix: powerIteration random failure - [Issue 346](https://github.com/markrogoyski/math-php/issues/346)
|
||||
|
||||
## v0.53.0 - 2019-09-09
|
||||
|
||||
### New Features
|
||||
* Matrix QR decomposition using Householder reflections
|
||||
* Matrix Householder transformation
|
||||
* MatrixFactory random matrix
|
||||
* MatrixFactory givens rotation matrix
|
||||
* Matrix isIdempotent
|
||||
* Matrix Eigenvalue power iteration
|
||||
* Matrix Eigenvalue jacobi method
|
||||
* Arithmetic root (nᵗʰ root)
|
||||
* Vector arithmetic multiply and divide
|
||||
* Vector Iterator interface
|
||||
|
||||
### Improvements
|
||||
* Internal improvements to Matrix
|
||||
* Matrix decompositions returned as objects
|
||||
* Matrix Cholesky decomposition provides L transpose
|
||||
|
||||
## v0.52.0 - 2019-07-11
|
||||
|
||||
### New Features
|
||||
* Grubb's test for statistical outliers
|
||||
|
||||
## v0.51.0 - 2019-06-05
|
||||
|
||||
### New Features
|
||||
* Matrix rowSums
|
||||
* Matrix columnSums
|
||||
* Matrix rowMeans
|
||||
* Matrix columnMeans
|
||||
* Matrix isNormal
|
||||
* MatrixFactory diagonal matrix creation method
|
||||
* MatrixFactory vandermonde matrix creation method
|
||||
|
||||
### Improvements
|
||||
* Set custom Matrix tolerances
|
||||
* Various internal improvements
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Remove Matrix sampleMeans (use rowMeans or columnMeans instead)
|
||||
* MatrixFactory create method only works with 2d arrays. 1d arrays no longer work. (use diagonal and vandermonde factory methods instead)
|
||||
* Statistics methods throw exceptions instead of returning null on bad input
|
||||
* Change return type of LagrangePolynomial to Polynomial
|
||||
|
||||
## v0.50.0 - 2019-04-22
|
||||
|
||||
### New Features
|
||||
* Matrix isOrthogonal
|
||||
* Matrix isEqual
|
||||
* Harmonic sequence
|
||||
* Hyperharmonic sequence
|
||||
* Map\Single reciprocal
|
||||
|
||||
### Improvements
|
||||
* Support methods for almost equal
|
||||
* Matrix getDiagonalElements works for non-square matrices
|
||||
* Use more efficient algorithm in Matrix isSymmetric
|
||||
* Use more efficient algorithm in Matrix isSkewSymmetric
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Statistics methods throw exceptions instead of returning null on bad input
|
||||
|
||||
## v0.49.0 - 2019-02-23
|
||||
|
||||
### New Features
|
||||
- Matrix augmentAbove
|
||||
- Matrix augmentLeft
|
||||
|
||||
### Improvements
|
||||
- Object matrix multiplication
|
||||
|
||||
## v0.48.0 - 2018-12-15
|
||||
|
||||
### New Features
|
||||
- Matrix submatrix
|
||||
- Mahalanobis distance
|
||||
- Bernoulli distribution mean, median, mode and variance
|
||||
- Binomial distribution mean and variance
|
||||
- Geometric distribution mean, median, mode and variance
|
||||
- Hypergeometric distribution mode and variance
|
||||
- NegativeBinomial (Pascal) distribution CDF, mean, mode and variance
|
||||
- Poisson distribution mean, median, mode and variance
|
||||
- Discrete Uniform distribution variance
|
||||
|
||||
### Improvements
|
||||
- Binomial distribution PMF uses more numerically stable multiplication method
|
||||
- Fix potential divide by zero in TheilSen regression
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
- Multinomial distribution moved from Discrete to Multivariate namespace
|
||||
|
||||
## v0.47.0 - 2018-11-21
|
||||
|
||||
### New Features
|
||||
* Beta distribution median, mode, variance
|
||||
* Cauchy distribution variance
|
||||
* ChiSquared distribution mode, variance
|
||||
* Exponential distribution median, mode, variance
|
||||
* F distribution mode, variance
|
||||
* Gamma distribution median, mode, variance
|
||||
* Laplace distribution mode, variance
|
||||
* Logistic distribution mode, vaiance
|
||||
* LogLogistic distribution median, mode, variance
|
||||
* LogNormal distribution mode, variance
|
||||
* Normal distribution mode, variance
|
||||
* StandardNormal distribution mode, variance
|
||||
* StudentT distribution mode, variance
|
||||
* Uniform distribution median, mode, variance
|
||||
* Weibull distribution median, mode
|
||||
|
||||
### Improvements
|
||||
* Normal distribution rand algorithm changed to Box–Muller transform
|
||||
|
||||
## v0.46.0 - 2018-10-28
|
||||
|
||||
### New Features
|
||||
* NumberTheory isPerfectNumber
|
||||
* Sequence perfectNumber
|
||||
|
||||
### Improvements
|
||||
* Improve README documentation for continuous distributions
|
||||
* Updates to build tools
|
||||
* General improvements
|
||||
|
||||
## v0.45.0 - 2018-09-24
|
||||
|
||||
### Improvements
|
||||
- Add Beta distribution inverse quantile function
|
||||
- Improvements to Weibull distribution
|
||||
- Improvements to Cauchy distribution
|
||||
- Improvements to Laplace distribution
|
||||
- Improvements to Logistic distribution
|
||||
- Improvements to LogNormal distribution
|
||||
- Improvements to Normal distribution
|
||||
- Improvements to Pareto distribution
|
||||
- Improvements to Algebra cubic/quartic complex root handling
|
||||
|
||||
## v0.44.0 - 2018-08-29
|
||||
|
||||
### Improvements
|
||||
- [[Issue 271]](https://github.com/markrogoyski/math-php/issues/271) Improvements to documentation
|
||||
- [[Issue 269]](https://github.com/markrogoyski/math-php/issues/269) Add closed-form inverse function for Exponential distribution
|
||||
|
||||
## v0.43.0 - 2018-05-21
|
||||
|
||||
### New Features
|
||||
* Arithmetic copySign
|
||||
* Matrix negate
|
||||
* Matrix isSkewSymmetric
|
||||
|
||||
## v0.42.0 - 2018-05-09
|
||||
|
||||
### New Features
|
||||
* Weighted mean
|
||||
* Weighted sample variance
|
||||
* Weighted covariance
|
||||
* Weighted correlation coefficient
|
||||
|
||||
### Improvements
|
||||
* Minor code improvements
|
||||
|
||||
## v0.41.0 - 2018-04-23
|
||||
|
||||
### New Features
|
||||
* Arithmetic almostEqual
|
||||
|
||||
### Improvements
|
||||
* Statistics\Average::mode improved to work with non-integer values
|
||||
* Various minor code improvements
|
||||
|
||||
## v0.40.0 - 2018-03-22
|
||||
|
||||
### New Features
|
||||
* Simpler interface for Significance ```tTest``` for one and two samples
|
||||
|
||||
### Improvements
|
||||
* T test for two samples uses more robust Welch test
|
||||
* Improvements to Normal and Standard Normal continuous distributions
|
||||
* General improvements to continuous distributions
|
||||
|
||||
## v0.39.0 - 2018-02-27
|
||||
|
||||
### Improvements
|
||||
* Upgrade unit testing framework to PHPUnit 6
|
||||
* Update unit tests for PHPUnit 6 compatibility
|
||||
* Add PHP 7.2 to continuous integration tests
|
||||
|
||||
## v0.38.0 - 2017-12-10
|
||||
|
||||
### Improvements
|
||||
* Percentile reimplemented to use linear interpolation between closest ranks method - Second variant, C = 1
|
||||
* General code improvements
|
||||
* Better error and exception handling
|
||||
|
||||
## v0.37.0 - 2017-10-23
|
||||
|
||||
### Improvements
|
||||
- Change probability distributions to be objects instead of static methods
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
- Change probability distributions to be objects instead of static methods
|
||||
|
||||
## v0.36.0 - 2017-09-26
|
||||
|
||||
### New Features
|
||||
* Rational number
|
||||
* Gamma distribution mean
|
||||
|
||||
### Improvements
|
||||
* Add .gitignore file
|
||||
|
||||
## v0.35.0 - 2017-08-20
|
||||
|
||||
### New Features
|
||||
* Matrix isTridiagonal
|
||||
* Matrix isUpperHessenberg
|
||||
* Matrix isLowerHessenberg
|
||||
* Matrix getSuperdiagonalElements
|
||||
* Matrix getSubdiagonalElements
|
||||
|
||||
### Improvements
|
||||
* [Issue 242 - documentation improvement](https://github.com/markrogoyski/math-php/issues/242)
|
||||
|
||||
## v0.34.0 - 2017-08-12
|
||||
|
||||
### New Features
|
||||
- Multivariate normal distribution
|
||||
|
||||
## v0.33.0 - 2017-08-04
|
||||
|
||||
### New Features
|
||||
- Kernel density estimation
|
||||
|
||||
## v0.32.0 - 2017-07-24
|
||||
|
||||
### New Features
|
||||
* Matrix Crout decomposition
|
||||
* Categorical discrete distribution
|
||||
|
||||
## v0.31.0 - 2017-07-02
|
||||
|
||||
### New Features
|
||||
* Hypergeometric distribution
|
||||
* Discrete uniform distribution
|
||||
|
||||
## v0.30.0 - 2017-06-11
|
||||
|
||||
### New Features
|
||||
* Dirichlet multivariate distribution
|
||||
* Gamma distribution
|
||||
* Initial eigenvalue matrix method
|
||||
* Initial eigenvector matrix method
|
||||
* Confidence ellipse
|
||||
|
||||
### Improvements
|
||||
* Internal Bitwise addition
|
||||
|
||||
## v0.29.0 - 2017-05-21
|
||||
|
||||
### New Features
|
||||
- Matrix rank
|
||||
- ObjectArithmetic interface
|
||||
- Polynomial implements ObjectArithmetic
|
||||
- ObjectSquareMatrix
|
||||
- Polynomial negate
|
||||
|
||||
### Improvements
|
||||
- Refactor Matrix REF algorithm
|
||||
- Refactor Matrix RREF algorithm
|
||||
- Support functions for better handling of infinitesimal floating-point zero-like quantities
|
||||
- Fix bug in Polynomial degree calculation
|
||||
- Refactored Polynomial::add() to be simpler and faster
|
||||
|
||||
## v0.28.0 - 2017-05-02
|
||||
|
||||
### New Features
|
||||
* Matrix adjugate
|
||||
* Polynomial subtract
|
||||
|
||||
### Improvements
|
||||
* Internal refactoring/improvements
|
||||
* Tests namespace for unit tests
|
||||
* Standardize method naming convention
|
||||
* Update PHPUnit exception assertion
|
||||
* Replace class strings in tests with class constants
|
||||
|
||||
## v0.27.0 - 2017-04-23
|
||||
|
||||
### New Features
|
||||
* Matrix
|
||||
* Cholesky decomposition
|
||||
* isRref
|
||||
* Exchange matrix
|
||||
* isInvolutory
|
||||
* isSignature
|
||||
* Hilbert matrix
|
||||
* isUpperBidiagonal
|
||||
* isLowerBidiagonal
|
||||
* isBidiagonal
|
||||
* Quartic function roots
|
||||
* Trigonometry unit circle
|
||||
* Integer
|
||||
* isOdd
|
||||
* isEven
|
||||
|
||||
## v0.26.0 - 2017-04-15
|
||||
|
||||
### New Features
|
||||
* Initial Complex number class
|
||||
* Complex number support to quadratic and cubic equations
|
||||
* Initial Eigenvalue strategy class (2x2 and 3x3 matrices using root equations)
|
||||
* Matrix
|
||||
* isLowerTriangular
|
||||
* isUpperTriangular
|
||||
* isTriangular
|
||||
* isDiagonal
|
||||
* Beta function convenience method
|
||||
|
||||
### Improvements
|
||||
* Add BadDataException to LeastSquares regression method trait if degrees of freedom is 0
|
||||
* Complex Root of Quadratic Function
|
||||
|
||||
## v0.25.0 - 2017-04-01
|
||||
|
||||
### New Features
|
||||
* Matrix
|
||||
* isSingular
|
||||
* isNonsingular
|
||||
* isInvertible
|
||||
* leadingPrincipalMinor
|
||||
* isPositiveDefinite
|
||||
* isPositiveSemidefinite
|
||||
* isNegativeDefinite
|
||||
* isNegativeSemidefinite
|
||||
* Number Theory
|
||||
* Integer coprime
|
||||
* Arithmetic
|
||||
* digitSum
|
||||
* digitalRoot
|
||||
* Basic sequences
|
||||
* digitSum
|
||||
* digitalRoot
|
||||
|
||||
## v0.24.0 - 2017-03-26
|
||||
|
||||
### New Features
|
||||
* Arithmetic cube root
|
||||
* Algebra cubic equation
|
||||
* Matrix Kronecker sum
|
||||
* Vector Kronecker product
|
||||
* Number theory prime factorization
|
||||
|
||||
### Improvements
|
||||
* Improved quadratic equation edge case handling
|
||||
|
||||
## v0.23.0 - 2017-03-12
|
||||
|
||||
### New Features
|
||||
* Number Theory - Integers
|
||||
* Perfect powers
|
||||
* Advanced Sequences
|
||||
* Perfect powers
|
||||
* Not perfect powers
|
||||
* Primes up to n
|
||||
* Algebra
|
||||
* Quadratic equation
|
||||
|
||||
## v0.22.0 - 2017-01-31
|
||||
|
||||
### New Features
|
||||
* Circular statistics (directional statistics)
|
||||
* Circular mean
|
||||
* Resultant length
|
||||
* Mean resultant length
|
||||
* Circular variance
|
||||
* Circular standard deviation
|
||||
* Describe
|
||||
* Finance profitability index
|
||||
|
||||
### Improvements
|
||||
* Update Finance payback to be both simple and discounted payback
|
||||
|
||||
## v0.21.0 - 2017-01-23
|
||||
|
||||
### New Features
|
||||
* Finance interest payment
|
||||
* Finance principle payment on an annuity
|
||||
* Finance payback
|
||||
* Make files for unit tests, linting, and code coverage
|
||||
|
||||
## v0.20.0 - 2017-01-12
|
||||
|
||||
### New Features
|
||||
* Finance net present value
|
||||
* Finance rate function
|
||||
* Finance internal rate of return
|
||||
* Finance modified internal rate of return
|
||||
* Finance payment periods of an annuity
|
||||
|
||||
### Improvements
|
||||
* Update Newton's Method to handle non-convergence and infinite slopes.
|
||||
|
||||
## v0.19.0 - 2016-12-31
|
||||
|
||||
### New Features
|
||||
* Matrix sample mean
|
||||
* Matrix mean deviation form
|
||||
* Covariance matrix
|
||||
* Matrix representation as array of column vectors
|
||||
* Finance future value
|
||||
* Finance present value
|
||||
|
||||
## v0.18.0 - 2016-12-28
|
||||
|
||||
### New Features
|
||||
* Joint entropy
|
||||
* Rényi entropy
|
||||
* Perplexity
|
||||
* Matrix scalar division
|
||||
* Finance: Annual Equivalent Rate (AER)
|
||||
|
||||
### Improvements
|
||||
* Fix vector pnorm to take absolute value of each element
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Refactor distances and divergences from InformationTheory\Entropy to Statistics\Distance
|
||||
|
||||
## v0.17.0 - 2016-12-21
|
||||
|
||||
### New Features
|
||||
* Two-sample z significance test
|
||||
|
||||
## v.0.16.0 - 2016-12-18
|
||||
|
||||
### New Features
|
||||
* Information Theory
|
||||
* Shannon entropy (bits, nats, hartleys)
|
||||
* Cross entropy
|
||||
* Bhattacharyya distance
|
||||
* Kullback-Leibler divergence
|
||||
* Hellinger distance
|
||||
* Jensen-Shannon divergence
|
||||
* Linear Algebra
|
||||
* vectorMultiply method on Matrix to return Vector when multiply with a Vector
|
||||
|
||||
## v0.15.0 - 2016-11-10
|
||||
|
||||
### New Features
|
||||
* Lazy caterer's sequence
|
||||
* Magic squares sequence
|
||||
|
||||
## v0.14.0 - 2016-10-28
|
||||
|
||||
### New Features
|
||||
* Look-and-say sequence
|
||||
|
||||
## v0.13.0 - 2016-10-17
|
||||
|
||||
### New Features
|
||||
* Custom exception classes
|
||||
|
||||
### Improvements
|
||||
* Refactor exceptions to use custom exception classes
|
||||
|
||||
## v0.12.0 - 2016-10-06
|
||||
|
||||
### New Features
|
||||
* Softmax function
|
||||
* Effect size η² (Eta-squared)
|
||||
* Effect size η²p (Partial eta-squared)
|
||||
* Effect size ω² (omega-squared)
|
||||
* Effect size Cohen's ƒ²
|
||||
* Effect size Cohen's q
|
||||
* Effect size Cohen's d
|
||||
* Effect size Hedges' g
|
||||
* Effect size Glass' Δ (glass' delta)
|
||||
|
||||
### Improvements
|
||||
* Replace mt_rand with random_int
|
||||
|
||||
## v0.11.0 - 2016-10-01
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Change root namespace from Math to MathPHP
|
||||
* (Run composer update to update autoloader)
|
||||
|
||||
## v0.10.0 - 2016-09-28
|
||||
|
||||
### New Features
|
||||
* Clamped Cubic Spline Interpolation
|
||||
* Custom variable in Polynomial class
|
||||
|
||||
## v0.9.0 - 2016-09-27
|
||||
|
||||
### New Features
|
||||
* Natural cubic spline interpolation
|
||||
* Vector direct product
|
||||
|
||||
## v0.8.0 - 2016-09-22
|
||||
|
||||
### New Features
|
||||
* Set Theory
|
||||
* Matrix kronecker product
|
||||
* Matrix augment below
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
* Some null return values changed to NAN when computation is invalid
|
||||
|
||||
|
||||
## v0.7.0 - 2016-09-19
|
||||
|
||||
### New Features
|
||||
* Matrix solve linear system of equations
|
||||
* Noncentral T distribution
|
||||
* Piecewise function class
|
||||
* Initial Finance class (pmt function)
|
||||
* Vector scalar multiplication
|
||||
* Vector normalization
|
||||
* Vector scalar division
|
||||
* Vector perpendicular operator
|
||||
* Vector projections
|
||||
* Vector perp and perp dot product
|
||||
|
||||
### Improvements
|
||||
* Add getters to Polynomial for degree and coefficients
|
||||
* Improvements to gamma function
|
||||
|
||||
## v0.6.1 - 2016-09-11
|
||||
|
||||
### Improvements
|
||||
* Fix matrix determinant calculation
|
||||
|
||||
## v0.6.0 - 2016-09-10
|
||||
|
||||
### New Features
|
||||
* Polynomial class
|
||||
* Vector cross product
|
||||
|
||||
## v0.5.0 - 2016-09-07
|
||||
|
||||
### New Features
|
||||
* Numerical Differentiation (\Math\NumericalAnalysis\NumericalDifferentiation)
|
||||
* Three Point Formula (\Math\NumericalAnalysis\NumericalDifferentiation\ThreePointFormula)
|
||||
* Five Point Formula (\Math\NumericalAnalysis\NumericalDifferentiation\FivePointFormula)
|
||||
* SecondDerivativeMidpointFormula (\Math\NumericalAnalysis\NumericalDifferentiation\SecondDerivativeMidpointFormula)
|
||||
* Two-way ANOVA (\Math\Statistics\ANOVA)
|
||||
|
||||
## v0.4.0 - 2016-09-07
|
||||
|
||||
### New Features
|
||||
|
||||
* Nevilles Method (\Math\NumericalAnalysis\Interpolation)
|
||||
* Newton Polynomial (\Math\NumericalAnalysis\Interpolation)
|
||||
|
||||
## v0.3.0 - 2016-09-06
|
||||
|
||||
### New Features
|
||||
|
||||
* Lagrange polynomials (\Math\NumericalAnalysis\Interpolation)
|
||||
* Function arithmetic (\Math\Functions\Arithmetic)
|
||||
|
||||
## v0.2.0 - 2016-09-05
|
||||
|
||||
### New Features
|
||||
|
||||
* One-way ANOVA (```Math\Statistics\ANOVA```)
|
||||
* χ² Table (```Math\Probability\Distribution\Table```)
|
||||
* Five number summary (```Math\Statistics\Descriptive```)
|
||||
* Simple sum of squares (```Math\Statistics\RandomVariable```)
|
||||
|
||||
### Improvements
|
||||
|
||||
* Refactor probability distribution tables (```Math\Probability\Distribution\Table```)
|
||||
* Minor refactors
|
||||
|
||||
### Backwards Incompatible Changes
|
||||
|
||||
* Move probability distribution tables to new namespace
|
||||
* From ```Math\Probability``` to ```Math\Probability\Distribution\Table```
|
||||
|
||||
## v0.1.0 - 2016-09-02
|
||||
|
||||
### New Features
|
||||
|
||||
* Algebra
|
||||
* Functions
|
||||
- Map
|
||||
- Special Functions
|
||||
* Linear Algebra
|
||||
- Matrix
|
||||
- Vector
|
||||
* Numerical Analysis
|
||||
- Numerical Integration
|
||||
- Root Finding
|
||||
* Probability
|
||||
- Combinatorics
|
||||
- Distributions
|
||||
* Continuous
|
||||
* Discrete
|
||||
- Standard Normal Table (Z Table)
|
||||
- t Distribution Table
|
||||
* Sequences
|
||||
- Basic
|
||||
- Advanced
|
||||
* Statistics
|
||||
- Averages
|
||||
- Correlation
|
||||
- Descriptive
|
||||
- Distributions
|
||||
- Experiments
|
||||
- Random Variables
|
||||
- Regressions
|
||||
- Significance Testing
|
||||
21
htdocs/includes/markrogoyski/math-php/LICENSE.txt
Normal file
21
htdocs/includes/markrogoyski/math-php/LICENSE.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2016 Mark Rogoyski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2796
htdocs/includes/markrogoyski/math-php/README.md
Normal file
2796
htdocs/includes/markrogoyski/math-php/README.md
Normal file
File diff suppressed because it is too large
Load Diff
41
htdocs/includes/markrogoyski/math-php/composer.json
Normal file
41
htdocs/includes/markrogoyski/math-php/composer.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "markrogoyski/math-php",
|
||||
"type": "library",
|
||||
"description": "Math Library for PHP. Features descriptive statistics and regressions; Continuous and discrete probability distributions; Linear algebra with matrices and vectors, Numerical analysis; special mathematical functions; Algebra",
|
||||
"keywords": ["math", "mathematics", "probability", "combinatorics", "statistics", "distributions", "regressions", "linear algebra", "matrix", "algebra", "numerical analysis"],
|
||||
"homepage": "https://github.com/markrogoyski/math-php/",
|
||||
"require": {
|
||||
"php": ">=7.2.0",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "MathPHP\\": "src/" }
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5",
|
||||
"php-coveralls/php-coveralls": "^2.0",
|
||||
"squizlabs/php_codesniffer": "3.*",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpmd/phpmd": "^2.6",
|
||||
"phploc/phploc": "*",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.2"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Rogoyski",
|
||||
"role": "Lead developer",
|
||||
"email": "mark@rogoyski.com",
|
||||
"homepage": "https://github.com/markrogoyski"
|
||||
},
|
||||
{
|
||||
"name": "Kevin Nowaczyk",
|
||||
"role": "Developer",
|
||||
"homepage": "https://github.com/Beakerboy"
|
||||
},
|
||||
{
|
||||
"name": "MathPHP Community of Contributors",
|
||||
"homepage": "https://github.com/markrogoyski/math-php/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace MathPHP\Exception;
|
||||
|
||||
class BadDataException extends MathException
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace MathPHP\Exception;
|
||||
|
||||
class OutOfBoundsException extends MathException
|
||||
{
|
||||
}
|
||||
780
htdocs/includes/markrogoyski/math-php/src/Finance.php
Normal file
780
htdocs/includes/markrogoyski/math-php/src/Finance.php
Normal file
|
|
@ -0,0 +1,780 @@
|
|||
<?php
|
||||
|
||||
namespace MathPHP;
|
||||
|
||||
use MathPHP\Exception\OutOfBoundsException;
|
||||
|
||||
/**
|
||||
* General references on financial functions and formulas:
|
||||
* - Open Document Format for Office Applications (OpenDocument) Version 1.2 Part 2:
|
||||
* Recalculated Formula (OpenFormula) Format. 29 September 2011. OASIS Standard.
|
||||
* http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part2.html#__RefHeading__1018228_715980110
|
||||
* - https://wiki.openoffice.org/wiki/Documentation/How_Tos/Calc:_Derivation_of_Financial_Formulas#Loans_and_Annuities
|
||||
*/
|
||||
class Finance
|
||||
{
|
||||
/**
|
||||
* Floating-point range near zero to consider insignificant.
|
||||
*/
|
||||
public const EPSILON = 1e-6;
|
||||
|
||||
/**
|
||||
* Consider any floating-point value less than epsilon from zero as zero,
|
||||
* ie any value in the range [-epsilon < 0 < epsilon] is considered zero.
|
||||
* Also used to convert -0.0 to 0.0.
|
||||
*
|
||||
* @param float $value
|
||||
* @param float $epsilon
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private static function checkZero(float $value, float $epsilon = self::EPSILON): float
|
||||
{
|
||||
return \abs($value) < $epsilon ? 0.0 : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Financial payment for a loan or annuity with compound interest.
|
||||
* Determines the periodic payment amount for a given interest rate,
|
||||
* principal, targeted payment goal, life of the annuity as number
|
||||
* of payments, and whether the payments are made at the start or end
|
||||
* of each payment period.
|
||||
*
|
||||
* Same as the =PMT() function in most spreadsheet software.
|
||||
*
|
||||
* The basic monthly payment formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Mortgage_calculator#Monthly_payment_formula
|
||||
*
|
||||
* rP(1+r)ᴺ
|
||||
* PMT = --------
|
||||
* (1+r)ᴺ-1
|
||||
*
|
||||
* The formula is adjusted to allow targeting any future value rather than 0.
|
||||
* The 1/(1+r*when) factor adjusts the payment to the beginning or end
|
||||
* of the period. In the common case of a payment at the end of a period,
|
||||
* the factor is 1 and reduces to the formula above. Setting when=1 computes
|
||||
* an "annuity due" with an immediate payment.
|
||||
*
|
||||
* Examples:
|
||||
* The payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
|
||||
* paid at the end of every month.
|
||||
* pmt(0.035/12, 30*12, 265000, 0, false)
|
||||
*
|
||||
* The payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
|
||||
* needed to half the principal in half in 5 years:
|
||||
* pmt(0.035/12, 5*12, 265000, 265000/2, false)
|
||||
*
|
||||
* The weekly payment into a savings account with 1% interest rate and current
|
||||
* balance of $1500 needed to reach $10000 after 3 years:
|
||||
* pmt(0.01/52, 3*52, -1500, 10000, false)
|
||||
* The present_value is negative indicating money put into the savings account,
|
||||
* whereas future_value is positive, indicating money that will be withdrawn from
|
||||
* the account. Similarly, the payment value is negative
|
||||
*
|
||||
* How much money can be withdrawn at the end of every quarter from an account
|
||||
* with $1000000 earning 4% so the money lasts 20 years:
|
||||
* pmt(0.04/4, 20*4, 1000000, 0, false)
|
||||
*
|
||||
* @param float $rate
|
||||
* @param int $periods
|
||||
* @param float $present_value
|
||||
* @param float $future_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pmt(float $rate, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float
|
||||
{
|
||||
$when = $beginning ? 1 : 0;
|
||||
|
||||
if ($rate == 0) {
|
||||
return - ($future_value + $present_value) / $periods;
|
||||
}
|
||||
|
||||
return - ($future_value + ($present_value * \pow(1 + $rate, $periods)))
|
||||
/
|
||||
((1 + $rate * $when) / $rate * (\pow(1 + $rate, $periods) - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interest on a financial payment for a loan or annuity with compound interest.
|
||||
* Determines the interest payment at a particular period of the annuity. For
|
||||
* a typical loan paid down to zero, the amount of interest and principle paid
|
||||
* throughout the lifetime of the loan will change, with the interest portion
|
||||
* of the payment decreasing over time as the loan principle decreases.
|
||||
*
|
||||
* Same as the =IPMT() function in most spreadsheet software.
|
||||
*
|
||||
* See the PMT function for derivation of the formula. For IPMT, we have
|
||||
* the payment equal to the interest portion and principle portion of the payment:
|
||||
*
|
||||
* PMT = IPMT + PPMT
|
||||
*
|
||||
* The interest portion IPMT on a regular annuity can be calculated by computing
|
||||
* the future value of the annuity for the prior period and computing the compound
|
||||
* interest for one period:
|
||||
*
|
||||
* IPMT = FV(p=n-1) * rate
|
||||
*
|
||||
* For an "annuity due" where payment is at the start of the period, period=1 has
|
||||
* no interest portion of the payment because no time has elapsed for compounding.
|
||||
* To compute the interest portion of the payment, the future value of 2 periods
|
||||
* back needs to be computed, as the definition of a period is different, giving:
|
||||
*
|
||||
* IPMT = (FV(p=n-2) - PMT) * rate
|
||||
*
|
||||
* By thinking of the future value at period 0 instead of the present value, the
|
||||
* given formulas are computed.
|
||||
*
|
||||
* Example of regular annuity and annuity due for a loan of $10.00 paid back in 3 periods.
|
||||
* Although the principle payments are equal, the total payment and interest portion are
|
||||
* lower with the annuity due because a principle payment is made immediately.
|
||||
*
|
||||
* Regular Annuity | Annuity Due
|
||||
* Period FV PMT IPMT PPMT | PMT IPMT PPMT
|
||||
* 0 -10.00 |
|
||||
* 1 -6.83 -3.67 -0.50 -3.17 | -3.50 0.00 -3.50
|
||||
* 2 -3.50 -3.67 -0.34 -3.33 | -3.50 -0.33 -3.17
|
||||
* 3 0.00 -3.67 -0.17 -3.50 | -3.50 -0.17 -3.33
|
||||
* -----------------------|----------------------
|
||||
* SUM -11.01 -1.01 -10.00 | -10.50 -0.50 -10.00
|
||||
*
|
||||
* Examples:
|
||||
* The interest on a payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
|
||||
* paid at the end of every month, looking at the first payment:
|
||||
* ipmt(0.035/12, 1, 30*12, 265000, 0, false)
|
||||
*
|
||||
* @param float $rate
|
||||
* @param int $period
|
||||
* @param int $periods
|
||||
* @param float $present_value
|
||||
* @param float $future_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function ipmt(float $rate, int $period, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float
|
||||
{
|
||||
if ($period < 1 || $period > $periods) {
|
||||
return \NAN;
|
||||
}
|
||||
|
||||
if ($rate == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($beginning && $period == 1) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$payment = self::pmt($rate, $periods, $present_value, $future_value, $beginning);
|
||||
if ($beginning) {
|
||||
$interest = (self::fv($rate, $period - 2, $payment, $present_value, $beginning) - $payment) * $rate;
|
||||
} else {
|
||||
$interest = self::fv($rate, $period - 1, $payment, $present_value, $beginning) * $rate;
|
||||
}
|
||||
|
||||
return self::checkZero($interest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Principle on a financial payment for a loan or annuity with compound interest.
|
||||
* Determines the principle payment at a particular period of the annuity. For
|
||||
* a typical loan paid down to zero, the amount of interest and principle paid
|
||||
* throughout the lifetime of the loan will change, with the principle portion
|
||||
* of the payment increasing over time as the loan principle decreases.
|
||||
*
|
||||
* Same as the =PPMT() function in most spreadsheet software.
|
||||
*
|
||||
* See the PMT function for derivation of the formula.
|
||||
* See the IPMT function for derivation and use of PMT, IPMT, and PPMT.
|
||||
*
|
||||
* With derivations for PMT and IPMT, we simply compute:
|
||||
*
|
||||
* PPMT = PMT - IPMT
|
||||
*
|
||||
* Examples:
|
||||
* The principle on a payment on a 30-year fixed mortgage note of $265000 at 3.5% interest
|
||||
* paid at the end of every month, looking at the first payment:
|
||||
* ppmt(0.035/12, 1, 30*12, 265000, 0, false)
|
||||
*
|
||||
* @param float $rate
|
||||
* @param int $period
|
||||
* @param int $periods
|
||||
* @param float $present_value
|
||||
* @param float $future_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function ppmt(float $rate, int $period, int $periods, float $present_value, float $future_value = 0.0, bool $beginning = false): float
|
||||
{
|
||||
$payment = self::pmt($rate, $periods, $present_value, $future_value, $beginning);
|
||||
$ipmt = self::ipmt($rate, $period, $periods, $present_value, $future_value, $beginning);
|
||||
|
||||
return $payment - $ipmt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of payment periods of an annuity.
|
||||
* Solves for the number of periods in the annuity formula.
|
||||
*
|
||||
* Same as the =NPER() function in most spreadsheet software.
|
||||
*
|
||||
* Solving the basic annuity formula for number of periods:
|
||||
* log(PMT - FV*r)
|
||||
* ---------------
|
||||
* log(PMT + PV*r)
|
||||
* n = --------------------
|
||||
* log(1 + r)
|
||||
*
|
||||
* The (1+r*when) factor adjusts the payment to the beginning or end
|
||||
* of the period. In the common case of a payment at the end of a period,
|
||||
* the factor is 1 and reduces to the formula above. Setting when=1 computes
|
||||
* an "annuity due" with an immediate payment.
|
||||
*
|
||||
* Examples:
|
||||
* The number of periods of a $475000 mortgage with interest rate 3.5% and monthly
|
||||
* payment of $2132.96 paid in full:
|
||||
* nper(0.035/12, -2132.96, 475000, 0)
|
||||
*
|
||||
* @param float $rate
|
||||
* @param float $payment
|
||||
* @param float $present_value
|
||||
* @param float $future_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function periods(float $rate, float $payment, float $present_value, float $future_value, bool $beginning = false): float
|
||||
{
|
||||
$when = $beginning ? 1 : 0;
|
||||
|
||||
if ($rate == 0) {
|
||||
return - ($present_value + $future_value) / $payment;
|
||||
}
|
||||
|
||||
$initial = $payment * (1.0 + $rate * $when);
|
||||
return \log(($initial - $future_value * $rate) / ($initial + $present_value * $rate)) / \log(1.0 + $rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Annual Equivalent Rate (AER) of an annual percentage rate (APR).
|
||||
* The effective yearly rate of an annual percentage rate when the
|
||||
* annual percentage rate is compounded periodically within the year.
|
||||
*
|
||||
* Same as the =EFFECT() function in most spreadsheet software.
|
||||
*
|
||||
* The formula:
|
||||
* https://en.wikipedia.org/wiki/Effective_interest_rate
|
||||
*
|
||||
* / i \ ᴺ
|
||||
* AER = | 1 + - | - 1
|
||||
* \ n /
|
||||
*
|
||||
* Examples:
|
||||
* The AER of APR 3.5% interest compounded monthly.
|
||||
* aer(0.035, 12)
|
||||
*
|
||||
* @param float $nominal
|
||||
* @param int $periods
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function aer(float $nominal, int $periods): float
|
||||
{
|
||||
if ($periods == 1) {
|
||||
return $nominal;
|
||||
}
|
||||
|
||||
return \pow(1 + ($nominal / $periods), $periods) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Annual Nominal Rate of an annual effective rate (AER).
|
||||
* The nominal yearly rate of an annual effective rate when the
|
||||
* annual effective rate is compounded periodically within the year.
|
||||
*
|
||||
* Same as the =NOMINAL() function in most spreadsheet software.
|
||||
*
|
||||
* See:
|
||||
* https://en.wikipedia.org/wiki/Nominal_interest_rate
|
||||
*
|
||||
* / 1/N \
|
||||
* NOMINAL = | (AER + 1) -1 | * N
|
||||
* \ /
|
||||
*
|
||||
* Examples:
|
||||
* The nominal rate of AER 3.557% interest compounded monthly.
|
||||
* nominal(0.03557, 12)
|
||||
*
|
||||
* @param float $aer
|
||||
* @param int $periods
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function nominal(float $aer, int $periods): float
|
||||
{
|
||||
if ($periods == 1) {
|
||||
return $aer;
|
||||
}
|
||||
|
||||
return (\pow($aer + 1, 1 / $periods) - 1) * $periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Future value for a loan or annuity with compound interest.
|
||||
*
|
||||
* Same as the =FV() function in most spreadsheet software.
|
||||
*
|
||||
* The basic future-value formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Future_value
|
||||
*
|
||||
* PMT*((1+r)ᴺ - 1)
|
||||
* FV = -PV*(1+r)ᴺ - ----------------
|
||||
* r
|
||||
*
|
||||
* The (1+r*when) factor adjusts the payment to the beginning or end
|
||||
* of the period. In the common case of a payment at the end of a period,
|
||||
* the factor is 1 and reduces to the formula above. Setting when=1 computes
|
||||
* an "annuity due" with an immediate payment.
|
||||
*
|
||||
* Examples:
|
||||
* The future value in 5 years on a 30-year fixed mortgage note of $265000
|
||||
* at 3.5% interest paid at the end of every month. This is how much loan
|
||||
* principle would be outstanding:
|
||||
* fv(0.035/12, 5*12, 1189.97, -265000, false)
|
||||
*
|
||||
* The present_value is negative indicating money borrowed for the mortgage,
|
||||
* whereas payment is positive, indicating money that will be paid to the
|
||||
* mortgage.
|
||||
*
|
||||
* @param float $rate
|
||||
* @param int $periods
|
||||
* @param float $payment
|
||||
* @param float $present_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function fv(float $rate, int $periods, float $payment, float $present_value, bool $beginning = false): float
|
||||
{
|
||||
$when = $beginning ? 1 : 0;
|
||||
|
||||
if ($rate == 0) {
|
||||
$fv = -($present_value + ($payment * $periods));
|
||||
return self::checkZero($fv);
|
||||
}
|
||||
|
||||
$initial = 1 + ($rate * $when);
|
||||
$compound = \pow(1 + $rate, $periods);
|
||||
$fv = - (($present_value * $compound) + (($payment * $initial * ($compound - 1)) / $rate));
|
||||
|
||||
return self::checkZero($fv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Present value for a loan or annuity with compound interest.
|
||||
*
|
||||
* Same as the =PV() function in most spreadsheet software.
|
||||
*
|
||||
* The basic present-value formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Present_value
|
||||
*
|
||||
* PMT*((1+r)ᴺ - 1)
|
||||
* PV = -FV - ----------------
|
||||
* r
|
||||
* ---------------------
|
||||
* (1 + r)ᴺ
|
||||
*
|
||||
* The (1+r*when) factor adjusts the payment to the beginning or end
|
||||
* of the period. In the common case of a payment at the end of a period,
|
||||
* the factor is 1 and reduces to the formula above. Setting when=1 computes
|
||||
* an "annuity due" with an immediate payment.
|
||||
*
|
||||
* Examples:
|
||||
* The present value of a bond's $1000 face value paid in 5 year's time
|
||||
* with a constant discount rate of 3.5% compounded monthly:
|
||||
* pv(0.035/12, 5*12, 0, -1000, false)
|
||||
*
|
||||
* The present value of a $1000 5-year bond that pays a fixed 7% ($70)
|
||||
* coupon at the end of each year with a discount rate of 5%:
|
||||
* pv(0.5, 5, -70, -1000, false)
|
||||
*
|
||||
* The payment and future_value is negative indicating money paid out.
|
||||
*
|
||||
* @param float $rate
|
||||
* @param int $periods
|
||||
* @param float $payment
|
||||
* @param float $future_value
|
||||
* @param bool $beginning adjust the payment to the beginning or end of the period
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function pv(float $rate, int $periods, float $payment, float $future_value, bool $beginning = false): float
|
||||
{
|
||||
$when = $beginning ? 1 : 0;
|
||||
|
||||
if ($rate == 0) {
|
||||
$pv = -$future_value - ($payment * $periods);
|
||||
return self::checkZero($pv);
|
||||
}
|
||||
|
||||
$initial = 1 + ($rate * $when);
|
||||
$compound = \pow(1 + $rate, $periods);
|
||||
$pv = (-$future_value - (($payment * $initial * ($compound - 1)) / $rate)) / $compound;
|
||||
|
||||
return self::checkZero($pv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Net present value of cash flows. Cash flows are periodic starting
|
||||
* from an initial time and with a uniform discount rate.
|
||||
*
|
||||
* Similar to the =NPV() function in most spreadsheet software, except
|
||||
* the initial (usually negative) cash flow at time 0 is given as the
|
||||
* first element of the array rather than subtracted. For example,
|
||||
* spreadsheet: =NPV(0.01, 100, 200, 300, 400) - 1000
|
||||
* is done as
|
||||
* MathPHP::npv(0.01, [-1000, 100, 200, 300, 400])
|
||||
*
|
||||
* The basic net-present-value formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Net_present_value
|
||||
*
|
||||
* n Rt
|
||||
* Σ --------
|
||||
* t=0 (1 / r)ᵗ
|
||||
*
|
||||
* Examples:
|
||||
* The net present value of 5 yearly cash flows after an initial $1000
|
||||
* investment with a 3% discount rate:
|
||||
* npv(0.03, [-1000, 100, 500, 300, 700, 700])
|
||||
*
|
||||
* @param float $rate
|
||||
* @param array<float> $values
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function npv(float $rate, array $values): float
|
||||
{
|
||||
$result = 0.0;
|
||||
|
||||
for ($i = 0; $i < \count($values); ++$i) {
|
||||
$result += $values[$i] / (1 + $rate) ** $i;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interest rate per period of an Annuity.
|
||||
*
|
||||
* Same as the =RATE() formula in most spreadsheet software.
|
||||
*
|
||||
* The basic rate formula derivation is to solve for the future value
|
||||
* taking into account the present value:
|
||||
* https://en.wikipedia.org/wiki/Future_value
|
||||
*
|
||||
* ((1+r)ᴺ - 1)
|
||||
* FV + PV*(1+r)ᴺ + PMT * ------------ = 0
|
||||
* r
|
||||
* The (1+r*when) factor adjusts the payment to the beginning or end
|
||||
* of the period. In the common case of a payment at the end of a period,
|
||||
* the factor is 1 and reduces to the formula above. Setting when=1 computes
|
||||
* an "annuity due" with an immediate payment.
|
||||
*
|
||||
* Not all solutions for the rate have real-value solutions or converge.
|
||||
* In these cases, NAN is returned.
|
||||
*
|
||||
* @param float $periods
|
||||
* @param float $payment
|
||||
* @param float $present_value
|
||||
* @param float $future_value
|
||||
* @param bool $beginning
|
||||
* @param float $initial_guess
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function rate(float $periods, float $payment, float $present_value, float $future_value, bool $beginning = false, float $initial_guess = 0.1): float
|
||||
{
|
||||
$when = $beginning ? 1 : 0;
|
||||
|
||||
$func = function ($x, $periods, $payment, $present_value, $future_value, $when) {
|
||||
return $future_value + $present_value * (1 + $x) ** $periods + $payment * (1 + $x * $when) / $x * ((1 + $x) ** $periods - 1);
|
||||
};
|
||||
|
||||
return self::checkZero(NumericalAnalysis\RootFinding\NewtonsMethod::solve($func, [$initial_guess, $periods, $payment, $present_value, $future_value, $when], 0, self::EPSILON, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal rate of return.
|
||||
* Periodic rate of return that would provide a net-present value (NPV) of 0.
|
||||
*
|
||||
* Same as =IRR formula in most spreadsheet software.
|
||||
*
|
||||
* Reference:
|
||||
* https://en.wikipedia.org/wiki/Internal_rate_of_return
|
||||
*
|
||||
* Examples:
|
||||
* The rate of return of an initial investment of $100 with returns
|
||||
* of $50, $40, and $30:
|
||||
* irr([-100, 50, 40, 30])
|
||||
*
|
||||
* Solves for NPV=0 using Newton's Method.
|
||||
* @param array<float> $values
|
||||
* @param float $initial_guess
|
||||
*
|
||||
* @return float
|
||||
*
|
||||
* @throws OutOfBoundsException
|
||||
*
|
||||
* @todo: Use eigenvalues to find the roots of a characteristic polynomial.
|
||||
* This will allow finding all solutions and eliminate the need of the initial_guess.
|
||||
*/
|
||||
public static function irr(array $values, float $initial_guess = 0.1): float
|
||||
{
|
||||
$func = function ($x, $values) {
|
||||
return Finance::npv($x, $values);
|
||||
};
|
||||
|
||||
if (\count($values) <= 1) {
|
||||
return \NAN;
|
||||
}
|
||||
|
||||
$root = NumericalAnalysis\RootFinding\NewtonsMethod::solve($func, [$initial_guess, $values], 0, self::EPSILON, 0);
|
||||
if (!\is_nan($root)) {
|
||||
return self::CheckZero($root);
|
||||
}
|
||||
return self::checkZero(self::alternateIrr($values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate IRR implementation.
|
||||
*
|
||||
* A more numerically stable implementation that converges to only one value.
|
||||
*
|
||||
* Based off of Better: https://github.com/better/irr
|
||||
*
|
||||
* @param array<float> $values
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
private static function alternateIrr(array $values): float
|
||||
{
|
||||
$rate = 0.0;
|
||||
for ($iter = 0; $iter < 100; $iter++) {
|
||||
$m = -1000;
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
$m = \max($m, -$rate * $i);
|
||||
}
|
||||
$f = [];
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
$f[$i] = \exp(-$rate * $i - $m);
|
||||
}
|
||||
$t = 0;
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
$t += $f[$i] * $values[$i];
|
||||
}
|
||||
if (\abs($t) < (self::EPSILON * \exp($m))) {
|
||||
break;
|
||||
}
|
||||
$u = 0;
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
$u += $f[$i] * $i * $values[$i];
|
||||
}
|
||||
if ($u == 0) {
|
||||
return \NAN;
|
||||
}
|
||||
$rate += $t / $u;
|
||||
}
|
||||
return \exp($rate) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified internal rate of return.
|
||||
* Rate of return that discounts outflows (investments) at the financing rate,
|
||||
* and reinvests inflows with an expected rate of return.
|
||||
*
|
||||
* Same as =MIRR formula in most spreadsheet software.
|
||||
*
|
||||
* The formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Modified_internal_rate_of_return
|
||||
*
|
||||
* _____________________________
|
||||
* n/ FV(re-invested cash inflows)
|
||||
* - / ---------------------------- - 1.0
|
||||
* \/ PV(discounted cash outflows)
|
||||
*
|
||||
* Examples:
|
||||
* The rate of return of an initial investment of $100 at 5% financing
|
||||
* with returns of $50, $40, and $30 reinvested at 10%:
|
||||
* mirr([-100, 50, 40, 30], 0.05, 0.10)
|
||||
*
|
||||
* @param array<float> $values
|
||||
* @param float $finance_rate
|
||||
* @param float $reinvestment_rate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function mirr(array $values, float $finance_rate, float $reinvestment_rate): float
|
||||
{
|
||||
$inflows = array();
|
||||
$outflows = array();
|
||||
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
if ($values[$i] >= 0) {
|
||||
$inflows[] = $values[$i];
|
||||
$outflows[] = 0;
|
||||
} else {
|
||||
$inflows[] = 0;
|
||||
$outflows[] = $values[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$nonzero = function ($x) {
|
||||
return $x != 0;
|
||||
};
|
||||
|
||||
if (\count(\array_filter($inflows, $nonzero)) == 0 || \count(\array_filter($outflows, $nonzero)) == 0) {
|
||||
return \NAN;
|
||||
}
|
||||
|
||||
$root = \count($values) - 1;
|
||||
$pv_inflows = self::npv($reinvestment_rate, $inflows);
|
||||
$fv_inflows = self::fv($reinvestment_rate, $root, 0, -$pv_inflows);
|
||||
$pv_outflows = self::npv($finance_rate, $outflows);
|
||||
|
||||
return self::checkZero(\pow($fv_inflows / -$pv_outflows, 1 / $root) - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discounted Payback of an investment.
|
||||
* The number of periods to recoup cash outlays of an investment.
|
||||
*
|
||||
* This is commonly used with discount rate=0 as simple payback period,
|
||||
* but it is not a real financial measurement when it doesn't consider the
|
||||
* discount rate. Even with a discount rate, it doesn't consider the cost
|
||||
* of capital or re-investment of returns.
|
||||
*
|
||||
* Avoid this when possible. Consider NPV, MIRR, IRR, and other financial
|
||||
* functions.
|
||||
*
|
||||
* Reference:
|
||||
* https://en.wikipedia.org/wiki/Payback_period
|
||||
*
|
||||
* The result is given assuming cash flows are continous throughout a period.
|
||||
* To compute payback in terms of whole periods, use ceil() on the result.
|
||||
*
|
||||
* An investment could reach its payback period before future cash outlays occur.
|
||||
* The payback period returned is defined to be the final point at which the
|
||||
* sum of returns becomes positive.
|
||||
*
|
||||
* Examples:
|
||||
* The payback period of an investment with a $1,000 investment and future returns
|
||||
* of $100, $200, $300, $400, $500:
|
||||
* payback([-1000, 100, 200, 300, 400, 500])
|
||||
*
|
||||
* The discounted payback period of an investment with a $1,000 investment, future returns
|
||||
* of $100, $200, $300, $400, $500, and a discount rate of 0.10:
|
||||
* payback([-1000, 100, 200, 300, 400, 500], 0.1)
|
||||
*
|
||||
* @param array<float> $values
|
||||
* @param float $rate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function payback(array $values, float $rate = 0.0): float
|
||||
{
|
||||
$last_outflow = -1;
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
if ($values[$i] < 0) {
|
||||
$last_outflow = $i;
|
||||
}
|
||||
}
|
||||
|
||||
if ($last_outflow < 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
$sum = $values[0];
|
||||
$payback_period = -1;
|
||||
|
||||
for ($i = 1; $i < \count($values); $i++) {
|
||||
$prevsum = $sum;
|
||||
$discounted_flow = $values[$i] / (1 + $rate) ** $i;
|
||||
$sum += $discounted_flow;
|
||||
if ($sum >= 0) {
|
||||
if ($i > $last_outflow) {
|
||||
return ($i - 1) + (-$prevsum / $discounted_flow);
|
||||
}
|
||||
if ($payback_period == -1) {
|
||||
$payback_period = ($i - 1) + (-$prevsum / $discounted_flow);
|
||||
}
|
||||
} else {
|
||||
$payback_period = -1;
|
||||
}
|
||||
}
|
||||
if ($sum >= 0) {
|
||||
return $payback_period;
|
||||
}
|
||||
|
||||
return \NAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Profitability Index.
|
||||
* The Profitability Index, also referred to as Profit Investment
|
||||
* Ratio (PIR) and Value Investment Ratio (VIR), is a comparison of
|
||||
* discounted cash inflows to discounted cash outflows. It can be
|
||||
* used as a decision criteria of an investment, using larger than 1
|
||||
* to choose an investment, and less than 1 to pass.
|
||||
*
|
||||
* The formula derivation:
|
||||
* https://en.wikipedia.org/wiki/Profitability_index
|
||||
*
|
||||
* PV(cash inflows)
|
||||
* ----------------
|
||||
* PV(cash outflows)
|
||||
*
|
||||
* The formula is usually stated in terms of the initial investmest,
|
||||
* but it is generalized here to discount all future outflows.
|
||||
*
|
||||
* Examples:
|
||||
* The profitability index of an initial $100 investment with future
|
||||
* returns of $50, $50, $50 with a 10% discount rate:
|
||||
* profitabilityIndex([-100, 50, 50, 50], 0.10)
|
||||
*
|
||||
* @param array<float> $values
|
||||
* @param float $rate
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function profitabilityIndex(array $values, float $rate): float
|
||||
{
|
||||
$inflows = array();
|
||||
$outflows = array();
|
||||
|
||||
for ($i = 0; $i < \count($values); $i++) {
|
||||
if ($values[$i] >= 0) {
|
||||
$inflows[] = $values[$i];
|
||||
$outflows[] = 0;
|
||||
} else {
|
||||
$inflows[] = 0;
|
||||
$outflows[] = -$values[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$nonzero = function ($x) {
|
||||
return $x != 0;
|
||||
};
|
||||
|
||||
if (\count(\array_filter($outflows, $nonzero)) == 0) {
|
||||
return \NAN;
|
||||
}
|
||||
|
||||
$pv_inflows = self::npv($rate, $inflows);
|
||||
$pv_outflows = self::npv($rate, $outflows);
|
||||
|
||||
return $pv_inflows / $pv_outflows;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace MathPHP\NumericalAnalysis\RootFinding;
|
||||
|
||||
use MathPHP\Exception;
|
||||
|
||||
/**
|
||||
* Newton's Method (also known as the Newton–Raphson method)
|
||||
*
|
||||
* In numerical analysis, Newton's method is a method for finding successively better
|
||||
* approximations to the roots (or zeroes) of a real-valued function.
|
||||
*/
|
||||
class NewtonsMethod
|
||||
{
|
||||
/**
|
||||
* Use Newton's Method to find the x which produces $target = $function(x) value
|
||||
* $args is an array of parameters to pass to $function, but having the element that
|
||||
* will be changed and serve as the initial guess in position $position.
|
||||
*
|
||||
* @param callable $function f(x) callback function
|
||||
* @param array<mixed> $args Parameters to pass to callback function. The initial value for the
|
||||
* parameter of interest must be in this array.
|
||||
* @param int|float $target Value of f(x) we a trying to solve for
|
||||
* @param float $tol Tolerance; How close to the actual solution we would like.
|
||||
* @param int $position Which element in the $args array will be changed; also serves as initial guess
|
||||
* @param int $iterations
|
||||
*
|
||||
* @return int|float
|
||||
*
|
||||
* @throws Exception\OutOfBoundsException if the tolerance is not valid
|
||||
*/
|
||||
public static function solve(callable $function, array $args, $target, float $tol, int $position = 0, int $iterations = 100)
|
||||
{
|
||||
Validation::tolerance($tol);
|
||||
|
||||
// Initialize
|
||||
$args1 = $args;
|
||||
$guess = $args[$position];
|
||||
$i = 0;
|
||||
|
||||
do {
|
||||
$args1[$position] = $guess + $tol; // load the initial guess into the arguments
|
||||
$args[$position] = $guess; // load the initial guess into the arguments
|
||||
$y = $function(...$args);
|
||||
$y_at_xplusdelx = $function(...$args1);
|
||||
$slope = ($y_at_xplusdelx - $y) / $tol;
|
||||
$del_y = $target - $y;
|
||||
if (\abs($slope) < $tol) {
|
||||
return \NAN;
|
||||
}
|
||||
$guess = $del_y / $slope + $guess;
|
||||
$dif = \abs($del_y);
|
||||
$i++;
|
||||
} while ($dif > $tol && $i < $iterations);
|
||||
|
||||
if ($dif > $tol) {
|
||||
return \NAN;
|
||||
}
|
||||
return $guess;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace MathPHP\NumericalAnalysis\RootFinding;
|
||||
|
||||
use MathPHP\Exception;
|
||||
|
||||
/**
|
||||
* Common validation methods for root finding techniques
|
||||
*/
|
||||
class Validation
|
||||
{
|
||||
/**
|
||||
* Throw an exception if the tolerance is negative.
|
||||
*
|
||||
* @param int|float $tol Tolerance; How close to the actual solution we would like.
|
||||
*
|
||||
* @throws Exception\OutOfBoundsException if $tol (the tolerance) is negative
|
||||
*/
|
||||
public static function tolerance($tol): void
|
||||
{
|
||||
if ($tol < 0) {
|
||||
throw new Exception\OutOfBoundsException('Tolerance must be greater than zero.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the start and end of of an interval are distinct numbers.
|
||||
*
|
||||
* @param int|float $a The start of the interval
|
||||
* @param int|float $b The end of the interval
|
||||
*
|
||||
* @throws Exception\BadDataException if $a = $b
|
||||
*/
|
||||
public static function interval($a, $b): void
|
||||
{
|
||||
if ($a === $b) {
|
||||
throw new Exception\BadDataException('Start point and end point of interval cannot be the same.');
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user