7

I noticed that all the mathematical constants are declared as double, which leads to conversion problems on some platforms where no double precision units exist. Is there a switch in the standard library of GCC to automatically down-cast or use separate definitions?

dgrat
  • 2,214
  • 4
  • 24
  • 46
  • Unfortunately, I think you'll need to provide your own conversions. – AndyG Feb 10 '16 at 19:08
  • 4
    Boost provides mathematical constants at various precisions, including `float`: http://www.boost.org/doc/libs/1_60_0/libs/math/doc/html/math_toolkit/tutorial/non_templ.html – Alan Stokes Feb 10 '16 at 19:14
  • `M_PI` is not part of the standard either, so any dependence on it is inherently not platform independent (although nearly everyone provides it) – AndyG Feb 10 '16 at 19:16
  • They are macros, so they are not declared at all. They're just numeric literals. What make you think that is creating a problem? Do you have a platform where overly-precise floating-point literals trigger an error? – rici Feb 10 '16 at 19:20
  • It is a bit weird that such easy things are that complicated to solve. – dgrat Feb 10 '16 at 19:26
  • @rici They're double literals; casting to float introduces a second rounding (the first is in the decimal to binary conversion to double) which may not produce the correctly rounded answer. – Alan Stokes Feb 10 '16 at 19:32
  • @AlanStokes: with the actual value of π, there is no such issue, although I understand that there exist numbers for which it could be the case. – rici Feb 10 '16 at 19:35

1 Answers1

2

C++ Numbers (since C++20)

As mentioned be Bob below, since C++20 we have std::numbers. This would result in:

#include <numbers>

    ...
    double PI = std::number::pi;
    float PIF = std::number::pi_v<float>;
    ...

This will probably be the way to move forward as time passes, although the Boost numbers have many more numbers predefined.


Boost Numbers

Alan Stroke's comment has a link to boost constants which, I think, gives what is the best answer. Use:

#include <boost/math/constants/constants.hpp>

    ...
    boost::math::float_constants::pi
    ...

Similarly, you can make use of double and long double constants:

    ...
    boost::math::double_constants::pi
    ...
    boost::math::long_double_constants::pi
    ...

Internally, Boost uses a macro which does the equivalent of:

M_PI ## F

In other words, it tells the compiler to read that floating point literal as a float instead of a double.


Macro (not recommended)

If you prefer to stick with C-like constants, you could also declare such like so:

#define M_PIF 3.141592653589793238462643383279502884e+00F

Notice the F at the end of the number.

which is pretty much what boost does internally. This may actually be the best solution in your situation since you are saying some of the compilers you use do not support double at all (and thus just using M_PI may already be an issue to start with and the boost library declares all three types: float, double, and long double).

If necessary, the precision of the value can be reduced in case the compiler complains that the literal has too many digits.


Cast

You could also simply cast the default value, however, the compiler still needs to properly support double to some extend:

    ...
    static_cast<float>(M_PI)
    ...

Such a simple cast will prevent the compiler from transforming your numbers to double and then back to float, which in most cases will make things run faster.

Note that for some numbers a cast may not result in the same value as using the F suffix. However, for M_PI, it happens to work just fine:

// create pi.cpp
#include <iostream>
int main(int argc, char * argv[])
{
    float pi1 = 3.14159265358979323846;
    float pi2 = 3.14159265358979323846f;

    std::cout << "pi1: " << pi1 << "\n";
    std::cout << "pi2: " << pi2 << "\n";
    std::cout << "pi1 == pi2? " << std::boolalpha << (pi1 == pi2) << "\n";

    return 0;
}

And the output:

$ g++ -std=c++17 pi.cpp
$ ./a.out
pi1: 3.14159
pi2: 3.14159
pi1 == pi2? true

Well, at least on an Intel processor. The difference should anyway be one bit either way, which is probably not a concern in most situations.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • 1
    Well, since C++20, we can include [``](https://en.cppreference.com/w/cpp/header/numbers). – Bob__ Apr 17 '22 at 16:12
  • @Bob__ Good news! As I was writing this post, I was wondering about these boost numbers moving to the C++ standard... I'm still on C++17, but I can't wait! – Alexis Wilke Apr 18 '22 at 01:23
  • `static_cast(M_PI)` shouldn't be used because [it might result in a different value than with the `f` suffix](https://stackoverflow.com/a/68586856/995714). Use a macro and concatenate the value like this `M_PI ## f` instead – phuclv Apr 18 '22 at 02:49