Functions.php 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. <?php
  2. namespace Complex;
  3. use InvalidArgumentException;
  4. class Functions
  5. {
  6. /**
  7. * Returns the absolute value (modulus) of a complex number.
  8. * Also known as the rho of the complex number, i.e. the distance/radius
  9. * from the centrepoint to the representation of the number in polar coordinates.
  10. *
  11. * This function is a synonym for rho()
  12. *
  13. * @param Complex|mixed $complex Complex number or a numeric value.
  14. * @return float The absolute (or rho) value of the complex argument.
  15. * @throws Exception If argument isn't a valid real or complex number.
  16. *
  17. * @see rho
  18. *
  19. */
  20. public static function abs($complex): float
  21. {
  22. return self::rho($complex);
  23. }
  24. /**
  25. * Returns the inverse cosine of a complex number.
  26. *
  27. * @param Complex|mixed $complex Complex number or a numeric value.
  28. * @return Complex The inverse cosine of the complex argument.
  29. * @throws Exception If argument isn't a valid real or complex number.
  30. */
  31. public static function acos($complex): Complex
  32. {
  33. $complex = Complex::validateComplexArgument($complex);
  34. $invsqrt = self::sqrt(Operations::subtract(1, Operations::multiply($complex, $complex)));
  35. $adjust = new Complex(
  36. $complex->getReal() - $invsqrt->getImaginary(),
  37. $complex->getImaginary() + $invsqrt->getReal()
  38. );
  39. $log = self::ln($adjust);
  40. return new Complex(
  41. $log->getImaginary(),
  42. -1 * $log->getReal()
  43. );
  44. }
  45. /**
  46. * Returns the inverse hyperbolic cosine of a complex number.
  47. *
  48. * Formula from Wolfram Alpha:
  49. * cosh^(-1)z = ln(z + sqrt(z + 1) sqrt(z - 1)).
  50. *
  51. * @param Complex|mixed $complex Complex number or a numeric value.
  52. * @return Complex The inverse hyperbolic cosine of the complex argument.
  53. * @throws Exception If argument isn't a valid real or complex number.
  54. */
  55. public static function acosh($complex): Complex
  56. {
  57. $complex = Complex::validateComplexArgument($complex);
  58. if ($complex->isReal() && ($complex->getReal() > 1)) {
  59. return new Complex(\acosh($complex->getReal()));
  60. }
  61. $acosh = self::ln(
  62. Operations::add(
  63. $complex,
  64. Operations::multiply(
  65. self::sqrt(Operations::add($complex, 1)),
  66. self::sqrt(Operations::subtract($complex, 1))
  67. )
  68. )
  69. );
  70. return $acosh;
  71. }
  72. /**
  73. * Returns the inverse cotangent of a complex number.
  74. *
  75. * @param Complex|mixed $complex Complex number or a numeric value.
  76. * @return Complex The inverse cotangent of the complex argument.
  77. * @throws Exception If argument isn't a valid real or complex number.
  78. * @throws \InvalidArgumentException If function would result in a division by zero
  79. */
  80. public static function acot($complex): Complex
  81. {
  82. $complex = Complex::validateComplexArgument($complex);
  83. return self::atan(self::inverse($complex));
  84. }
  85. /**
  86. * Returns the inverse hyperbolic cotangent of a complex number.
  87. *
  88. * @param Complex|mixed $complex Complex number or a numeric value.
  89. * @return Complex The inverse hyperbolic cotangent of the complex argument.
  90. * @throws Exception If argument isn't a valid real or complex number.
  91. * @throws \InvalidArgumentException If function would result in a division by zero
  92. */
  93. public static function acoth($complex): Complex
  94. {
  95. $complex = Complex::validateComplexArgument($complex);
  96. return self::atanh(self::inverse($complex));
  97. }
  98. /**
  99. * Returns the inverse cosecant of a complex number.
  100. *
  101. * @param Complex|mixed $complex Complex number or a numeric value.
  102. * @return Complex The inverse cosecant of the complex argument.
  103. * @throws Exception If argument isn't a valid real or complex number.
  104. * @throws \InvalidArgumentException If function would result in a division by zero
  105. */
  106. public static function acsc($complex): Complex
  107. {
  108. $complex = Complex::validateComplexArgument($complex);
  109. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  110. return new Complex(INF);
  111. }
  112. return self::asin(self::inverse($complex));
  113. }
  114. /**
  115. * Returns the inverse hyperbolic cosecant of a complex number.
  116. *
  117. * @param Complex|mixed $complex Complex number or a numeric value.
  118. * @return Complex The inverse hyperbolic cosecant of the complex argument.
  119. * @throws Exception If argument isn't a valid real or complex number.
  120. * @throws \InvalidArgumentException If function would result in a division by zero
  121. */
  122. public static function acsch($complex): Complex
  123. {
  124. $complex = Complex::validateComplexArgument($complex);
  125. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  126. return new Complex(INF);
  127. }
  128. return self::asinh(self::inverse($complex));
  129. }
  130. /**
  131. * Returns the argument of a complex number.
  132. * Also known as the theta of the complex number, i.e. the angle in radians
  133. * from the real axis to the representation of the number in polar coordinates.
  134. *
  135. * This function is a synonym for theta()
  136. *
  137. * @param Complex|mixed $complex Complex number or a numeric value.
  138. * @return float The argument (or theta) value of the complex argument.
  139. * @throws Exception If argument isn't a valid real or complex number.
  140. *
  141. * @see theta
  142. */
  143. public static function argument($complex): float
  144. {
  145. return self::theta($complex);
  146. }
  147. /**
  148. * Returns the inverse secant of a complex number.
  149. *
  150. * @param Complex|mixed $complex Complex number or a numeric value.
  151. * @return Complex The inverse secant of the complex argument.
  152. * @throws Exception If argument isn't a valid real or complex number.
  153. * @throws \InvalidArgumentException If function would result in a division by zero
  154. */
  155. public static function asec($complex): Complex
  156. {
  157. $complex = Complex::validateComplexArgument($complex);
  158. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  159. return new Complex(INF);
  160. }
  161. return self::acos(self::inverse($complex));
  162. }
  163. /**
  164. * Returns the inverse hyperbolic secant of a complex number.
  165. *
  166. * @param Complex|mixed $complex Complex number or a numeric value.
  167. * @return Complex The inverse hyperbolic secant of the complex argument.
  168. * @throws Exception If argument isn't a valid real or complex number.
  169. * @throws \InvalidArgumentException If function would result in a division by zero
  170. */
  171. public static function asech($complex): Complex
  172. {
  173. $complex = Complex::validateComplexArgument($complex);
  174. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  175. return new Complex(INF);
  176. }
  177. return self::acosh(self::inverse($complex));
  178. }
  179. /**
  180. * Returns the inverse sine of a complex number.
  181. *
  182. * @param Complex|mixed $complex Complex number or a numeric value.
  183. * @return Complex The inverse sine of the complex argument.
  184. * @throws Exception If argument isn't a valid real or complex number.
  185. */
  186. public static function asin($complex): Complex
  187. {
  188. $complex = Complex::validateComplexArgument($complex);
  189. $invsqrt = self::sqrt(Operations::subtract(1, Operations::multiply($complex, $complex)));
  190. $adjust = new Complex(
  191. $invsqrt->getReal() - $complex->getImaginary(),
  192. $invsqrt->getImaginary() + $complex->getReal()
  193. );
  194. $log = self::ln($adjust);
  195. return new Complex(
  196. $log->getImaginary(),
  197. -1 * $log->getReal()
  198. );
  199. }
  200. /**
  201. * Returns the inverse hyperbolic sine of a complex number.
  202. *
  203. * @param Complex|mixed $complex Complex number or a numeric value.
  204. * @return Complex The inverse hyperbolic sine of the complex argument.
  205. * @throws Exception If argument isn't a valid real or complex number.
  206. */
  207. public static function asinh($complex): Complex
  208. {
  209. $complex = Complex::validateComplexArgument($complex);
  210. if ($complex->isReal() && ($complex->getReal() > 1)) {
  211. return new Complex(\asinh($complex->getReal()));
  212. }
  213. $asinh = clone $complex;
  214. $asinh = $asinh->reverse()
  215. ->invertReal();
  216. $asinh = self::asin($asinh);
  217. return $asinh->reverse()
  218. ->invertImaginary();
  219. }
  220. /**
  221. * Returns the inverse tangent of a complex number.
  222. *
  223. * @param Complex|mixed $complex Complex number or a numeric value.
  224. * @return Complex The inverse tangent of the complex argument.
  225. * @throws Exception If argument isn't a valid real or complex number.
  226. * @throws \InvalidArgumentException If function would result in a division by zero
  227. */
  228. public static function atan($complex): Complex
  229. {
  230. $complex = Complex::validateComplexArgument($complex);
  231. if ($complex->isReal()) {
  232. return new Complex(\atan($complex->getReal()));
  233. }
  234. $t1Value = new Complex(-1 * $complex->getImaginary(), $complex->getReal());
  235. $uValue = new Complex(1, 0);
  236. $d1Value = clone $uValue;
  237. $d1Value = Operations::subtract($d1Value, $t1Value);
  238. $d2Value = Operations::add($t1Value, $uValue);
  239. $uResult = $d1Value->divideBy($d2Value);
  240. $uResult = self::ln($uResult);
  241. $realMultiplier = -0.5;
  242. $imaginaryMultiplier = 0.5;
  243. if (abs($uResult->getImaginary()) === M_PI) {
  244. // If we have an imaginary value at the max or min (PI or -PI), then we need to ensure
  245. // that the primary is assigned for the correct quadrant.
  246. $realMultiplier = (
  247. ($uResult->getImaginary() === M_PI && $uResult->getReal() > 0.0) ||
  248. ($uResult->getImaginary() === -M_PI && $uResult->getReal() < 0.0)
  249. ) ? 0.5 : -0.5;
  250. }
  251. return new Complex(
  252. $uResult->getImaginary() * $realMultiplier,
  253. $uResult->getReal() * $imaginaryMultiplier,
  254. $complex->getSuffix()
  255. );
  256. }
  257. /**
  258. * Returns the inverse hyperbolic tangent of a complex number.
  259. *
  260. * Formula from Wolfram Alpha:
  261. * tanh^(-1)z = 1/2 [ln(1 + z) - ln(1 - z)].
  262. *
  263. * @param Complex|mixed $complex Complex number or a numeric value.
  264. * @return Complex The inverse hyperbolic tangent of the complex argument.
  265. * @throws Exception If argument isn't a valid real or complex number.
  266. */
  267. public static function atanh($complex): Complex
  268. {
  269. $complex = Complex::validateComplexArgument($complex);
  270. if ($complex->isReal()) {
  271. $real = $complex->getReal();
  272. if ($real >= -1.0 && $real <= 1.0) {
  273. return new Complex(\atanh($real));
  274. } else {
  275. return new Complex(\atanh(1 / $real), (($real < 0.0) ? M_PI_2 : -1 * M_PI_2));
  276. }
  277. }
  278. $atanh = Operations::multiply(
  279. Operations::subtract(
  280. self::ln(Operations::add(1.0, $complex)),
  281. self::ln(Operations::subtract(1.0, $complex))
  282. ),
  283. 0.5
  284. );
  285. return $atanh;
  286. }
  287. /**
  288. * Returns the complex conjugate of a complex number
  289. *
  290. * @param Complex|mixed $complex Complex number or a numeric value.
  291. * @return Complex The conjugate of the complex argument.
  292. * @throws Exception If argument isn't a valid real or complex number.
  293. */
  294. public static function conjugate($complex): Complex
  295. {
  296. $complex = Complex::validateComplexArgument($complex);
  297. return new Complex(
  298. $complex->getReal(),
  299. -1 * $complex->getImaginary(),
  300. $complex->getSuffix()
  301. );
  302. }
  303. /**
  304. * Returns the cosine of a complex number.
  305. *
  306. * @param Complex|mixed $complex Complex number or a numeric value.
  307. * @return Complex The cosine of the complex argument.
  308. * @throws Exception If argument isn't a valid real or complex number.
  309. */
  310. public static function cos($complex): Complex
  311. {
  312. $complex = Complex::validateComplexArgument($complex);
  313. if ($complex->isReal()) {
  314. return new Complex(\cos($complex->getReal()));
  315. }
  316. return self::conjugate(
  317. new Complex(
  318. \cos($complex->getReal()) * \cosh($complex->getImaginary()),
  319. \sin($complex->getReal()) * \sinh($complex->getImaginary()),
  320. $complex->getSuffix()
  321. )
  322. );
  323. }
  324. /**
  325. * Returns the hyperbolic cosine of a complex number.
  326. *
  327. * @param Complex|mixed $complex Complex number or a numeric value.
  328. * @return Complex The hyperbolic cosine of the complex argument.
  329. * @throws Exception If argument isn't a valid real or complex number.
  330. */
  331. public static function cosh($complex): Complex
  332. {
  333. $complex = Complex::validateComplexArgument($complex);
  334. if ($complex->isReal()) {
  335. return new Complex(\cosh($complex->getReal()));
  336. }
  337. return new Complex(
  338. \cosh($complex->getReal()) * \cos($complex->getImaginary()),
  339. \sinh($complex->getReal()) * \sin($complex->getImaginary()),
  340. $complex->getSuffix()
  341. );
  342. }
  343. /**
  344. * Returns the cotangent of a complex number.
  345. *
  346. * @param Complex|mixed $complex Complex number or a numeric value.
  347. * @return Complex The cotangent of the complex argument.
  348. * @throws Exception If argument isn't a valid real or complex number.
  349. * @throws \InvalidArgumentException If function would result in a division by zero
  350. */
  351. public static function cot($complex): Complex
  352. {
  353. $complex = Complex::validateComplexArgument($complex);
  354. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  355. return new Complex(INF);
  356. }
  357. return self::inverse(self::tan($complex));
  358. }
  359. /**
  360. * Returns the hyperbolic cotangent of a complex number.
  361. *
  362. * @param Complex|mixed $complex Complex number or a numeric value.
  363. * @return Complex The hyperbolic cotangent of the complex argument.
  364. * @throws Exception If argument isn't a valid real or complex number.
  365. * @throws \InvalidArgumentException If function would result in a division by zero
  366. */
  367. public static function coth($complex): Complex
  368. {
  369. $complex = Complex::validateComplexArgument($complex);
  370. return self::inverse(self::tanh($complex));
  371. }
  372. /**
  373. * Returns the cosecant of a complex number.
  374. *
  375. * @param Complex|mixed $complex Complex number or a numeric value.
  376. * @return Complex The cosecant of the complex argument.
  377. * @throws Exception If argument isn't a valid real or complex number.
  378. * @throws \InvalidArgumentException If function would result in a division by zero
  379. */
  380. public static function csc($complex): Complex
  381. {
  382. $complex = Complex::validateComplexArgument($complex);
  383. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  384. return new Complex(INF);
  385. }
  386. return self::inverse(self::sin($complex));
  387. }
  388. /**
  389. * Returns the hyperbolic cosecant of a complex number.
  390. *
  391. * @param Complex|mixed $complex Complex number or a numeric value.
  392. * @return Complex The hyperbolic cosecant of the complex argument.
  393. * @throws Exception If argument isn't a valid real or complex number.
  394. * @throws \InvalidArgumentException If function would result in a division by zero
  395. */
  396. public static function csch($complex): Complex
  397. {
  398. $complex = Complex::validateComplexArgument($complex);
  399. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  400. return new Complex(INF);
  401. }
  402. return self::inverse(self::sinh($complex));
  403. }
  404. /**
  405. * Returns the exponential of a complex number.
  406. *
  407. * @param Complex|mixed $complex Complex number or a numeric value.
  408. * @return Complex The exponential of the complex argument.
  409. * @throws Exception If argument isn't a valid real or complex number.
  410. */
  411. public static function exp($complex): Complex
  412. {
  413. $complex = Complex::validateComplexArgument($complex);
  414. if (($complex->getReal() == 0.0) && (\abs($complex->getImaginary()) == M_PI)) {
  415. return new Complex(-1.0, 0.0);
  416. }
  417. $rho = \exp($complex->getReal());
  418. return new Complex(
  419. $rho * \cos($complex->getImaginary()),
  420. $rho * \sin($complex->getImaginary()),
  421. $complex->getSuffix()
  422. );
  423. }
  424. /**
  425. * Returns the inverse of a complex number.
  426. *
  427. * @param Complex|mixed $complex Complex number or a numeric value.
  428. * @return Complex The inverse of the complex argument.
  429. * @throws Exception If argument isn't a valid real or complex number.
  430. * @throws InvalidArgumentException If function would result in a division by zero
  431. */
  432. public static function inverse($complex): Complex
  433. {
  434. $complex = clone Complex::validateComplexArgument($complex);
  435. if ($complex->getReal() == 0.0 && $complex->getImaginary() == 0.0) {
  436. throw new InvalidArgumentException('Division by zero');
  437. }
  438. return $complex->divideInto(1.0);
  439. }
  440. /**
  441. * Returns the natural logarithm of a complex number.
  442. *
  443. * @param Complex|mixed $complex Complex number or a numeric value.
  444. * @return Complex The natural logarithm of the complex argument.
  445. * @throws Exception If argument isn't a valid real or complex number.
  446. * @throws InvalidArgumentException If the real and the imaginary parts are both zero
  447. */
  448. public static function ln($complex): Complex
  449. {
  450. $complex = Complex::validateComplexArgument($complex);
  451. if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
  452. throw new InvalidArgumentException();
  453. }
  454. return new Complex(
  455. \log(self::rho($complex)),
  456. self::theta($complex),
  457. $complex->getSuffix()
  458. );
  459. }
  460. /**
  461. * Returns the base-2 logarithm of a complex number.
  462. *
  463. * @param Complex|mixed $complex Complex number or a numeric value.
  464. * @return Complex The base-2 logarithm of the complex argument.
  465. * @throws Exception If argument isn't a valid real or complex number.
  466. * @throws InvalidArgumentException If the real and the imaginary parts are both zero
  467. */
  468. public static function log2($complex): Complex
  469. {
  470. $complex = Complex::validateComplexArgument($complex);
  471. if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
  472. throw new InvalidArgumentException();
  473. } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
  474. return new Complex(\log($complex->getReal(), 2), 0.0, $complex->getSuffix());
  475. }
  476. return self::ln($complex)
  477. ->multiply(\log(Complex::EULER, 2));
  478. }
  479. /**
  480. * Returns the common logarithm (base 10) of a complex number.
  481. *
  482. * @param Complex|mixed $complex Complex number or a numeric value.
  483. * @return Complex The common logarithm (base 10) of the complex argument.
  484. * @throws Exception If argument isn't a valid real or complex number.
  485. * @throws InvalidArgumentException If the real and the imaginary parts are both zero
  486. */
  487. public static function log10($complex): Complex
  488. {
  489. $complex = Complex::validateComplexArgument($complex);
  490. if (($complex->getReal() == 0.0) && ($complex->getImaginary() == 0.0)) {
  491. throw new InvalidArgumentException();
  492. } elseif (($complex->getReal() > 0.0) && ($complex->getImaginary() == 0.0)) {
  493. return new Complex(\log10($complex->getReal()), 0.0, $complex->getSuffix());
  494. }
  495. return self::ln($complex)
  496. ->multiply(\log10(Complex::EULER));
  497. }
  498. /**
  499. * Returns the negative of a complex number.
  500. *
  501. * @param Complex|mixed $complex Complex number or a numeric value.
  502. * @return Complex The negative value of the complex argument.
  503. * @throws Exception If argument isn't a valid real or complex number.
  504. *
  505. * @see rho
  506. *
  507. */
  508. public static function negative($complex): Complex
  509. {
  510. $complex = Complex::validateComplexArgument($complex);
  511. return new Complex(
  512. -1 * $complex->getReal(),
  513. -1 * $complex->getImaginary(),
  514. $complex->getSuffix()
  515. );
  516. }
  517. /**
  518. * Returns a complex number raised to a power.
  519. *
  520. * @param Complex|mixed $complex Complex number or a numeric value.
  521. * @param float|integer $power The power to raise this value to
  522. * @return Complex The complex argument raised to the real power.
  523. * @throws Exception If the power argument isn't a valid real
  524. */
  525. public static function pow($complex, $power): Complex
  526. {
  527. $complex = Complex::validateComplexArgument($complex);
  528. if (!is_numeric($power)) {
  529. throw new Exception('Power argument must be a real number');
  530. }
  531. if ($complex->getImaginary() == 0.0 && $complex->getReal() >= 0.0) {
  532. return new Complex(\pow($complex->getReal(), $power));
  533. }
  534. $rValue = \sqrt(($complex->getReal() * $complex->getReal()) + ($complex->getImaginary() * $complex->getImaginary()));
  535. $rPower = \pow($rValue, $power);
  536. $theta = $complex->argument() * $power;
  537. if ($theta == 0) {
  538. return new Complex(1);
  539. }
  540. return new Complex($rPower * \cos($theta), $rPower * \sin($theta), $complex->getSuffix());
  541. }
  542. /**
  543. * Returns the rho of a complex number.
  544. * This is the distance/radius from the centrepoint to the representation of the number in polar coordinates.
  545. *
  546. * @param Complex|mixed $complex Complex number or a numeric value.
  547. * @return float The rho value of the complex argument.
  548. * @throws Exception If argument isn't a valid real or complex number.
  549. */
  550. public static function rho($complex): float
  551. {
  552. $complex = Complex::validateComplexArgument($complex);
  553. return \sqrt(
  554. ($complex->getReal() * $complex->getReal()) +
  555. ($complex->getImaginary() * $complex->getImaginary())
  556. );
  557. }
  558. /**
  559. * Returns the secant of a complex number.
  560. *
  561. * @param Complex|mixed $complex Complex number or a numeric value.
  562. * @return Complex The secant of the complex argument.
  563. * @throws Exception If argument isn't a valid real or complex number.
  564. * @throws \InvalidArgumentException If function would result in a division by zero
  565. */
  566. public static function sec($complex): Complex
  567. {
  568. $complex = Complex::validateComplexArgument($complex);
  569. return self::inverse(self::cos($complex));
  570. }
  571. /**
  572. * Returns the hyperbolic secant of a complex number.
  573. *
  574. * @param Complex|mixed $complex Complex number or a numeric value.
  575. * @return Complex The hyperbolic secant of the complex argument.
  576. * @throws Exception If argument isn't a valid real or complex number.
  577. * @throws \InvalidArgumentException If function would result in a division by zero
  578. */
  579. public static function sech($complex): Complex
  580. {
  581. $complex = Complex::validateComplexArgument($complex);
  582. return self::inverse(self::cosh($complex));
  583. }
  584. /**
  585. * Returns the sine of a complex number.
  586. *
  587. * @param Complex|mixed $complex Complex number or a numeric value.
  588. * @return Complex The sine of the complex argument.
  589. * @throws Exception If argument isn't a valid real or complex number.
  590. */
  591. public static function sin($complex): Complex
  592. {
  593. $complex = Complex::validateComplexArgument($complex);
  594. if ($complex->isReal()) {
  595. return new Complex(\sin($complex->getReal()));
  596. }
  597. return new Complex(
  598. \sin($complex->getReal()) * \cosh($complex->getImaginary()),
  599. \cos($complex->getReal()) * \sinh($complex->getImaginary()),
  600. $complex->getSuffix()
  601. );
  602. }
  603. /**
  604. * Returns the hyperbolic sine of a complex number.
  605. *
  606. * @param Complex|mixed $complex Complex number or a numeric value.
  607. * @return Complex The hyperbolic sine of the complex argument.
  608. * @throws Exception If argument isn't a valid real or complex number.
  609. */
  610. public static function sinh($complex): Complex
  611. {
  612. $complex = Complex::validateComplexArgument($complex);
  613. if ($complex->isReal()) {
  614. return new Complex(\sinh($complex->getReal()));
  615. }
  616. return new Complex(
  617. \sinh($complex->getReal()) * \cos($complex->getImaginary()),
  618. \cosh($complex->getReal()) * \sin($complex->getImaginary()),
  619. $complex->getSuffix()
  620. );
  621. }
  622. /**
  623. * Returns the square root of a complex number.
  624. *
  625. * @param Complex|mixed $complex Complex number or a numeric value.
  626. * @return Complex The Square root of the complex argument.
  627. * @throws Exception If argument isn't a valid real or complex number.
  628. */
  629. public static function sqrt($complex): Complex
  630. {
  631. $complex = Complex::validateComplexArgument($complex);
  632. $theta = self::theta($complex);
  633. $delta1 = \cos($theta / 2);
  634. $delta2 = \sin($theta / 2);
  635. $rho = \sqrt(self::rho($complex));
  636. return new Complex($delta1 * $rho, $delta2 * $rho, $complex->getSuffix());
  637. }
  638. /**
  639. * Returns the tangent of a complex number.
  640. *
  641. * @param Complex|mixed $complex Complex number or a numeric value.
  642. * @return Complex The tangent of the complex argument.
  643. * @throws Exception If argument isn't a valid real or complex number.
  644. * @throws InvalidArgumentException If function would result in a division by zero
  645. */
  646. public static function tan($complex): Complex
  647. {
  648. $complex = Complex::validateComplexArgument($complex);
  649. if ($complex->isReal()) {
  650. return new Complex(\tan($complex->getReal()));
  651. }
  652. $real = $complex->getReal();
  653. $imaginary = $complex->getImaginary();
  654. $divisor = 1 + \pow(\tan($real), 2) * \pow(\tanh($imaginary), 2);
  655. if ($divisor == 0.0) {
  656. throw new InvalidArgumentException('Division by zero');
  657. }
  658. return new Complex(
  659. \pow(self::sech($imaginary)->getReal(), 2) * \tan($real) / $divisor,
  660. \pow(self::sec($real)->getReal(), 2) * \tanh($imaginary) / $divisor,
  661. $complex->getSuffix()
  662. );
  663. }
  664. /**
  665. * Returns the hyperbolic tangent of a complex number.
  666. *
  667. * @param Complex|mixed $complex Complex number or a numeric value.
  668. * @return Complex The hyperbolic tangent of the complex argument.
  669. * @throws Exception If argument isn't a valid real or complex number.
  670. * @throws \InvalidArgumentException If function would result in a division by zero
  671. */
  672. public static function tanh($complex): Complex
  673. {
  674. $complex = Complex::validateComplexArgument($complex);
  675. $real = $complex->getReal();
  676. $imaginary = $complex->getImaginary();
  677. $divisor = \cos($imaginary) * \cos($imaginary) + \sinh($real) * \sinh($real);
  678. if ($divisor == 0.0) {
  679. throw new InvalidArgumentException('Division by zero');
  680. }
  681. return new Complex(
  682. \sinh($real) * \cosh($real) / $divisor,
  683. 0.5 * \sin(2 * $imaginary) / $divisor,
  684. $complex->getSuffix()
  685. );
  686. }
  687. /**
  688. * Returns the theta of a complex number.
  689. * This is the angle in radians from the real axis to the representation of the number in polar coordinates.
  690. *
  691. * @param Complex|mixed $complex Complex number or a numeric value.
  692. * @return float The theta value of the complex argument.
  693. * @throws Exception If argument isn't a valid real or complex number.
  694. */
  695. public static function theta($complex): float
  696. {
  697. $complex = Complex::validateComplexArgument($complex);
  698. if ($complex->getReal() == 0.0) {
  699. if ($complex->isReal()) {
  700. return 0.0;
  701. } elseif ($complex->getImaginary() < 0.0) {
  702. return M_PI / -2;
  703. }
  704. return M_PI / 2;
  705. } elseif ($complex->getReal() > 0.0) {
  706. return \atan($complex->getImaginary() / $complex->getReal());
  707. } elseif ($complex->getImaginary() < 0.0) {
  708. return -(M_PI - \atan(\abs($complex->getImaginary()) / \abs($complex->getReal())));
  709. }
  710. return M_PI - \atan($complex->getImaginary() / \abs($complex->getReal()));
  711. }
  712. }