1 /* 2 Copyright 2008-2026 3 Matthias Ehmann, 4 Michael Gerhaeuser, 5 Carsten Miller, 6 Bianca Valentin, 7 Alfred Wassermann, 8 Peter Wilfahrt 9 10 This file is part of JSXGraph. 11 12 JSXGraph is free software dual licensed under the GNU LGPL or MIT License. 13 14 You can redistribute it and/or modify it under the terms of the 15 16 * GNU Lesser General Public License as published by 17 the Free Software Foundation, either version 3 of the License, or 18 (at your option) any later version 19 OR 20 * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT 21 22 JSXGraph is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU Lesser General Public License for more details. 26 27 You should have received a copy of the GNU Lesser General Public License and 28 the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/> 29 and <https://opensource.org/licenses/MIT/>. 30 */ 31 32 /*global JXG: true, define: true*/ 33 /*jslint nomen: true, plusplus: true*/ 34 35 /** 36 * @fileoverview A class for complex arithmetics JXG.Complex is defined in this 37 * file. Also a namespace JXG.C is included to provide instance-independent 38 * arithmetic functions. 39 */ 40 41 import JXG from "../jxg.js"; 42 import Type from "../utils/type.js"; 43 import Mat from "./math.js"; 44 45 /** 46 * Creates a new complex number. See also {@link JXG.C}. 47 * @class This class is for calculating with complex numbers, see also {@link JXG.C} for more methods. 48 * @constructor 49 * @param {Number} [x=0] Real part. 50 * @param {Number} [y=0] Imaginary part. 51 * @see JXG.C 52 */ 53 JXG.Complex = function (x, y) { 54 /** 55 * This property is only to signalize that this object is of type JXG.Complex. Only 56 * used internally to distinguish between normal JavaScript numbers and JXG.Complex numbers. 57 * @type Boolean 58 * @default true 59 * @private 60 */ 61 this.isComplex = true; 62 63 /* is the first argument a complex number? if it is, 64 * extract real and imaginary part. */ 65 if (x && x.isComplex) { 66 y = x.imaginary; 67 x = x.real; 68 } 69 70 /** 71 * Real part of the complex number. 72 * @type Number 73 * @default 0 74 */ 75 this.real = x || 0; 76 77 /** 78 * Imaginary part of the complex number. 79 * @type Number 80 * @default 0 81 */ 82 this.imaginary = y || 0; 83 84 // /** 85 // * Absolute value in the polar form of the complex number. Currently unused. 86 // * @type Number 87 // */ 88 // this.absval = 0; 89 90 // /** 91 // * Angle value in the polar form of the complex number. Currently unused. 92 // * @type Number 93 // */ 94 // this.angle = 0; 95 }; 96 97 JXG.extend( 98 JXG.Complex.prototype, 99 /** @lends JXG.Complex.prototype */ { 100 /** 101 * Converts a complex number into a string. 102 * @param {Number} [digits=null] number of digits if not null 103 * @returns {String} Formatted string containing the complex number in human readable form (algebraic form). 104 */ 105 toString: function (digits) { 106 var op = (this.imaginary < 0) ? ' - ' : ' + ', 107 im = Math.abs(this.imaginary); 108 109 if (digits !== null) { 110 return this.real.toFixed(digits) + op + im.toFixed(digits) + 'i'; 111 } 112 return this.real + op + im + 'i'; 113 }, 114 115 /** 116 * Return real and imaginary parts of a complex number as array of length 2. 117 * @returns [complex.real,complex.imaginary]; 118 */ 119 toArray: function() { 120 return [this.real, this.imaginary]; 121 }, 122 123 /** 124 * Add another complex number to this complex number. 125 * @param {JXG.Complex|Number} c A JavaScript number or a JXG.Complex object to be added to the current object. 126 * @returns {JXG.Complex} Reference to this complex number 127 */ 128 add: function (c) { 129 if (Type.isNumber(c)) { 130 this.real += c; 131 } else { 132 this.real += c.real; 133 this.imaginary += c.imaginary; 134 } 135 136 return this; 137 }, 138 139 /** 140 * Subtract another complex number from this complex number. 141 * @param {JXG.Complex|Number} c A JavaScript number or a JXG.Complex object to subtract from the current object. 142 * @returns {JXG.Complex} Reference to this complex number 143 */ 144 sub: function (c) { 145 if (Type.isNumber(c)) { 146 this.real -= c; 147 } else { 148 this.real -= c.real; 149 this.imaginary -= c.imaginary; 150 } 151 152 return this; 153 }, 154 155 /** 156 * Multiply another complex number to this complex number. 157 * @param {JXG.Complex|Number} c A JavaScript number or a JXG.Complex object to 158 * multiply with the current object. 159 * @returns {JXG.Complex} Reference to this complex number 160 */ 161 mult: function (c) { 162 var re, im, c_re, c_im; 163 164 if (Type.isNumber(c)) { 165 this.real *= c; 166 this.imaginary *= c; 167 } else { 168 re = this.real; 169 im = this.imaginary; 170 c_re = c.real; 171 c_im = c.imaginary; 172 173 // (a+ib)(x+iy) = ax-by + i(xb+ay) 174 // this.real = re * c.real - im * c.imaginary; 175 // this.imaginary = re * c.imaginary + im * c.real; 176 this.real = re * c_re - im * c_im; 177 this.imaginary = re * c_im + im * c_re; 178 } 179 180 return this; 181 }, 182 183 /** 184 * Divide this complex number by the given complex number. 185 * @param {JXG.Complex|Number} c A JavaScript number or a JXG.Complex object to 186 * divide the current object by. 187 * @returns {JXG.Complex} Reference to this complex number 188 */ 189 div: function (c) { 190 var denom, im, re, c_re, c_im, 191 eps = Mat.eps * Mat.eps; 192 193 if (Type.isNumber(c)) { 194 if (Math.abs(c) < Mat.eps) { 195 this.real = Infinity; 196 this.imaginary = Infinity; 197 198 return this; 199 } 200 201 this.real /= c; 202 this.imaginary /= c; 203 } else { 204 // (a+ib)(x+iy) = ax-by + i(xb+ay) 205 c_re = c.real; 206 c_im = c.imaginary; 207 if (Math.abs(c_re) < eps && Math.abs(c_im) < eps) { 208 this.real = Infinity; 209 this.imaginary = Infinity; 210 211 return this; 212 } 213 214 denom = c_re * c_re + c_im * c_im; 215 216 re = this.real; 217 im = this.imaginary; 218 this.real = (re * c_re + im * c_im) / denom; 219 this.imaginary = (im * c_re - re * c_im) / denom; 220 } 221 222 return this; 223 }, 224 225 /** 226 * Conjugate a complex number in place. 227 * @returns {JXG.Complex} Reference to this complex number 228 */ 229 conj: function () { 230 this.imaginary *= -1; 231 232 return this; 233 }, 234 235 /** 236 * Absolute value in the polar form, i.e. |z| of the complex number z. 237 * @returns Number 238 */ 239 abs: function() { 240 var x = this.real, 241 y = this.imaginary; 242 return Math.sqrt(x * x + y * y); 243 }, 244 245 /** 246 * Angle value in the polar form of the complex number (in radians). 247 * @returns Number 248 */ 249 angle: function() { 250 return Math.atan2(this.imaginary, this.real); 251 } 252 253 } 254 ); 255 256 /** 257 * @namespace Namespace for the complex number arithmetic functions, see also {@link JXG.Complex}. 258 * @description 259 * JXG.C is the complex number (name)space. It provides functions to calculate with 260 * complex numbers (defined in {@link JXG.Complex}). With this namespace you don't have to modify 261 * your existing complex numbers, e.g. to add two complex numbers: 262 * <pre class="code"> var z1 = new JXG.Complex(1, 0); 263 * var z2 = new JXG.Complex(0, 1); 264 * z = JXG.C.add(z1, z1);</pre> 265 * z1 and z2 here remain unmodified. With the object oriented approach above this 266 * section the code would look like: 267 * <pre class="code"> 268 * var z1 = new JXG.Complex(1, 0); 269 * var z2 = new JXG.Complex(0, 1); 270 * var z = new JXG.Complex(z1); 271 * z.add(z2);</pre> 272 * @see JXG.Complex 273 */ 274 JXG.C = {}; 275 276 /** 277 * Add two (complex) numbers z1 and z2 and return the result as a (complex) number. 278 * @param {JXG.Complex|Number} z1 Summand 279 * @param {JXG.Complex|Number} z2 Summand 280 * @returns {JXG.Complex} A complex number equal to the sum of the given parameters. 281 */ 282 JXG.C.add = function (z1, z2) { 283 var z = new JXG.Complex(z1); 284 z.add(z2); 285 return z; 286 }; 287 288 /** 289 * Subtract two (complex) numbers z1 and z2 and return the result as a (complex) number. 290 * @param {JXG.Complex|Number} z1 Minuend 291 * @param {JXG.Complex|Number} z2 Subtrahend 292 * @returns {JXG.Complex} A complex number equal to the difference of the given parameters. 293 */ 294 JXG.C.sub = function (z1, z2) { 295 var z = new JXG.Complex(z1); 296 z.sub(z2); 297 return z; 298 }; 299 300 /** 301 * Multiply two (complex) numbers z1 and z2 and return the result as a (complex) number. 302 * @param {JXG.Complex|Number} z1 Factor 303 * @param {JXG.Complex|Number} z2 Factor 304 * @returns {JXG.Complex} A complex number equal to the product of the given parameters. 305 */ 306 JXG.C.mult = function (z1, z2) { 307 var z = new JXG.Complex(z1); 308 z.mult(z2); 309 return z; 310 }; 311 312 /** 313 * Divide two (complex) numbers z1 and z2 and return the result as a (complex) number. 314 * @param {JXG.Complex|Number} z1 Dividend 315 * @param {JXG.Complex|Number} z2 Divisor 316 * @returns {JXG.Complex} A complex number equal to the quotient of the given parameters. 317 */ 318 JXG.C.div = function (z1, z2) { 319 var z = new JXG.Complex(z1); 320 z.div(z2); 321 return z; 322 }; 323 324 /** 325 * Conjugate a complex number and return the result. 326 * @param {JXG.Complex|Number} z1 Complex number 327 * @returns {JXG.Complex} A complex number equal to the conjugate of the given parameter. 328 */ 329 JXG.C.conj = function (z1) { 330 var z = new JXG.Complex(z1); 331 z.conj(); 332 return z; 333 }; 334 335 /** 336 * Absolute value of a complex number. 337 * @param {JXG.Complex|Number} z1 Complex number 338 * @returns {Number} real number equal to the absolute value of the given parameter. 339 */ 340 JXG.C.abs = function (z1) { 341 var z = new JXG.Complex(z1); 342 // z.conj(); 343 // z.mult(z1); 344 // return Math.sqrt(z.real); 345 return z.abs(); 346 }; 347 348 /** 349 * Angle of a complex number (in radians). 350 * @param {JXG.Complex|Number} z1 Complex number 351 * @returns {Number} real number equal to the angle value of the given parameter. 352 */ 353 JXG.C.angle = function (z1) { 354 var z = new JXG.Complex(z1); 355 return z.angle(); 356 }; 357 358 /** 359 * Create copy of complex number. 360 * 361 * @param {JXG.Complex|Number} z 362 * @returns {JXG.Complex} 363 */ 364 JXG.C.copy = function(z) { 365 return new JXG.Complex(z); 366 }; 367 368 JXG.Complex.C = JXG.C; 369 370 export default JXG.Complex; 371