7

I do understand why we have this in standard headers:

#define M_PI       3.14159265358979323846   // pi

However, I don't see much benefit in having these:

#define M_PI_2     1.57079632679489661923   // pi/2
#define M_PI_4     0.785398163397448309616  // pi/4
#define M_1_PI     0.318309886183790671538  // 1/pi
#define M_2_PI     0.636619772367581343076  // 2/pi

Is there any advantage in using these instead of M_PI/2, M_PI/4, 1/M_PI and 2/M_PI in actual code? (In 2020 and beyond?)

Aren't the spelled-out expressions much more readable?


I'm asking for a couple of reasons really.

Firstly, one day I accidentally mixed up M_PI_2 and M_2_PI (and maybe even 2 * M_PI). Took a while to figure out something was wrong, and after that took another while to find out what exactly was the root cause. Still think it's not super obvious what M_PI_2 and M_2_PI mean, if you are just reading code using them and don't see the definitions. And why should I memorize something like that? So, is it safe to say that using these definitions is actually an anti-pattern that degrades code readability?

Secondly, having these definitions available may still be an issue, e.g. in Windows (Visual C++). Instead of defining all these, I'd prefer to define only M_PI, and then say M_PI/2 and not M_PI_2 in the code. Is there something I'm missing?

Reunanen
  • 7,921
  • 2
  • 35
  • 57
  • 3
    You'll lose precision if you calculate them arithmetically. – Barmar Mar 05 '20 at 18:19
  • 2
    None of these constants are part of the C or C++ standards. Rather they are [part of the POSIX standard](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/math.h.html). In case of C++, starting with C++20, these constants will be standardized in [`std::numbers`](https://en.cppreference.com/w/cpp/numeric/constants) (at least pi and 1/pi). – walnut Mar 05 '20 at 18:28

1 Answers1

10

Because 2 and 4 are powers of two, M_PI_2 and M_PI_4 really are redundant and 100% equivalent to M_PI/2 and M_PI/4. However, M_1_PI is not necessarily equivalent to 1/M_PI; the latter has two roundings (approximation of pi, then inexact division) rather than just one (approximation of 1/pi).

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • `M_PI_4 != M_PI / 4`, `M_PI / 4 == 0.785398163397448309615` – Alan Birtles Mar 05 '20 at 18:24
  • 1
    `M_PI_2` and `M_PI_4` are redundant if `FLT_RADIX` is 2. But it is not required to be 2, and the prevalence of other radices may have been more of a consideration when they were created. – Eric Postpischil Mar 05 '20 at 18:26
  • 2
    @AlanBirtles: In any implementation with `FLT_RADIX == 2`, the resolved value for `M_PI_4` should equal the resolved value for `M_PI / 4`, even if the numerals used to define them do not satisfy that property. In other words, they may be defined using some strings of decimal numerals that are sufficient to specify the desired binary floating-point values, but those two strings might not be such that their decimal numbers are in the ratio 4:1. – Eric Postpischil Mar 05 '20 at 18:27
  • @AlanBirtles: What Eric said. You have to look at the actual floating point values they round to, not the decimal strings, to check equality. – R.. GitHub STOP HELPING ICE Mar 05 '20 at 18:29
  • 3
    The reasoning in this answer is also used by the proposal introducing mathematical constants to C++20 in `std::numbers` to not include equivalents of `M_PI_2` and `M_PI_4`, see [P0631](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0631r8.pdf). – walnut Mar 05 '20 at 18:37
  • Is `M_2_PI` redundant as well, being equal to `2*M_1_PI`? I think we'd be better off without `M_2_PI`, as it looks *extremely* easy to misinterpret (and misuse) as 2π. – flarn2006 Aug 17 '20 at 01:33