綟N5NRvBomԄjFq9yΣbH_ =* vv#)F.[`Dʼn j)] 9"If ]t]mt񒜠FuCO|ޛuňev*k+|YrVi'@ L?O!LrCnpR”?S,Is~V"`a鄱!n59?G,; %gmiXڑ IQ"].ƦsF++w뺲ǏqKpAxf|GgCc.1'm]n z7s0USG~d%PoWtmЗJ\Lc.3m(L T@zh{פ}1E <+(3rL[?c2W*UGE?KөZ.T@~ģ lrdTv '#x鲴͛Xf:V€z nD؄ cI<}ЫIǦr #WrLj甊ĨI5sp"U@wKR4 g $DA䊞1?e6AԐ=^cjƦ݉U7 dnN-@ߕFߦ'I7p(8Ⱥ Hg;yd<:W;[' .vJIXoḷ݉U7 dnN,itK aLeʳ %xӉ&UMBmQÆĘ$`\8қ툕C&Q!(Ao "ĤW]"Ԇ Ւn}1 Ho/g7dQ^y/Hɋ墨Ke]FjZnq֨YAb}j?X)lnKMd"eaey*ĵN5(K5)&? T|in B]E{!!٣R4%=(ԴL iswH歇nnn{o!'*&?Wą(9኷ ,P) ĢQ$3,b ayʵw^?^_.(d:~qBmZPnKVR#?:Bd~,b ayʵw^?^p3$7$Gq 9Tl8ЅŰE9W@j0zѤ/ad5v5B `S_!㻒1eupH]"i͖;y[T K:F tDbܾ;hAC*ހͷ} ">\Os ĢQ$3)HV]K#x0ZvaMit٭=K}-΍_/z $[4:1{.7Nپ4{/6Zɒ6C@՛wf97Vڈꖷvi_a;Lxխ)x}_g-|h9R5@}kH]"i͖;y[T K:F ;?.@!?\L,JX_-Sn ĢQ$3ϔ©NªW f*Ci)cc zce3lBc-k ĢQ$3I? `NlD¦n_<0W9aٳeΏVULc8'( ĢQ$3(bLm-0YKyMhPh\3F3숌-z9 R}=ɱ7(1 {{X&<_ )ݠXٮ6ŚL gs*o\?dl +֝^5fzBE$RS {uM3xN EIHeV+uh9/B2|=T vsqL;'nj%Xi;r-zQM-N}7NUQ.5^1(]?<>-vI\5]|Ȑ8/ CljrkuS%wr99U=aczHVS}ذ| yXOdf,3:.o6CLˤ["uHjn!~]#]jJ(mYvn4z LJ'ͅT8@F!;A:=m![ L0N-˥-2 zæQ X=5Czm5+U.8n;LhzG羭s*߈Y{8Fn>4Z$>rDY+,ҧo{Z .:#yqT*`gr9&ـ{)KLfUTP-2c~ڲ KuX*SvjR7+WhD wVtZ;K9ZT!R V>,SQ3;{prLsI*p\b8t7c-< 4_~{Q4F@DzqtCB@_r7냤n߯SȬ."\x@o^@XAti:P i3! 4)愡Oo-&׬}teN)S|(95M*IZ]empE#j#Ҭq##(%#q̺U\G^W}#.*]b9QsFӋ啕3"@dk!u\jFI*ߏG]bN}:] c> V-%˼bw1m iॹu0_j``P _y g0;,oKҀ(-س}5qѮ art, so test to see if we actually have a suffix $validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts); if (!$validComplex) { throw new Exception('Invalid complex number'); } // We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign) $imaginary = 1; if ($complexParts[1] === '-') { $imaginary = 0 - $imaginary; } return [0, $imaginary, $complexParts[2]]; } // If we don't have an imaginary part, identify whether it should be +1 or -1... if (($complexParts[4] === '') && ($complexParts[9] !== '')) { if ($complexParts[7] !== $complexParts[9]) { $complexParts[4] = 1; if ($complexParts[8] === '-') { $complexParts[4] = -1; } } else { // ... or if we have only the real and no imaginary part // (in which case our real should be the imaginary) $complexParts[4] = $complexParts[1]; $complexParts[1] = 0; } } // Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily return [ $complexParts[1], $complexParts[4], !empty($complexParts[9]) ? $complexParts[9] : 'i' ]; } public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i') { if ($imaginaryPart === null) { if (is_array($realPart)) { // We have an array of (potentially) real and imaginary parts, and any suffix list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i']; } elseif ((is_string($realPart)) || (is_numeric($realPart))) { // We've been given a string to parse to extract the real and imaginary parts, and any suffix list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart); } } if ($imaginaryPart != 0.0 && empty($suffix)) { $suffix = 'i'; } elseif ($imaginaryPart == 0.0 && !empty($suffix)) { $suffix = ''; } // Set parsed values in our properties $this->realPart = (float) $realPart; $this->imaginaryPart = (float) $imaginaryPart; $this->suffix = strtolower($suffix ?? ''); } /** * Gets the real part of this complex number * * @return Float */ public function getReal(): float { return $this->realPart; } /** * Gets the imaginary part of this complex number * * @return Float */ public function getImaginary(): float { return $this->imaginaryPart; } /** * Gets the suffix of this complex number * * @return String */ public function getSuffix(): string { return $this->suffix; } /** * Returns true if this is a real value, false if a complex value * * @return Bool */ public function isReal(): bool { return $this->imaginaryPart == 0.0; } /** * Returns true if this is a complex value, false if a real value * * @return Bool */ public function isComplex(): bool { return !$this->isReal(); } public function format(): string { $str = ""; if ($this->imaginaryPart != 0.0) { if (\abs($this->imaginaryPart) != 1.0) { $str .= $this->imaginaryPart . $this->suffix; } else { $str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix; } } if ($this->realPart != 0.0) { if (($str) && ($this->imaginaryPart > 0.0)) { $str = "+" . $str; } $str = $this->realPart . $str; } if (!$str) { $str = "0.0"; } return $str; } public function __toString(): string { return $this->format(); } /** * Validates whether the argument is a valid complex number, converting scalar or array values if possible * * @param mixed $complex The value to validate * @return Complex * @throws Exception If the argument isn't a Complex number or cannot be converted to one */ public static function validateComplexArgument($complex): Complex { if (is_scalar($complex) || is_array($complex)) { $complex = new Complex($complex); } elseif (!is_object($complex) || !($complex instanceof Complex)) { throw new Exception('Value is not a valid complex number'); } return $complex; } /** * Returns the reverse of this complex number * * @return Complex */ public function reverse(): Complex { return new Complex( $this->imaginaryPart, $this->realPart, ($this->realPart == 0.0) ? null : $this->suffix ); } public function invertImaginary(): Complex { return new Complex( $this->realPart, $this->imaginaryPart * -1, ($this->imaginaryPart == 0.0) ? null : $this->suffix ); } public function invertReal(): Complex { return new Complex( $this->realPart * -1, $this->imaginaryPart, ($this->imaginaryPart == 0.0) ? null : $this->suffix ); } protected static $functions = [ 'abs', 'acos', 'acosh', 'acot', 'acoth', 'acsc', 'acsch', 'argument', 'asec', 'asech', 'asin', 'asinh', 'atan', 'atanh', 'conjugate', 'cos', 'cosh', 'cot', 'coth', 'csc', 'csch', 'exp', 'inverse', 'ln', 'log2', 'log10', 'negative', 'pow', 'rho', 'sec', 'sech', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'theta', ]; protected static $operations = [ 'add', 'subtract', 'multiply', 'divideby', 'divideinto', ]; /** * Returns the result of the function call or operation * * @return Complex|float * @throws Exception|\InvalidArgumentException */ public function __call($functionName, $arguments) { $functionName = strtolower(str_replace('_', '', $functionName)); // Test for function calls if (in_array($functionName, self::$functions, true)) { return Functions::$functionName($this, ...$arguments); } // Test for operation calls if (in_array($functionName, self::$operations, true)) { return Operations::$functionName($this, ...$arguments); } throw new Exception('Complex Function or Operation does not exist'); } }