Move Bessel function calculations from the Engineering class to a dedicated Engineering\Bessel<x> classes (#1846)

* Move Bessel function calculations from the Engineering class to a dedicated Engineering\Bessel class
Retain the original methods in the Engineering class as stubs for BC, but deprecate them. They will be removed for PHPSpreadsheet v2
* Some refactoring of the Bessel calculation logic
* Fix callable for ConvertUOM()
This commit is contained in:
Mark Baker 2021-02-12 17:55:53 +01:00 committed by GitHub
parent 17f405cf62
commit 2aa4a28863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 373 additions and 210 deletions

View File

@ -363,22 +363,22 @@ class Calculation
], ],
'BESSELI' => [ 'BESSELI' => [
'category' => Category::CATEGORY_ENGINEERING, 'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BESSELI'], 'functionCall' => [Engineering\BesselI::class, 'BESSELI'],
'argumentCount' => '2', 'argumentCount' => '2',
], ],
'BESSELJ' => [ 'BESSELJ' => [
'category' => Category::CATEGORY_ENGINEERING, 'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BESSELJ'], 'functionCall' => [Engineering\BesselJ::class, 'BESSELJ'],
'argumentCount' => '2', 'argumentCount' => '2',
], ],
'BESSELK' => [ 'BESSELK' => [
'category' => Category::CATEGORY_ENGINEERING, 'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BESSELK'], 'functionCall' => [Engineering\BesselK::class, 'BESSELK'],
'argumentCount' => '2', 'argumentCount' => '2',
], ],
'BESSELY' => [ 'BESSELY' => [
'category' => Category::CATEGORY_ENGINEERING, 'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'BESSELY'], 'functionCall' => [Engineering\BesselY::class, 'BESSELY'],
'argumentCount' => '2', 'argumentCount' => '2',
], ],
'BETADIST' => [ 'BETADIST' => [
@ -594,7 +594,7 @@ class Calculation
], ],
'CONVERT' => [ 'CONVERT' => [
'category' => Category::CATEGORY_ENGINEERING, 'category' => Category::CATEGORY_ENGINEERING,
'functionCall' => [Engineering::class, 'CONVERTUOM'], 'functionCall' => [Engineering\ConvertUOM::class, 'CONVERT'],
'argumentCount' => '3', 'argumentCount' => '3',
], ],
'CORREL' => [ 'CORREL' => [

View File

@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Calculation;
use Complex\Complex; use Complex\Complex;
use Complex\Exception as ComplexException; use Complex\Exception as ComplexException;
use PhpOffice\PhpSpreadsheet\Calculation\Engineering\Bessel;
use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM; use PhpOffice\PhpSpreadsheet\Calculation\Engineering\ConvertUOM;
class Engineering class Engineering
@ -73,6 +74,8 @@ class Engineering
* Excel Function: * Excel Function:
* BESSELI(x,ord) * BESSELI(x,ord)
* *
* @Deprecated 2.0.0 Use the BESSELI() method in the Engineering\BesselI class instead
*
* @param float $x The value at which to evaluate the function. * @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELI returns the #VALUE! error value. * If x is nonnumeric, BESSELI returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. * @param int $ord The order of the Bessel function.
@ -84,38 +87,7 @@ class Engineering
*/ */
public static function BESSELI($x, $ord) public static function BESSELI($x, $ord)
{ {
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); return Engineering\BesselI::BESSELI($x, $ord);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
$ord = floor($ord);
if ($ord < 0) {
return Functions::NAN();
}
if (abs($x) <= 30) {
$fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord);
$ordK = 1;
$fSqrX = ($x * $x) / 4;
do {
$fTerm *= $fSqrX;
$fTerm /= ($ordK * ($ordK + $ord));
$fResult += $fTerm;
} while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
} else {
$f_2_PI = 2 * M_PI;
$fXAbs = abs($x);
$fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
if (($ord & 1) && ($x < 0)) {
$fResult = -$fResult;
}
}
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
}
return Functions::VALUE();
} }
/** /**
@ -126,6 +98,8 @@ class Engineering
* Excel Function: * Excel Function:
* BESSELJ(x,ord) * BESSELJ(x,ord)
* *
* @Deprecated 2.0.0 Use the BESSELJ() method in the Engineering\BesselJ class instead
*
* @param float $x The value at which to evaluate the function. * @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELJ returns the #VALUE! error value. * If x is nonnumeric, BESSELJ returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
@ -136,76 +110,7 @@ class Engineering
*/ */
public static function BESSELJ($x, $ord) public static function BESSELJ($x, $ord)
{ {
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); return Engineering\BesselJ::BESSELJ($x, $ord);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
$ord = floor($ord);
if ($ord < 0) {
return Functions::NAN();
}
$fResult = 0;
if (abs($x) <= 30) {
$fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord);
$ordK = 1;
$fSqrX = ($x * $x) / -4;
do {
$fTerm *= $fSqrX;
$fTerm /= ($ordK * ($ordK + $ord));
$fResult += $fTerm;
} while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
} else {
$f_PI_DIV_2 = M_PI / 2;
$f_PI_DIV_4 = M_PI / 4;
$fXAbs = abs($x);
$fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4);
if (($ord & 1) && ($x < 0)) {
$fResult = -$fResult;
}
}
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
}
return Functions::VALUE();
}
private static function besselK0($fNum)
{
if ($fNum <= 2) {
$fNum2 = $fNum * 0.5;
$y = ($fNum2 * $fNum2);
$fRet = -log($fNum2) * self::BESSELI($fNum, 0) +
(-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
(0.10750e-3 + $y * 0.74e-5))))));
} else {
$y = 2 / $fNum;
$fRet = exp(-$fNum) / sqrt($fNum) *
(1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
(0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
}
return $fRet;
}
private static function besselK1($fNum)
{
if ($fNum <= 2) {
$fNum2 = $fNum * 0.5;
$y = ($fNum2 * $fNum2);
$fRet = log($fNum2) * self::BESSELI($fNum, 1) +
(1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
(-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
} else {
$y = 2 / $fNum;
$fRet = exp(-$fNum) / sqrt($fNum) *
(1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
(0.325614e-2 + $y * (-0.68245e-3)))))));
}
return $fRet;
} }
/** /**
@ -217,6 +122,8 @@ class Engineering
* Excel Function: * Excel Function:
* BESSELK(x,ord) * BESSELK(x,ord)
* *
* @Deprecated 2.0.0 Use the BESSELK() method in the Engineering\BesselK class instead
*
* @param float $x The value at which to evaluate the function. * @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELK returns the #VALUE! error value. * If x is nonnumeric, BESSELK returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
@ -227,73 +134,7 @@ class Engineering
*/ */
public static function BESSELK($x, $ord) public static function BESSELK($x, $ord)
{ {
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); return Engineering\BesselK::BESSELK($x, $ord);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
if (($ord < 0) || ($x == 0.0)) {
return Functions::NAN();
}
switch (floor($ord)) {
case 0:
$fBk = self::besselK0($x);
break;
case 1:
$fBk = self::besselK1($x);
break;
default:
$fTox = 2 / $x;
$fBkm = self::besselK0($x);
$fBk = self::besselK1($x);
for ($n = 1; $n < $ord; ++$n) {
$fBkp = $fBkm + $n * $fTox * $fBk;
$fBkm = $fBk;
$fBk = $fBkp;
}
}
return (is_nan($fBk)) ? Functions::NAN() : $fBk;
}
return Functions::VALUE();
}
private static function besselY0($fNum)
{
if ($fNum < 8.0) {
$y = ($fNum * $fNum);
$f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y * (-86327.92757 + $y * 228.4622733))));
$f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y * (47447.26470 + $y * (226.1030244 + $y))));
$fRet = $f1 / $f2 + 0.636619772 * self::BESSELJ($fNum, 0) * log($fNum);
} else {
$z = 8.0 / $fNum;
$y = ($z * $z);
$xx = $fNum - 0.785398164;
$f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
$f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y * (-0.934945152e-7))));
$fRet = sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
}
return $fRet;
}
private static function besselY1($fNum)
{
if ($fNum < 8.0) {
$y = ($fNum * $fNum);
$f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y * (0.7349264551e9 + $y *
(-0.4237922726e7 + $y * 0.8511937935e4)))));
$f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
(0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
$fRet = $f1 / $f2 + 0.636619772 * (self::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
} else {
$fRet = sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
}
return $fRet;
} }
/** /**
@ -304,48 +145,19 @@ class Engineering
* Excel Function: * Excel Function:
* BESSELY(x,ord) * BESSELY(x,ord)
* *
* @Deprecated 2.0.0 Use the BESSELY() method in the Engineering\BesselY class instead
*
* @param float $x The value at which to evaluate the function. * @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELK returns the #VALUE! error value. * If x is nonnumeric, BESSELY returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated. * @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value. * If $ord is nonnumeric, BESSELY returns the #VALUE! error value.
* If $ord < 0, BESSELK returns the #NUM! error value. * If $ord < 0, BESSELY returns the #NUM! error value.
* *
* @return float|string Result, or a string containing an error * @return float|string Result, or a string containing an error
*/ */
public static function BESSELY($x, $ord) public static function BESSELY($x, $ord)
{ {
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x); return Engineering\BesselY::BESSELY($x, $ord);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
if (($ord < 0) || ($x == 0.0)) {
return Functions::NAN();
}
switch (floor($ord)) {
case 0:
$fBy = self::besselY0($x);
break;
case 1:
$fBy = self::besselY1($x);
break;
default:
$fTox = 2 / $x;
$fBym = self::besselY0($x);
$fBy = self::besselY1($x);
for ($n = 1; $n < $ord; ++$n) {
$fByp = $n * $fTox * $fBy - $fBym;
$fBym = $fBy;
$fBy = $fByp;
}
}
return (is_nan($fBy)) ? Functions::NAN() : $fBy;
}
return Functions::VALUE();
} }
/** /**
@ -1882,7 +1694,7 @@ class Engineering
* getConversionGroups * getConversionGroups
* Returns a list of the different conversion groups for UOM conversions. * Returns a list of the different conversion groups for UOM conversions.
* *
* @Deprecated Use the getConversionCategories() method in the ConvertUOM class instead * @Deprecated 2.0.0 Use the getConversionCategories() method in the Engineering\ConvertUOM class instead
* *
* @return array * @return array
*/ */

View File

@ -0,0 +1,72 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
class BesselI
{
/**
* BESSELI.
*
* Returns the modified Bessel function In(x), which is equivalent to the Bessel function evaluated
* for purely imaginary arguments
*
* Excel Function:
* BESSELI(x,ord)
*
* @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELI returns the #VALUE! error value.
* @param int $ord The order of the Bessel function.
* If ord is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELI returns the #VALUE! error value.
* If $ord < 0, BESSELI returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
*/
public static function BESSELI($x, $ord)
{
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
$ord = (int) floor($ord);
if ($ord < 0) {
return Functions::NAN();
}
$fResult = self::calculate($x, $ord);
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
}
return Functions::VALUE();
}
private static function calculate(float $x, int $ord): float
{
if (abs($x) <= 30) {
$fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord);
$ordK = 1;
$fSqrX = ($x * $x) / 4;
do {
$fTerm *= $fSqrX;
$fTerm /= ($ordK * ($ordK + $ord));
$fResult += $fTerm;
} while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
return $fResult;
}
$f_2_PI = 2 * M_PI;
$fXAbs = abs($x);
$fResult = exp($fXAbs) / sqrt($f_2_PI * $fXAbs);
if (($ord & 1) && ($x < 0)) {
$fResult = -$fResult;
}
return $fResult;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
class BesselJ
{
/**
* BESSELJ.
*
* Returns the Bessel function
*
* Excel Function:
* BESSELJ(x,ord)
*
* @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELJ returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELJ returns the #VALUE! error value.
* If $ord < 0, BESSELJ returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
*/
public static function BESSELJ($x, $ord)
{
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
$ord = ($ord === null) ? 0.0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
$ord = (int) floor($ord);
if ($ord < 0) {
return Functions::NAN();
}
$fResult = self::calculate($x, $ord);
return (is_nan($fResult)) ? Functions::NAN() : $fResult;
}
return Functions::VALUE();
}
private static function calculate(float $x, int $ord): float
{
if (abs($x) <= 30) {
$fResult = $fTerm = ($x / 2) ** $ord / MathTrig::FACT($ord);
$ordK = 1;
$fSqrX = ($x * $x) / -4;
do {
$fTerm *= $fSqrX;
$fTerm /= ($ordK * ($ordK + $ord));
$fResult += $fTerm;
} while ((abs($fTerm) > 1e-12) && (++$ordK < 100));
return $fResult;
}
$f_PI_DIV_2 = M_PI / 2;
$f_PI_DIV_4 = M_PI / 4;
$fXAbs = abs($x);
$fResult = sqrt(Functions::M_2DIVPI / $fXAbs) * cos($fXAbs - $ord * $f_PI_DIV_2 - $f_PI_DIV_4);
if (($ord & 1) && ($x < 0)) {
$fResult = -$fResult;
}
return $fResult;
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselK
{
/**
* BESSELK.
*
* Returns the modified Bessel function Kn(x), which is equivalent to the Bessel functions evaluated
* for purely imaginary arguments.
*
* Excel Function:
* BESSELK(x,ord)
*
* @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELK returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELK returns the #VALUE! error value.
* If $ord < 0, BESSELK returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
*/
public static function BESSELK($x, $ord)
{
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
if (($ord < 0) || ($x == 0.0)) {
return Functions::NAN();
}
switch (floor($ord)) {
case 0:
$fBk = self::besselK0($x);
break;
case 1:
$fBk = self::besselK1($x);
break;
default:
$fBk = self::besselK2($x, $ord);
}
return (is_nan($fBk)) ? Functions::NAN() : $fBk;
}
return Functions::VALUE();
}
private static function besselK0(float $fNum): float
{
if ($fNum <= 2) {
$fNum2 = $fNum * 0.5;
$y = ($fNum2 * $fNum2);
return -log($fNum2) * BesselI::BESSELI($fNum, 0) +
(-0.57721566 + $y * (0.42278420 + $y * (0.23069756 + $y * (0.3488590e-1 + $y * (0.262698e-2 + $y *
(0.10750e-3 + $y * 0.74e-5))))));
}
$y = 2 / $fNum;
return exp(-$fNum) / sqrt($fNum) *
(1.25331414 + $y * (-0.7832358e-1 + $y * (0.2189568e-1 + $y * (-0.1062446e-1 + $y *
(0.587872e-2 + $y * (-0.251540e-2 + $y * 0.53208e-3))))));
}
private static function besselK1(float $fNum): float
{
if ($fNum <= 2) {
$fNum2 = $fNum * 0.5;
$y = ($fNum2 * $fNum2);
return log($fNum2) * BesselI::BESSELI($fNum, 1) +
(1 + $y * (0.15443144 + $y * (-0.67278579 + $y * (-0.18156897 + $y * (-0.1919402e-1 + $y *
(-0.110404e-2 + $y * (-0.4686e-4))))))) / $fNum;
}
$y = 2 / $fNum;
return exp(-$fNum) / sqrt($fNum) *
(1.25331414 + $y * (0.23498619 + $y * (-0.3655620e-1 + $y * (0.1504268e-1 + $y * (-0.780353e-2 + $y *
(0.325614e-2 + $y * (-0.68245e-3)))))));
}
private static function besselK2(float $x, int $ord)
{
$fTox = 2 / $x;
$fBkm = self::besselK0($x);
$fBk = self::besselK1($x);
for ($n = 1; $n < $ord; ++$n) {
$fBkp = $fBkm + $n * $fTox * $fBk;
$fBkm = $fBk;
$fBk = $fBkp;
}
return $fBk;
}
}

View File

@ -0,0 +1,104 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class BesselY
{
/**
* BESSELY.
*
* Returns the Bessel function, which is also called the Weber function or the Neumann function.
*
* Excel Function:
* BESSELY(x,ord)
*
* @param float $x The value at which to evaluate the function.
* If x is nonnumeric, BESSELY returns the #VALUE! error value.
* @param int $ord The order of the Bessel function. If n is not an integer, it is truncated.
* If $ord is nonnumeric, BESSELY returns the #VALUE! error value.
* If $ord < 0, BESSELY returns the #NUM! error value.
*
* @return float|string Result, or a string containing an error
*/
public static function BESSELY($x, $ord)
{
$x = ($x === null) ? 0.0 : Functions::flattenSingleValue($x);
$ord = ($ord === null) ? 0 : Functions::flattenSingleValue($ord);
if ((is_numeric($x)) && (is_numeric($ord))) {
if (($ord < 0) || ($x == 0.0)) {
return Functions::NAN();
}
switch (floor($ord)) {
case 0:
$fBy = self::besselY0($x);
break;
case 1:
$fBy = self::besselY1($x);
break;
default:
$fBy = self::besselY2($x, $ord);
}
return (is_nan($fBy)) ? Functions::NAN() : $fBy;
}
return Functions::VALUE();
}
private static function besselY0(float $fNum): float
{
if ($fNum < 8.0) {
$y = ($fNum * $fNum);
$f1 = -2957821389.0 + $y * (7062834065.0 + $y * (-512359803.6 + $y * (10879881.29 + $y *
(-86327.92757 + $y * 228.4622733))));
$f2 = 40076544269.0 + $y * (745249964.8 + $y * (7189466.438 + $y *
(47447.26470 + $y * (226.1030244 + $y))));
return $f1 / $f2 + 0.636619772 * BesselJ::BESSELJ($fNum, 0) * log($fNum);
}
$z = 8.0 / $fNum;
$y = ($z * $z);
$xx = $fNum - 0.785398164;
$f1 = 1 + $y * (-0.1098628627e-2 + $y * (0.2734510407e-4 + $y * (-0.2073370639e-5 + $y * 0.2093887211e-6)));
$f2 = -0.1562499995e-1 + $y * (0.1430488765e-3 + $y * (-0.6911147651e-5 + $y * (0.7621095161e-6 + $y *
(-0.934945152e-7))));
return sqrt(0.636619772 / $fNum) * (sin($xx) * $f1 + $z * cos($xx) * $f2);
}
private static function besselY1(float $fNum): float
{
if ($fNum < 8.0) {
$y = ($fNum * $fNum);
$f1 = $fNum * (-0.4900604943e13 + $y * (0.1275274390e13 + $y * (-0.5153438139e11 + $y *
(0.7349264551e9 + $y * (-0.4237922726e7 + $y * 0.8511937935e4)))));
$f2 = 0.2499580570e14 + $y * (0.4244419664e12 + $y * (0.3733650367e10 + $y * (0.2245904002e8 + $y *
(0.1020426050e6 + $y * (0.3549632885e3 + $y)))));
return $f1 / $f2 + 0.636619772 * (BesselJ::BESSELJ($fNum, 1) * log($fNum) - 1 / $fNum);
}
return sqrt(0.636619772 / $fNum) * sin($fNum - 2.356194491);
}
private static function besselY2(float $x, int $ord)
{
$fTox = 2 / $x;
$fBym = self::besselY0($x);
$fBy = self::besselY1($x);
for ($n = 1; $n < $ord; ++$n) {
$fByp = $n * $fTox * $fBy - $fBym;
$fBym = $fBy;
$fBy = $fByp;
}
return $fBy;
}
}