cesss
cesss

Reputation: 883

Correctly converting floating point in C++

What would be the correct/recommended way of telling the C++ compiler "only warn me of floating point conversions that I'm not aware of"?

In C, I would enable the warnings related to floating point conversions, and then I would use explicit C-style casts to silence warnings related to the conversions that are under control.

For example, computing a*a*a - b*b is quite prone to overflow in single precision floating point, so you might wish to compute it in double precision and only go single precision later:

double a = 443620.52;
double b = 874003.01;
float c = (float)(a*a*a - b*b);

The above C-style explicit cast would silence the compiler warning about the conversion from double to float.

Reading C++ documentation about casts, I get to the conclusion that the correct way of doing this in C++ would be as follows:

double a = 443620.52;
double b = 874003.01;
float c = static_cast<float>(a*a*a - b*b);

But, is this really the correct way of doing this in C++?

I understand the rationale behind the static_cast syntax being ugly on purpose, so that you avoid casts completely if possible.

Yes, I can omit the explicit cast to float. But then I need to disable compiler warnings telling me of precision loss (or otherwise I'd get a number of irrelevant warnings that would make it difficult to notice really relevant warnings). And if I disable fp-related compiler warnings, I'd lose the possibility of being warned when I'm mistakenly losing precision in other code places.

So, what's the correct approach for floating point conversions in C++?

Upvotes: 2

Views: 1325

Answers (2)

mindriot
mindriot

Reputation: 5668

As far as I am aware, there are three different ways to avoid the warning:

  1. C-style cast
  2. static_cast
  3. Constructor-style cast (e.g. float c = float(a*a*a-b*b))

In the code example below, c1, c2 and c3 avoid the warnings:

int main()
{
  double a = 443620.52;
  double b = 874003.01;

  // These three versions avoid the conversion warnings:
  float c1 = (float)(a*a*a - b*b);
  float c2 = static_cast<float>(a*a*a - b*b);
  float c3 = float(a*a*a - b*b);

  // Only these two give conversion warnings:
  float c4(a*a*a - b*b);
  float c5 = a*a*a - b*b;

  (void)c1; // Just to avoid unused-variable warnings
  (void)c2;
  (void)c3;
  (void)c4;
  (void)c5;
}

Only c4 and c5 trigger a warning. Check the live demo to see the results.

Upvotes: 0

Yes

float c = static_cast<float>(a*a*a - b*b);

is the correct way of explicitly casting to float in C++. You can also do:

float c = (float)(a*a*a - b*b);

but using a "C-style" cast like that is bad style because static_cast will hide rather fewer errors than C-style.

Alternatively, if you are doing this a lot, you can define a function:

inline float flt(double d){return static_cast<float>(d);}

and then you can write:

float c = flt(a*a*a - b*b);

which is even more compact than the original C (and will be optimized away to nothing).

Upvotes: 1

Related Questions