|
141 | 141 | P['re'] = a['re'];
|
142 | 142 | P['im'] = a['im'];
|
143 | 143 | } else if ('abs' in a && 'arg' in a) {
|
| 144 | + |
144 | 145 | P['re'] = a['abs'] * Math.cos(a['arg']);
|
145 |
| - P['im'] = a['abs'] * Math.sin(a['arg']); |
| 146 | + P['im'] = a['arg'] === 0 |
| 147 | + ? 0 |
| 148 | + : a['abs'] * Math.sin(a['arg']); |
146 | 149 | } else if ('r' in a && 'phi' in a) {
|
147 | 150 | P['re'] = a['r'] * Math.cos(a['phi']);
|
148 |
| - P['im'] = a['r'] * Math.sin(a['phi']); |
| 151 | + P['im'] = a['phi'] === 0 |
| 152 | + ? 0 |
| 153 | + : a['r'] * Math.sin(a['phi']); |
149 | 154 | } else {
|
150 | 155 | parser_exit();
|
151 | 156 | }
|
|
154 | 159 | case 'string':
|
155 | 160 |
|
156 | 161 | P['im'] = /* void */
|
157 |
| - P['re'] = 0; |
| 162 | + P['re'] = 0; |
158 | 163 |
|
159 | 164 | var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g);
|
160 | 165 | var plus = 1;
|
|
219 | 224 | parser_exit();
|
220 | 225 | }
|
221 | 226 |
|
| 227 | + |
222 | 228 | if (isNaN(P['re']) || isNaN(P['im'])) {
|
223 |
| - // If a calculation is NaN, we treat it as NaN and don't throw |
224 |
| - //parser_exit(); |
| 229 | + P['re'] = P['im'] = NaN; |
| 230 | + } |
| 231 | + |
| 232 | + if (((P['re'] === Infinity || P['re'] === -Infinity) && P['im'] !== 0) |
| 233 | + || ((P['im'] === Infinity || P['im'] === -Infinity) && P['re'] !== 0)) { |
| 234 | + P['re'] = P['im'] = Infinity; |
225 | 235 | }
|
226 | 236 | };
|
227 | 237 |
|
| 238 | + /** |
| 239 | + * Convert NaN to zero. |
| 240 | + */ |
| 241 | + function NaNtoZero(x) { |
| 242 | + if (Number.isNaN(x)) { |
| 243 | + return 0; |
| 244 | + } else { |
| 245 | + return x; |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + /** |
| 250 | + * Test if a complex object `{re, im}` is NaN |
| 251 | + */ |
| 252 | + function complexIsNaN(z) { |
| 253 | + // Todo: is having two checks redundant or sensible? |
| 254 | + return isNaN(z['re']) || isNaN(z['im']); |
| 255 | + } |
| 256 | + |
| 257 | + /** |
| 258 | + * Test if a complex object `{re, im}` is Finite |
| 259 | + */ |
| 260 | + function complexIsFinte(z) { |
| 261 | + return isFinite(z['re']) && isFinite(z['im']); |
| 262 | + } |
| 263 | + |
| 264 | + /** |
| 265 | + * Test if a complex object `{re, im}` is zero |
| 266 | + */ |
| 267 | + function complexIsZero(z) { |
| 268 | + return z['re'] === 0 && z['im'] === 0; |
| 269 | + } |
| 270 | + |
| 271 | + |
228 | 272 | /**
|
229 | 273 | * @constructor
|
230 | 274 | * @returns {Complex}
|
|
297 | 341 |
|
298 | 342 | parse(a, b); // mutates P
|
299 | 343 |
|
300 |
| - // Besides the addition/subtraction, this helps having a solution for real Infinity |
301 |
| - if (P['im'] === 0 && this['im'] === 0) { |
302 |
| - return new Complex(this['re'] * P['re'], 0); |
| 344 | + /* |
| 345 | + * A NaN value is returned if either operand |
| 346 | + * is NaN or if one operand is an infinity and |
| 347 | + * the other is zero. |
| 348 | + */ |
| 349 | + |
| 350 | + if (complexIsNaN(this) |
| 351 | + || complexIsNaN(P) |
| 352 | + || (!complexIsFinte(this) && complexIsZero(P)) |
| 353 | + || (!complexIsFinte(P) && complexIsZero(this)) |
| 354 | + ){ |
| 355 | + return Complex.COMPLEX_NAN; |
303 | 356 | }
|
304 | 357 |
|
| 358 | + // Some values will be coersed to ComplexNaN by constructor |
| 359 | + // make sure not to short cut this parsing. |
| 360 | + |
305 | 361 | return new Complex(
|
306 |
| - this['re'] * P['re'] - this['im'] * P['im'], |
307 |
| - this['re'] * P['im'] + this['im'] * P['re']); |
| 362 | + NaNtoZero(this['re'] * P['re']) - NaNtoZero(this['im'] * P['im']), |
| 363 | + NaNtoZero(this['re'] * P['im']) + NaNtoZero(this['im'] * P['re']) |
| 364 | + ); |
308 | 365 | },
|
309 | 366 |
|
310 | 367 | /**
|
|
1235 | 1292 | * @returns {boolean}
|
1236 | 1293 | */
|
1237 | 1294 | 'isNaN': function() {
|
1238 |
| - return isNaN(this['re']) || isNaN(this['im']); |
| 1295 | + return complexIsNaN(this); |
1239 | 1296 | },
|
1240 | 1297 |
|
1241 | 1298 | /**
|
|
1244 | 1301 | * @returns {boolean}
|
1245 | 1302 | */
|
1246 | 1303 | 'isFinite': function() {
|
1247 |
| - return isFinite(this['re']) && isFinite(this['im']); |
| 1304 | + return complexIsNaN(this); |
1248 | 1305 | },
|
1249 | 1306 | };
|
1250 | 1307 |
|
|
1254 | 1311 | Complex['PI'] = new Complex(Math.PI, 0);
|
1255 | 1312 | Complex['E'] = new Complex(Math.E, 0);
|
1256 | 1313 | Complex['Infinity'] = new Complex(Infinity, Infinity);
|
| 1314 | + Complex['NaN'] = new Complex(NaN, NaN); |
1257 | 1315 | Complex['EPSILON'] = 1e-16;
|
1258 | 1316 |
|
1259 | 1317 | if (typeof define === 'function' && define['amd']) {
|
|
0 commit comments