Functions.php 29 KB

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