See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
1 <?php 2 3 /** 4 * 5 * Class for the management of Complex numbers 6 * 7 * @copyright Copyright (c) 2013-2018 Mark Baker (https://github.com/MarkBaker/PHPComplex) 8 * @license https://opensource.org/licenses/MIT MIT 9 */ 10 namespace Complex; 11 12 /** 13 * Complex Number object. 14 * 15 * @package Complex 16 * 17 * @method float abs() 18 * @method Complex acos() 19 * @method Complex acosh() 20 * @method Complex acot() 21 * @method Complex acoth() 22 * @method Complex acsc() 23 * @method Complex acsch() 24 * @method float argument() 25 * @method Complex asec() 26 * @method Complex asech() 27 * @method Complex asin() 28 * @method Complex asinh() 29 * @method Complex atan() 30 * @method Complex atanh() 31 * @method Complex conjugate() 32 * @method Complex cos() 33 * @method Complex cosh() 34 * @method Complex cot() 35 * @method Complex coth() 36 * @method Complex csc() 37 * @method Complex csch() 38 * @method Complex exp() 39 * @method Complex inverse() 40 * @method Complex ln() 41 * @method Complex log2() 42 * @method Complex log10() 43 * @method Complex negative() 44 * @method Complex pow(int|float $power) 45 * @method float rho() 46 * @method Complex sec() 47 * @method Complex sech() 48 * @method Complex sin() 49 * @method Complex sinh() 50 * @method Complex sqrt() 51 * @method Complex tan() 52 * @method Complex tanh() 53 * @method float theta() 54 * @method Complex add(...$complexValues) 55 * @method Complex subtract(...$complexValues) 56 * @method Complex multiply(...$complexValues) 57 * @method Complex divideby(...$complexValues) 58 * @method Complex divideinto(...$complexValues) 59 */ 60 class Complex 61 { 62 /** 63 * @constant Euler's Number. 64 */ 65 const EULER = 2.7182818284590452353602874713526624977572; 66 67 /** 68 * @constant Regexp to split an input string into real and imaginary components and suffix 69 */ 70 const NUMBER_SPLIT_REGEXP = 71 '` ^ 72 ( # Real part 73 [-+]?(\d+\.?\d*|\d*\.?\d+) # Real value (integer or float) 74 ([Ee][-+]?[0-2]?\d{1,3})? # Optional real exponent for scientific format 75 ) 76 ( # Imaginary part 77 [-+]?(\d+\.?\d*|\d*\.?\d+) # Imaginary value (integer or float) 78 ([Ee][-+]?[0-2]?\d{1,3})? # Optional imaginary exponent for scientific format 79 )? 80 ( # Imaginary part is optional 81 ([-+]?) # Imaginary (implicit 1 or -1) only 82 ([ij]?) # Imaginary i or j - depending on whether mathematical or engineering 83 ) 84 $`uix'; 85 86 /** 87 * @var float $realPart The value of of this complex number on the real plane. 88 */ 89 protected $realPart = 0.0; 90 91 /** 92 * @var float $imaginaryPart The value of of this complex number on the imaginary plane. 93 */ 94 protected $imaginaryPart = 0.0; 95 96 /** 97 * @var string $suffix The suffix for this complex number (i or j). 98 */ 99 protected $suffix; 100 101 102 /** 103 * Validates whether the argument is a valid complex number, converting scalar or array values if possible 104 * 105 * @param mixed $complexNumber The value to parse 106 * @return array 107 * @throws Exception If the argument isn't a Complex number or cannot be converted to one 108 */ 109 private static function parseComplex($complexNumber) 110 { 111 // Test for real number, with no imaginary part 112 if (is_numeric($complexNumber)) { 113 return [$complexNumber, 0, null]; 114 } 115 116 // Fix silly human errors 117 $complexNumber = str_replace( 118 ['+-', '-+', '++', '--'], 119 ['-', '-', '+', '+'], 120 $complexNumber 121 ); 122 123 // Basic validation of string, to parse out real and imaginary parts, and any suffix 124 $validComplex = preg_match( 125 self::NUMBER_SPLIT_REGEXP, 126 $complexNumber, 127 $complexParts 128 ); 129 130 if (!$validComplex) { 131 // Neither real nor imaginary part, so test to see if we actually have a suffix 132 $validComplex = preg_match('/^([\-\+]?)([ij])$/ui', $complexNumber, $complexParts); 133 if (!$validComplex) { 134 throw new Exception('Invalid complex number'); 135 } 136 // We have a suffix, so set the real to 0, the imaginary to either 1 or -1 (as defined by the sign) 137 $imaginary = 1; 138 if ($complexParts[1] === '-') { 139 $imaginary = 0 - $imaginary; 140 } 141 return [0, $imaginary, $complexParts[2]]; 142 } 143 144 // If we don't have an imaginary part, identify whether it should be +1 or -1... 145 if (($complexParts[4] === '') && ($complexParts[9] !== '')) { 146 if ($complexParts[7] !== $complexParts[9]) { 147 $complexParts[4] = 1; 148 if ($complexParts[8] === '-') { 149 $complexParts[4] = -1; 150 } 151 } else { 152 // ... or if we have only the real and no imaginary part 153 // (in which case our real should be the imaginary) 154 $complexParts[4] = $complexParts[1]; 155 $complexParts[1] = 0; 156 } 157 } 158 159 // Return real and imaginary parts and suffix as an array, and set a default suffix if user input lazily 160 return [ 161 $complexParts[1], 162 $complexParts[4], 163 !empty($complexParts[9]) ? $complexParts[9] : 'i' 164 ]; 165 } 166 167 168 public function __construct($realPart = 0.0, $imaginaryPart = null, $suffix = 'i') 169 { 170 if ($imaginaryPart === null) { 171 if (is_array($realPart)) { 172 // We have an array of (potentially) real and imaginary parts, and any suffix 173 list ($realPart, $imaginaryPart, $suffix) = array_values($realPart) + [0.0, 0.0, 'i']; 174 } elseif ((is_string($realPart)) || (is_numeric($realPart))) { 175 // We've been given a string to parse to extract the real and imaginary parts, and any suffix 176 list($realPart, $imaginaryPart, $suffix) = self::parseComplex($realPart); 177 } 178 } 179 if ($imaginaryPart <> 0.0 && empty($suffix)) { 180 $suffix = 'i'; 181 } 182 183 // Set parsed values in our properties 184 $this->realPart = (float) $realPart; 185 $this->imaginaryPart = (float) $imaginaryPart; 186 $this->suffix = strtolower($suffix); 187 } 188 189 /** 190 * Gets the real part of this complex number 191 * 192 * @return Float 193 */ 194 public function getReal() 195 { 196 return $this->realPart; 197 } 198 199 /** 200 * Gets the imaginary part of this complex number 201 * 202 * @return Float 203 */ 204 public function getImaginary() 205 { 206 return $this->imaginaryPart; 207 } 208 209 /** 210 * Gets the suffix of this complex number 211 * 212 * @return String 213 */ 214 public function getSuffix() 215 { 216 return $this->suffix; 217 } 218 219 /** 220 * Returns true if this is a real value, false if a complex value 221 * 222 * @return Bool 223 */ 224 public function isReal() 225 { 226 return $this->imaginaryPart == 0.0; 227 } 228 229 /** 230 * Returns true if this is a complex value, false if a real value 231 * 232 * @return Bool 233 */ 234 public function isComplex() 235 { 236 return !$this->isReal(); 237 } 238 239 public function format() 240 { 241 $str = ""; 242 if ($this->imaginaryPart != 0.0) { 243 if (\abs($this->imaginaryPart) != 1.0) { 244 $str .= $this->imaginaryPart . $this->suffix; 245 } else { 246 $str .= (($this->imaginaryPart < 0.0) ? '-' : '') . $this->suffix; 247 } 248 } 249 if ($this->realPart != 0.0) { 250 if (($str) && ($this->imaginaryPart > 0.0)) { 251 $str = "+" . $str; 252 } 253 $str = $this->realPart . $str; 254 } 255 if (!$str) { 256 $str = "0.0"; 257 } 258 259 return $str; 260 } 261 262 public function __toString() 263 { 264 return $this->format(); 265 } 266 267 /** 268 * Validates whether the argument is a valid complex number, converting scalar or array values if possible 269 * 270 * @param mixed $complex The value to validate 271 * @return Complex 272 * @throws Exception If the argument isn't a Complex number or cannot be converted to one 273 */ 274 public static function validateComplexArgument($complex) 275 { 276 if (is_scalar($complex) || is_array($complex)) { 277 $complex = new Complex($complex); 278 } elseif (!is_object($complex) || !($complex instanceof Complex)) { 279 throw new Exception('Value is not a valid complex number'); 280 } 281 282 return $complex; 283 } 284 285 /** 286 * Returns the reverse of this complex number 287 * 288 * @return Complex 289 */ 290 public function reverse() 291 { 292 return new Complex( 293 $this->imaginaryPart, 294 $this->realPart, 295 ($this->realPart == 0.0) ? null : $this->suffix 296 ); 297 } 298 299 public function invertImaginary() 300 { 301 return new Complex( 302 $this->realPart, 303 $this->imaginaryPart * -1, 304 ($this->imaginaryPart == 0.0) ? null : $this->suffix 305 ); 306 } 307 308 public function invertReal() 309 { 310 return new Complex( 311 $this->realPart * -1, 312 $this->imaginaryPart, 313 ($this->imaginaryPart == 0.0) ? null : $this->suffix 314 ); 315 } 316 317 protected static $functions = [ 318 'abs', 319 'acos', 320 'acosh', 321 'acot', 322 'acoth', 323 'acsc', 324 'acsch', 325 'argument', 326 'asec', 327 'asech', 328 'asin', 329 'asinh', 330 'atan', 331 'atanh', 332 'conjugate', 333 'cos', 334 'cosh', 335 'cot', 336 'coth', 337 'csc', 338 'csch', 339 'exp', 340 'inverse', 341 'ln', 342 'log2', 343 'log10', 344 'negative', 345 'pow', 346 'rho', 347 'sec', 348 'sech', 349 'sin', 350 'sinh', 351 'sqrt', 352 'tan', 353 'tanh', 354 'theta', 355 ]; 356 357 protected static $operations = [ 358 'add', 359 'subtract', 360 'multiply', 361 'divideby', 362 'divideinto', 363 ]; 364 365 /** 366 * Returns the result of the function call or operation 367 * 368 * @return Complex|float 369 * @throws Exception|\InvalidArgumentException 370 */ 371 public function __call($functionName, $arguments) 372 { 373 $functionName = strtolower(str_replace('_', '', $functionName)); 374 375 // Test for function calls 376 if (in_array($functionName, self::$functions)) { 377 $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}"; 378 return $functionName($this, ...$arguments); 379 } 380 // Test for operation calls 381 if (in_array($functionName, self::$operations)) { 382 $functionName = "\\" . __NAMESPACE__ . "\\{$functionName}"; 383 return $functionName($this, ...$arguments); 384 } 385 throw new Exception('Function or Operation does not exist'); 386 } 387 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body