23

In the C++ complex library, the method norm() of a complex number actually returns the square of what I have learned is usually called the "Norm".

Reference: std::norm

For example, std::norm() of (3,4) is 25.

To me, this looks very confusing: why did people implement something that does not correspond to the "usual" use of the name?

  • 11
    It is in fact not "completely wrong". It's simply using a different meaning for the concept. – Nicol Bolas Dec 29 '19 at 14:53
  • 15
    But the norm is a math definition. Square of the norm is not the norm. Why not just keeping the same words as math ? The risk that people make a mistake is just huge, and the consequence (for example for researchers) could be huge. – Mathieu Krisztian Dec 29 '19 at 14:58
  • 13
    And I gave you a link to a page that explains why this is a mathematically valid definition of "norm". – Nicol Bolas Dec 29 '19 at 15:01
  • 2
    I took the freedom to improve the wording of the question (in the original form, it would definitely attract downvotes, close votes and maybe moderator flags for deletion). Please double check if I did not change the meaning. – Doc Brown Dec 29 '19 at 15:43
  • 2
    As for the risk in research: that's why you test your code before letting it loose on your research data. – Mast Dec 30 '19 at 14:20
38

This is not a C++ library issue but a question of mathematical terminology. In mathematics, a norm can mean different things:

  • What you call norm is the Euclidian norm, which is the distance to the origin. In C++ it's abs(). This naming convention has the advantage of being consistent for complex and for real numbers (the origin in the latter case being 0.0).

  • What the C++ library calls norm() corresponds to the field norm from complex numbers to real numbers. It's also known as absolute square.

Post Scriptum: the early design of the C++ complex number library dates back to 1984, before templates did exist. In the article (link on this page), Rose & Stroustrup explain that norm() was intended for comparing magnitudes faster, but at the same time was more subject to overflows.

  • 1
    While I agree with the asker that the terminology can be confusing, Wikipedia Complex number, under History, mentions that Gauss called a²+b² the "norm" of the complex number a + bi. And when working with the subring where both the real part and the imaginary part are whole numbers, this quantity seems to be called the norm still today, see Wikipedia Gaussian integer. It is nice that a²+b² is an integer when a and b are integers (the modulus, or absolute value, is often irrational). – Jeppe Stig Nielsen Dec 30 '19 at 19:58
  • @JeppeStigNielsen Thank you for this interesting insight! Indeed norm() has the property of not loosing precision for complex<int> (as long as it does not overflow), as I explained in a comment on another answer with this example. – Christophe Dec 30 '19 at 20:53
25

Christophe's post, whilst fully correct, does not actually answer the question why the terms look like they do.

To give you definite answer for the reasons, you would have to ask someone from the C++ standard committee, but let me make an "educated guess":

  • There was already a function name std::abs in use for the euclidean norm for float and double values, long before complex made it into the standard lib. So to stay consistent, the library designers chose to overload abs for complex numbers accordingly. And providing a second alias like norm for the same function would not improve the lib, but only create some confusion.

  • But: it also makes a lot of sense to provide a function for the square of the euclidean norm. For many use cases (for example, any kind of least-squares approach) this value can be used instead of std::abs, without the performance penalty of calculating a square root. If one looks at other function names in the standard lib, it seems pretty clear the designers prefer short, concise and easy-to-remember names over artificial names like square_of_abs. So they decided to use norm, which may not express the usual meaning in analysis, but is at least not inherently wrong in number theory.

Note in different fields of mathematics (as well as in programming or other domains), terminology can depend heavily on the context, there is often more than just "one truth". A standard library or component like complex which is probably used in many different contexts will have to make terminology choices which are always fit better to some cases, and less to others.

  • Thanks for pointing this out. However performance is not the only reason to have the norm: the library also offers a function for calculating the conjugate conj(c), and c*conj(c) is norm(c). Maybe also worth to mention that for abs() there is not only a performance drawback, but also a possible loss of precision in case complex<int> (example). – Christophe Dec 29 '19 at 22:26
  • Similar reasoning would suggest that the standard library should have included trig-function variants whose argument is expressed in units of complete rotations rather than radians, since many programs multiply an angle by 2pi before calling a trig function, argument reduction after the multiplication is more expensive than subtracting floor(arg+0.5) would be, and would yield a more precise result. – supercat Dec 30 '19 at 18:00
  • 1
    @supercat: Professionally I am working with software which contains a lot 2D and 3D vector calculations as well as a lot trigonometric calculations, and my experience with that is: having a function for calculating the square of the euclidean norm directly was useful several dozen times (so I guess for real-world software dealing with complex numbers it is not too unlikely the experience will be similar). But I never felt the need for trigonometric fucntions with units of complete rotations. YMMV. – Doc Brown Dec 30 '19 at 19:30
  • @DocBrown: For graphics processing, being able to rotate cleanly by precise multiples of 90 degrees the same way as one rotates by other angles seems useful, and in for many other purposes a function to compute sin(2pi*angle) would be at least as useful as one to compute sin(angle), but faster to compute, so easy win. – supercat Dec 30 '19 at 21:17
  • 1
    @supercat is absolutely right that trig functions in units of complete rotations would be a welcome feature. "First multiply by 2pi" is inherently inadequate because 2pi is not representable; there is no approximation of 2pi (or pi) for which sin evaluates to a true zero. – R.. GitHub STOP HELPING ICE Dec 31 '19 at 2:04
6

Aside from the already given reasons, there is a strong performance reason: taking the square root is significantly slower than the other needed calculations.

For many applications, the returned value is perfectly sufficient (like comparison to other norm values), and taking the square root would be wasted effort. If you happen to need the square root, you can always do that with sqrt(norm(...)), but if it's included, there would be no way to avoid it if you'd like to save the work.

  • This is the answer I would have added if it had been absent, but it's worth pondering why the one possible workaround - an extra argument, likely optional, to say whether to take the square root - hasn't been built into this method. After all, C++ does support optional arguments. My guess is 6 or 7 design principles can be cited for why that would have been a bad idea. – J.G. Dec 29 '19 at 23:12
  • 1
    @J.G. Don’t leave us hanging. – user76284 Dec 30 '19 at 3:13
2

Since it is a template you can have complex<int> - what should the return-type be for the "usual norm"? float? double? (Using int would be natural for a template, but doesn't work well.)

Obviously it can be solved in various ways, but here the standard avoid that question by returning what would normally be the square of the norm.

  • Is complex<int> even guaranteed to compile? – curiousguy Dec 30 '19 at 19:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.