C++ does not provide a standard to access common occurring mathematical constants like pi, sqrt(2), e, and so on. It doesnt provide either a standard to access physical constants like acceleration of gravity (g), Newtonian constant of gravitation (G), Avogadro's number, Plank's constant (h), etc.
It'd be nice to have specific namespaces for this. Also it would be nice to have them templatized for different numerical precisions.
Boost offers their own implementation.
However this might be an overkill for our needs and also would add the Boost dependency.
My proposal is to write a simple solution like so:
namespace drake{ namespace math {
template<typename T>
struct constants{};
//specialization to double precision
template<>
class constants<double>
{
public:
static constexpr double pi = 3.14159265358979323846;
static constexpr double one_half = 1.0/2.0;
};
//specializations to float precision
template<>
class constants<float>
{
public:
static constexpr float pi = 3.14159265358979323846f;
static constexpr float one_half = 1.0f/2.0f;
};
typedef constants<float> constantsf;
typedef constants<double> constantsd;
}} //namespace drake{ namespace math {
which can be used as:
#include <iostream>
#include <iomanip>
#include "Math.h"
using namespace drake;
int main()
{
std::cout << std::setprecision(20);
std::cout << math::constants<float>::pi << std::endl;
std::cout << math::constants<double>::pi << std::endl;
std::cout << math::constants<float>::one_half << std::endl;
std::cout << math::constants<double>::one_half << std::endl;
return 0;
}
I am open to alternatives.
Great idea. It would be ideal if these constants can also be used in the URDF / SDF models. Though, doing that will require resolving https://github.com/RobotLocomotion/drake/issues/2030.
Your proposal seems reasonable. To conform to our style guide, the name space should be:
namespace drake {
namespace math {
@liangfok, thanks for the feedback. I guess I don't understand how these constants couldn't be used in URDF/SDF models. #2030 as far as I understand is about reading parameters. Those parameters would therefore be determined at runtime. drake::math::constants
About the namespace convention I am happy to accept whichever convention we agree upon. @jwnimmer-tri do we already have a standard for this? so for is it just about using all lower case?
@amcastro-tri, sorry I was unclear, URDF and SDF models are written in XML, not C++. I think it would make sense to allow for symbols like "PI" to be used in the URDF / SDF, which are then translated into the constants you're talking about. Maybe this is completely out of scope of this issue.
No worries at all. The main distinction here is that whatever you read from an XML (even if it could actually be a physical constant like h bar for instance) is resolved at runtime (most likely calling a factory mechanism after parsing the file) while what I am proposing it's much simpler and gets resolved at compile time. Both are super useful but for different applications.
@jwnimmer-tri, a quick look at math.h will reveal that pi is simply defined with a macro # define M_PI 3.14159265358979323846, a non type-safe solution. Do you agree?
I mean, it's a double. I'm not sure what you mean by non-typesafe?
Two strikes against M_PI:
Boost has an implementation for constants which is more likely to end up in C++, where the constants are templatized constexprs and defined to much higher precision than typically needed so that they can at least serve as full precision long double values, which M_PI can't. I don't think we should use boost constants, but I do think ours should be explicitly typed.
Oh, also per style guide I think the constants have to start with a "k", like kPi.
avoid writing 1/2*v^2 which requires and additional division (1/2) when executing.
Actually the compiler will do that at compile time. The real problem is that (1/2)=0 because both arguments are integers! Even if you write v*v/2 there won't be a divide in the generated code after optimization, and that is much cleaner than constants<double>::kHalf*v*v which would be a classic example of premature optimization!
I don't think predefined constants should be thought of as an optimization feature. Their benefit is to avoid error prone code duplication, and to provide recognizable names for values like pi.
@amcastro-tri, we don't have to use specialization to produce constants at different precisions. That involves unnessary duplication. For example, something like
template <typename T>
struct constants {
static constexpr T kPi
{3.141592653589793238462643383279502884197169399375105820974944592L};
};
would work for all precisions, and I think it would allow constants<std::complex<double>>::kPi also.
cool! I didn't know about the compiler optimization there @sherm1. An yeap, 1/2 = 0, my bad there. I was writing fast.
FWIW, one of my future PRs uses:
namespace {
const double kPi = std::acos(-1);
}
My use case doesn't require a compile-time constexpr. I wish c++11 had solved this better.
I am fine if we want to vote down M_PI, though Drake C++ already uses it extensively, as do many of Drake's externals. M_SQRT2 is also used, though less so.
If we need to make our own constants to make templates work when ScalarType is not double, then so be it, but let's do it in the simplest way that could possibly work.
Developer with desired constant can PR. Closing
Most helpful comment
Actually the compiler will do that at compile time. The real problem is that (1/2)=0 because both arguments are integers! Even if you write
v*v/2there won't be a divide in the generated code after optimization, and that is much cleaner thanconstants<double>::kHalf*v*vwhich would be a classic example of premature optimization!I don't think predefined constants should be thought of as an optimization feature. Their benefit is to avoid error prone code duplication, and to provide recognizable names for values like pi.