imaginary number : i

JavaScript is now so mature, why not introduce imaginary 'I' to expand the scientific computing power of JS.

let a = 1 + i;
let b = 2 + 2i;
let c = a + b; // 3 + 3i
let d = a * b; //  4i

let aa = 1n + 1ni;
let bb = 2n + 2ni;
let cc = 1 + 1ni;
let dd = 2 + 2ni;
let ee = aa + bb; // 3n + 3ni
let ff = cc + dd; // 3 + 3ni;

Math.sqrt(-1) // i
5 Likes

i is already a very commonly used variable name; what alternative wouldn’t be confusing for those used to the math i?

That could easily be addressed by requiring 1ni/1.0i instead.

I'm torn on whether this should be a thing in the language or not, though - it's a rather complex feature (no pun intended) for something that wouldn't even be used pervasively, though there is significant language precedent, including a lot for it being implemented as a native primitive. (Oddly, Java does not have such a type in its standard library, despite all the other batteries it has.)

I wonder if it'd be best to do it this way:

  • Native i suffix to numbers (and ni for bigints, etc.) for complex numbers - it'd mix very well with the proposed decimal type (statistical and economic analysis calculations do occasionally see that appear - you'd see this on the server side more often than client-side, though) as well as scientific computing.
    • Note that number coercion should always throw for complex numbers - there's no single "maximum" for complex numbers, but multiple types (largest real, largest imaginary, largest absolute value, etc.), for instance.
  • A complex standard module (similar to temporal) to offer all the stuff the Math global offers, but generalized to complex numbers and with sqrt and friends (that return NaN due to being imaginary rather than indeterminate) returning imaginary numbers instead of NaNs as applicable. This separation of course also has precedent.

Do you use 'j' like Python?I think that would be more confusing

I think it's an interesting proposal

let a = i;
// That's a good thing to do
a++ // 2i ;
++a // 3i

Why would ++a do something different than a += 1?

let b = 2 + 3i;
++b; // ???

Haha , the above example has no real part.
The complex number should probably be taken as a whole
I just thought it would be fun, and of course we should keep it together.

let b = 2 + 3i;
// That's kind of weird, too  
++b; //  3 + 4i or 3 + 3i
```**粗体文本**

Complex number can be represented in polar form as well, i.e. radius < theta

This proposal is very good. Closer to our math

So this proposal would require adding one more data type in the form of complex numbers.
i without any further qualifiers couldn't be used as it would be a breaking change. But you could use something similar to BigInt and use the i as a postfix, so have 1i instead.

Let's see what this datatype would need to look like:

It would have 2 internal components, the real and the imaginary part both of which would be floating point numbers.

Arithmetic operations between a (real) number and a complex number should always yield a complex number, this would probably be done by implicitly converting real numbers into complex numbers with 0i as their imaginary component.
I think artihmetic operations between complex numbers should be self explaintory addition and subtraction being component wise and multiplication and division being a bit more complicated. (interesting case would probably be the modulo operator though)

Truthiness would probably be given if any of the components isn't 0.

I don't think Math.sqrt should yield a complex number for real number values, this could cause issues. If you want to get complex numbers you could instead force the conversion to a complex number by adding +0i to the input.

Some interesting things to consider would be interaction with the trigonometric functions.

a++ should only increase the real value, as it does already. it should always be equivalent to a = a + 1. I don't see a reason for having a separate imaginary number type either.

As for naming the type I'd probably call it complex so typeof 1i should yield complex. ""+(0+0i) should yield 0+0i with neither the real component nor the imaginary component being omitted regardless of the value.
Some other thing that should probably be considered is how to get the separate componets for the number to handle them individually where required.

From what I've seen, a lot of this type of math normally gets left to third-party libraries to handle (as it's not a feature most JavaScript developers or library authors need). With the extended numerical literal proposal, it would be possible for a third-party math library to literally provide an "i" complex literal, and with the operator overloading proposal, they could make math work properly on these literals.

For example:

import { Complex } from 'some-awesome-full-featured-math-library'

with suffix i = Complex.literal // Allows complex number literals
with operators from Complex // Allows operators to be overloaded on complex numbers

console.log((2i+3) + (3i+4)) // 5i+7
1 Like

I don't like the way a magic statement is used to change the way the following code is parsed without it being limited to a certain code block.
Maybe postfixing a number with a symbol in general would be better, so if we were to talk about transpilers it would essentially turn:

console.log((2i+3) + (3i+4))

into

console.log(i(2)+3 + i(3)+4)

of course you'd still need the ability to overload operators to be able to use it nicely.

2i is already a syntax error, so the "magic statement" (with suffix i = Complex.literal) just turns what would have been a syntax error into working code. And, it is actually limited to just the block in which that magic statement is used, it's not a global change.

I see, as I said though you could just define postfixing a number literall with a symbol name to be a function call with the number as it's parameter, although that could maybe cause some confusion, idk It just seems very unlinke ES.

That would make constructing imaginary numbers with i extremely error-prone.

Yes, considering that i is often used as a loop variable, it would mean that you would be unable to use the "i" postfix any time you're in a C-style for loop (for (let i = 0; i < whatever; ++i)).

But, you could certainly start a discussion on the extended numeric literal proposal, mentioning that you think it would be simpler to let any function in the local scope be used as a postfix, similar to how string templates work.

There's definitely a place for this idea; Complex numbers fill the gap in our mathematical notion of numbers. Any future forward language needs this system of numbers.
As said by @Ijharb

we can either go with:
10im (opted by Julia)
or 10j engineer's notation.
(j is also troublesome😅)

Maybe we can use the extension to decorators and use:
10@i doesn't look very elegant but still functional.
This should return a Complex object, with all mathematical operations defined. Again i here could be anything else☺

I like this idea.

BUT, I strongly advise against simply i as the default, purely because it can be a variable name, and it is immensely common in for(let i ...) loops. I think 1i is fine though.

Also, I think it is a bad idea to mix floats with BigInts. I see you use it in the expression 1 + 1ni.

Just a thought, how would 0i work?

In math 0i = 0, but how would it work in JS?

0 == 0i // true, probably
0 === 0i // true or false?

Also, would inequalities be unallowed, just like math?

Not TC39, but I strongly doubt anyone here would be willing to diverge from math in that case.