A question for the Go team: are complex numbers coming (some day)?

3,083 views
Skip to first unread message

Alfred Tarski

unread,
Nov 19, 2009, 5:11:59 AM11/19/09
to golang-nuts
Greetings! I am very positively impressed by Go and I am considering
it for numerical calculations. One thing which worries me however is
the lack of complex numbers as a basic type. While many numerical
computations do not require complex numbers there are also those where
they are hugely useful. The lack of complex numbers at the language
level can be a real show-stopper for serious numerical application.

At the same time adding complex numbers to the language is not a
design decision in the same sense as adding exceptions, tail recursion
or generic functions would be. Asking for those kind of features is a
bit presumptuous: the language is designed by people who have a
considerable amount of experience and good taste and it is silly for
people who have not programmed in Go for a least a few months to go on
and on requesting features which may be redundant or go against the
spirit of the language. Complex numbers are not in that category: they
can be added to the list of basic types without affecting anything
else.

I realize that the Go team has a long list of tasks to take care of
which will be of higher priority for their main target audience.
However I think a clear declaration that complex numbers will
eventually be added would be tremendously valuable for those of us who
want to keep an eye on Go for serious numerics down the road. This is
not just a humanitarian issue: if Go finds use in the numerical
computation/simulation community it can positively affect the Go
ecosystem in the future (think of all the grad students with years of
Go hacking under their belts!).

Cheers, AT.

tq

unread,
Nov 19, 2009, 7:25:48 AM11/19/09
to golang-nuts
Complex numbers can be implemented easily in a library. What is
missing though is operator overloading. You cannot add and multiply
complex numbers as if they were just ints or doubles.

Alfred Tarski

unread,
Nov 19, 2009, 9:33:57 AM11/19/09
to golang-nuts
Operator overloading is a major change to the language, which I would
not be advocating. Support for complex numbers is of course a major
undertaking, but it is not a major change to the language.

I am talking about "native" support for complex numbers: complex
number literals, complex number support in the math library etc. I
would like to be able to write things like

z:= 1.0j

and so on.

perrinmeyer

unread,
Nov 20, 2009, 12:29:19 AM11/20/09
to golang-nuts
C99 has built in complex numbers
<include complex.h>
double _Complex z1,z2,z3;
z1= 1.0 + I * 5.6 ; z2 = -3.9 * I; z3 = z1/z2;

so it would seem that at least it would be relatively to add C99
style complex number support
to the gcc-go compiler.

I too would vote for C99 complex numbers in go. same syntax would be
nice double _Complex, float _Complex, etc.

It would make go a very attractive language for numerics.

Perrin

Ben Bullock

unread,
Nov 20, 2009, 1:11:18 AM11/20/09
to golang-nuts
On Nov 20, 2:29 pm, perrinmeyer <perrinme...@gmail.com> wrote:
> C99 has built in complex numbers
> <include complex.h>
> double _Complex z1,z2,z3;
> z1= 1.0 + I * 5.6 ; z2 = -3.9 * I;  z3 = z1/z2;
>
> so it would seem that at least it would be relatively  to add C99
> style complex number support
> to the gcc-go compiler.
>
> I too would vote for C99 complex numbers in go.  same syntax would be
> nice double _Complex, float _Complex, etc.

So you'd also vote for completely scrapping the current Go
conventions, like float64, and replacing them with "double"?








hong

unread,
Nov 20, 2009, 2:39:16 AM11/20/09
to golang-nuts
> Operator overloading is a major change to the language, which I would
> not be advocating.

Actually, support operator overloading is very minor change to the
language.
We can simply treat operator as identifier and be done with it. It
requires
very little change to parser to handle it. Here is example:

+a will be parsed to a.+(), and compiler will search for func (a T) +
() T.

a + b will be parsed to a.+(b) and compiler will search for func (a T)
+(b T) T.

Just treat operator as function name. That is it.

Hong

Hong Zhang

unread,
Nov 20, 2009, 2:49:04 PM11/20/09
to Ian Lance Taylor, golang-nuts
> But that is, in itself, a major change to the language.  And you
> haven't discussed how to handle += and friends.  And you haven't
> discussed how to handle the unary operators.  And there are existing
> operators which have special semantics: ||, &&, <-; how should those
> be handled?

Go should have context insensitive parser, which should not care
about operand types.

"a += b" will be parsed into "a = a + b", then "a = a . + (b)", the
resolver will simply treat it the same way as "a = a.add(b)". The
"+" is just a regular identifier as "add". In fact, some language
simply treat "a plus b" and "a.plus(b)" the same, so there is
no increase of language complexity overall.

"+a" will be parsed into "a . + ()".

"<-" can be treated either as keyword or operator, depending on
how you like it. As operator "<-a" will be parsed into "a . <- ()".

|| and && will be considered as keyword "and" and "or". It will not
be treated as operator.

> But is not that these questions can not be answered; they can be, and
> in particular C++ does answer them (although I personally think the
> C++ answer for || and && is kind of strange in practice).  My point is
> that operator overloading really would be a major change to the
> language, not a minor one.

In term of language, you can consider it as major. But I measure it
in term of complexity. It will take couple of weeks for a decent
compiler expert to implement operator as identifier. While an
optimizer, thread scheduler, generics, can easily take many
year to achieve. In that sense, this is a minor feature.

I think this will hugely help the language in the long term by
converting language magic such as "int + int" into intrinsic
library, such as

func (a int) +(b int) int

Intel CPU supports 128-bit and 512-bit packed integers and floats.
And they can also be exposed as additional intrinsic library.

Overall, I think "operator as identifier" will be a win for Go in the
long term. The effort can be easily distributed within the community
since it is well known concept and does not require rocket
science research such as concurrent hard real time garbage
collector.

Hong

jimmy frasche

unread,
Nov 20, 2009, 2:55:34 PM11/20/09
to Hong Zhang, golang-nuts

Russ Cox

unread,
Nov 20, 2009, 3:00:04 PM11/20/09
to Hong Zhang, golang-nuts
We understand the basic idea.

A better question is what the set of operations is.
Is += its own operation separate from +?
If you expand x += y into x = x + y, then
you might lose the ability to implement some
things efficiently. For example, when using
bignum libraries you want to control when allocations
happen. So maybe a bignum library would provide
only += to avoid implicit allocation in +.
On the other hand, it's a pain to have to implement
+= on every type.

What about unary - vs binary -?
How do you distinguish those two methods?

If you allow + as a method name, can you write

type Plus interface { +(int) int }

for anything that produces an int when you add + to it?
Does ordinary int satisfy this interface? Go has
avoided defining methods on basic types precisely
to avoid these kinds of questions.

For such a simple idea, there's a lot of complexity here.

Russ

Hong Zhang

unread,
Nov 20, 2009, 3:22:06 PM11/20/09
to r...@golang.org, golang-nuts
> A better question is what the set of operations is.
> Is += its own operation separate from +?
> If you expand x += y into x = x + y, then
> you might lose the ability to implement some
> things efficiently.  For example, when using
> bignum libraries you want to control when allocations
> happen.  So maybe a bignum library would provide
> only += to avoid implicit allocation in +.
> On the other hand, it's a pain to have to implement
> += on every type.

I will disallow += altogether. Many language does not
have this operator at all. It is optimizer's job to handle
+= smartly.

> What about unary - vs binary -?
> How do you distinguish those two methods?

This does conflict with current Go language spec.
I would LOVE to see that Go support overloading
based on number of arguments, such as:

func foo();
func foo(a);
func foo(a, b);

It is very common engineering pattern a simpler
version of a function calling the complicated one
with one more argument. With Go or Haskell, I
have to write

func foo()
func foo1(a)
func foo2(a, b)

It just make the code ugly.

If we support overloading based on number of arguments,
then we will solve automatically solve the unary and binary
operator issue.

-a will call a.-()
a-b will call a.-(b)

> If you allow + as a method name, can you write
>
> type Plus interface { +(int) int }
>
> for anything that produces an int when you add + to it?

Yes and No. "+" is a legal identifier. You are most like to
write code like this to be useful:

type Plus interface {
+(a Plus) Plus;
}

> Does ordinary int satisfy this interface?  Go has
> avoided defining methods on basic types precisely
> to avoid these kinds of questions.

No. We define methods for int, but not interface. For example,
I can write valid code today as

type Int int

func (a Int) plus(b Int) Int {
return a + b;
}

func main() {
var a = Int(32);
fmt.Printf("%d", a.plus(a));
}

Simply replace "Int" with "int" above, we can define all methods
for intrinsic types. The interface can be added later if someone
wants to add generics.

> For such a simple idea, there's a lot of complexity here.

Maybe. This idea has been done so many times. We can just
borrow a good design and duplicate it in Go. There are plenty
of people capable doing it if the idea got proper support.

Hong

Russ Cox

unread,
Nov 20, 2009, 3:45:33 PM11/20/09
to Hong Zhang, golang-nuts
> Maybe. This idea has been done so many times. We can just
> borrow a good design and duplicate it in Go. There are plenty
> of people capable doing it if the idea got proper support.

There are two bad assumptions in this paragraph.

The first is that you can just drop a design from some
other language into Go and have it work. Go has its
own unique properties (methods on any type being the
one that differs most dramatically from other languages,
value receivers being another), so while it's certainly
useful to examine and learn from other languages, it's
not going to make sense to just grab semantics
from one language and transplant them.

The second is that the bottleneck is implementation effort.
I think operator overloading is an afternoon's work to put
into the tool chain. That's not the problem. The problem
is understanding all the implications and the complexity it
adds before making a conscious decision to add that
complexity to the language. We believe that the effect
on the language is a much more important consideration
than the effect on the compiler, though I understand that
many people don't see it that way.

There's a lot of complexity here that you're not
acknowledging.

Russ

Hong Zhang

unread,
Nov 20, 2009, 4:17:45 PM11/20/09
to r...@golang.org, golang-nuts
> There's a lot of complexity here that you're not acknowledging.

I think this is a judgment call. There will surely be some complexity.
In my previous message, I stated it will probably take couple of
weeks for an expert to implement it properly. Maybe I underestimate
it, but I don't think it will be a huge undertaking in the end.

Merging operator and identifier will simplify parts of language. It
will not add overall complexity to the language. I suggest we leave
the door open and have someone implement it down the road.
Personally, I think it will be a nice improvement to Go.

Hong

atomly

unread,
Nov 20, 2009, 4:25:23 PM11/20/09
to Hong Zhang, r...@golang.org, golang-nuts
On Fri, Nov 20, 2009 at 4:17 PM, Hong Zhang <ho...@google.com> wrote:
>> There's a lot of complexity here that you're not acknowledging.
>
> I think this is a judgment call. There will surely be some complexity.
> In my previous message, I stated it will probably take couple of
> weeks for an expert to implement it properly. Maybe I underestimate
> it, but I don't think it will be a huge undertaking in the end.

Not sure if you read Russ's message, but he said, "I think operator
overloading is an afternoon's work to put
into the tool chain." It's not that they think it's too difficult to
write, it's that they want to make sure they actually want to do it
and, if they do, that they do it right.

--
:: atomly ::

[ ato...@atomly.com : www.atomly.com : http://blog.atomly.com/ ...
[ atomiq records : new york city : +1.917.442.9450 ...
[ e-mail atomly-new...@atomly.com for atomly info and updates ...

Hong Zhang

unread,
Nov 20, 2009, 4:43:09 PM11/20/09
to atomly, r...@golang.org, golang-nuts
> Not sure if you read Russ's message, but he said, "I think operator
> overloading is an afternoon's work to put
> into the tool chain."  It's not that they think it's too difficult to
> write, it's that they want to make sure they actually want to do it
> and, if they do, that they do it right.

Maybe I interpret the language wrongly.

If people wants to take time to do it right. I certainly agree with it.
I don't see any need to rush for it.

If people avoid operator overloading because it is too complicated,
then I would disagree with it. It only becomes too complicated if
it has been done in the wrong way.

There will be some complexity. We all know it. I think it will be
worthwhile the effort overall.

BTW, I just want to share my personal experience here. I am
happy to agree on disagreements. Good luck.

Hong

perrinmeyer

unread,
Nov 20, 2009, 5:06:23 PM11/20/09
to golang-nuts

no, float32 _Complex would be absolutely fine!!!!

really want I meant was that it would be nice if the complex math
library could be borrowed from C99.

Perrin

Ben Tilly

unread,
Nov 20, 2009, 5:11:39 PM11/20/09
to r...@golang.org, Hong Zhang, golang-nuts
Here is my set of naive expectations based on other languages.

On Fri, Nov 20, 2009 at 12:00 PM, Russ Cox <r...@golang.org> wrote:
> We understand the basic idea.
>
> A better question is what the set of operations is.
> Is += its own operation separate from +?

I want to say yes, with a fallback that generates += out of + and = if
it is not directly implemented. That fallback could be autogenerated
if you have a good generics implementation. However "good generics
implementation" is kind of a magic wand - I have no idea how much work
it is to produce one but I suspect it isn't easy. For instance most
of the proposals that have been made so far for a generics
implementation wouldn't cover this case.

> If you expand x += y into x = x + y, then
> you might lose the ability to implement some
> things efficiently.  For example, when using
> bignum libraries you want to control when allocations
> happen.  So maybe a bignum library would provide
> only += to avoid implicit allocation in +.
> On the other hand, it's a pain to have to implement
> += on every type.

The cases people have talked about wanting overloading for are complex
numbers, matrices, and any numeric types that implemented in hardware.
In all of these cases I think it is better to define + and then to
define += in terms of that. That is right for 98% of what people want
overloading for, and if the remaining 2% doesn't get the syntactic
sugar, it is still a win.

> What about unary - vs binary -?
> How do you distinguish those two methods?

Distinguish at what level? Recognizing it when parsing code or
defining functions?

I assume you have no problem with the former. I would be inclined to
handle the latter by having a translation. (a + b) is the same as
a.Plus(b). (a * b) is the same as a.Times(b). (a - b) is the same as
a.Minus(b). In which case (-a) could be the same as a.Uminus().

> If you allow + as a method name, can you write
>
> type Plus interface { +(int) int }
>
> for anything that produces an int when you add + to it?

Using ordinary identifiers as method names means you don't have to
answer that question. :-)

> Does ordinary int satisfy this interface?  Go has
> avoided defining methods on basic types precisely
> to avoid these kinds of questions.

Ordinary int should satisfy this interface.

> For such a simple idea, there's a lot of complexity here.

Yes.

Cheers,
Ben
Message has been deleted

Weeble

unread,
Nov 20, 2009, 10:08:21 PM11/20/09
to golang-nuts
On Nov 20, 8:22 pm, Hong Zhang <h...@google.com> wrote:
> I would LOVE to see that Go support overloading
> based on number of arguments, such as:
>
> func foo();
> func foo(a);
> func foo(a, b);

It's all well and good when you're calling the function, but what
about when you're taking it as a value?

f := foo;

What's the type of "f" now? Is this illegal? If so, presumably you
need to introduce some new syntax to disambiguate such references. If
it's legal, you need to heap on more complexity to do sufficiently
clever type inference to figure it out from later usage. I suspect
you'll find things get similarly awkward when you get into reflection.
As much as I like languages with powerful type-inference, I can't help
but feel this is against the spirit in which Go has been conceived.

ancientlore

unread,
Nov 20, 2009, 10:49:47 PM11/20/09
to golang-nuts
I'd rather see default values for arguments than function overloading.
At least it's one definition of the function. Not that I'm advocating
for either.

Kevin Conner

unread,
Nov 21, 2009, 11:40:38 PM11/21/09
to golang-nuts
With respect to the original question, would you be satisfied if Go
maintained its current syntax, but had a standard package for complex
math? Off the top of my head, I imagine:

package complex

import "fmt"

func New(real, imaginary float64) Complex { return Complex{real,
imaginary} }

// Complex represents a complex number, with a real part and an
imaginary part.
type Complex struct {
real, imaginary float64;
}

// String() formats a complex number as "<real> + <imaginary>i".
func (self Complex) String() string {
return fmt.Sprintf("%v + %vi", self.real, self.imaginary)
}

// Add(Complex) returns the sum of two complex numbers.
func (self Complex) Add(other Complex) Complex {
return Complex{self.real + other.real, self.imaginary +
other.imaginary}
}

// Other methods...

But you are probably asking for new syntax and types because there are
intangibles that I don't see, since I don't have occasion to use
complex numbers. Can you explain the practical benefit? Is it
legibility? Greater accessibility for those whose focus is not
programming?

hong

unread,
Nov 22, 2009, 1:39:18 AM11/22/09
to golang-nuts
Without operator overloading, the complex package will look
differently from language primitive types. Of course, you can do it
today, but we need to be careful about it. For example, Intel CPU
supports packed number (the 128 bit register can contain several
different packed types). If people starts to write different packages
with different look-and-feel, it seems a bad idea.

Maybe we can define standard method names for all popular operators,
such as Add/Sub/Mul/Div/Mod/Quo/Rem. At least the numeric packages
will be consistent with each other. In the future, operator can be
mapped to method names (such as Python).

Hong

warmfuzzykitten

unread,
Nov 22, 2009, 1:42:48 AM11/22/09
to golang-nuts

On Nov 20, 4:47 pm, inspector_jouve <kaushan...@gmail.com> wrote:
> Somehow, the issue of supporting complex numbers morphed into
> discussion of operator overloading.
> Why not just support complex numbers in the language: complex,
> complex32 and complex64 as immutable objects, like floats, with the
> same set of built-in operators?
> It would be a big plus to the language, without sacrificing its
> philosophy.

I agree. That is much more in the spirit of Go. Except for the
immutable object part. Surely like all the other numeric types,
complex should be inline and passed by value.

Bob

Johann Höchtl

unread,
Jan 15, 2010, 5:10:06 PM1/15/10
to golang-nuts


> But you are probably asking for new syntax and types because there are

> intangibles that I don't see, since I don't have occasion to usecomplexnumbers.  Can you explain the practical benefit?  Is it


> legibility?  Greater accessibility for those whose focus is not
> programming?

Kevin, you have to understand that a lot of calculations the the realm
of signal processing (radio & cell phone communication, computer
signal processing) is dealing with complex numbers, as eg. the
calcualtion of electical impedance is. No-native support for complex
numbers is like digging a grave for an elephant with a kids shovel;
sure it works, it's just overly tedious!

Johann

Ken Thompson

unread,
Jan 15, 2010, 9:01:57 PM1/15/10
to Johann Höchtl, golang-nuts
i am interested in this and hope to do something.

Norman Yarvin

unread,
Jan 16, 2010, 12:48:47 PM1/16/10
to golang-nuts
On Fri, Jan 15, 2010 at 02:10:06PM -0800, Johann Höchtl wrote:

>> But you are probably asking for new syntax and types because there are
>> intangibles that I don't see, since I don't have occasion to use

>> complexnumbers. �Can you explain the practical benefit? Is it


>> legibility? �Greater accessibility for those whose focus is not
>> programming?
>
>Kevin, you have to understand that a lot of calculations the the realm
>of signal processing (radio & cell phone communication, computer
>signal processing) is dealing with complex numbers, as eg. the
>calcualtion of electical impedance is. No-native support for complex
>numbers is like digging a grave for an elephant with a kids shovel;
>sure it works, it's just overly tedious!

To illustrate, when working with complex numbers one wants to be able to
write:

a = b+c*d

rather than

a = add(b,mul(c,d))

One scheme that's popped into my mind would be to make the suffix "i",
appended to numeric constants, denote an imaginary number, so that:

z := 2 + 3i

would mean that the complex variable z was initialized with a real part
of 2, and an imaginary part of 3. (Despite the lack of decimal points,
this would be a floating-point complex number; hardly anyone does complex
arithmetic with integers, so it's safe to neglect that case.) But I
haven't thought about the ramifications of this as regards the rest of
the language, so am just tossing it out to be shot down.


--
Norman Yarvin http://yarchive.net

Johann Höchtl

unread,
Jan 17, 2010, 6:55:50 AM1/17/10
to golang-nuts

On Jan 16, 6:48 pm, Norman Yarvin <yar...@yarchive.net> wrote:

>
> One scheme that's popped into my mind would be to make the suffix "i",
> appended to numeric constants, denote an imaginary number, so that:
>
>         z := 2 + 3i
>
> would mean that the complex variable z was initialized with a real part
> of 2, and an imaginary part of 3.  (Despite the lack of decimal points,
> this would be a floating-point complex number; hardly anyone does complex
> arithmetic with integers, so it's safe to neglect that case.)  But I
> haven't thought about the ramifications of this as regards the rest of
> the language, so am just tossing it out to be shot down.
>

It seems like Go's current parser is very simplistic, in this context
it would first encounter an integer literal, the '+' operator and
later an integer literal. As soon it parses the 'i', the whole
expression has suddenly to be interpreted as a complex literal, with
'+' beeing kind of 'separator'. This would certainly add strange code
paths into the present parser.

Johann Höchtl

unread,
Jan 17, 2010, 7:02:10 AM1/17/10
to golang-nuts

On Jan 16, 3:01 am, Ken Thompson <k...@google.com> wrote:
> i am interested in this and hope to do something.
>

What about general literal prefixes?. A complex literal may get
anotated as CP'23+6' , with variable substitution as C'x+9' or C'x+y',
wtih '+' kind of mini-DSL. Other types might get annotations such as
S'Blah' for a string literal or I'4567' Integer literal.

Would be perfectly doable with a macro system or a rewritting parser.

Johann

Norman Yarvin

unread,
Jan 17, 2010, 1:54:19 PM1/17/10
to Johann Höchtl, golang-nuts
On Sun, Jan 17, 2010 at 03:55:50AM -0800, Johann Höchtl wrote:

>On Jan 16, 6:48 pm, Norman Yarvin <yar...@yarchive.net> wrote:
>
>> One scheme that's popped into my mind would be to make the suffix "i",
>> appended to numeric constants, denote an imaginary number, so that:
>>
>> z := 2 + 3i
>>
>> would mean that the complex variable z was initialized with a real part
>> of 2, and an imaginary part of 3. �(Despite the lack of decimal points,
>> this would be a floating-point complex number; hardly anyone does complex
>> arithmetic with integers, so it's safe to neglect that case.)
>

>It seems like Go's current parser is very simplistic, in this context
>it would first encounter an integer literal, the '+' operator and
>later an integer literal. As soon it parses the 'i', the whole
>expression has suddenly to be interpreted as a complex literal, with
>'+' beeing kind of 'separator'.

Nah, it'd be an integer literal, a + operator, and then a complex
literal; adding the integer literal and the complex literal would yield
another complex literal.

Reply all
Reply to author
Forward
0 new messages