Roel
Roel

Reputation: 19612

Casting in a compound assignment operator?

I have code that, reduced to its essence, comes down to:

int x = 5;
x *= 0.5;

Compiling this with Visual Studio, I get a warning C4244 about possible loss of data - of course, because (simplified) the multiplication of an int by a double results in a double which is then cast to an int, losing the non-integer part.

My question is, is there C++ syntax to indicate that this the intended behavior, so as to silence the warning (I know about pragma push/pop to disable the warning, I think it's clearer to indicate that this is actually intended behavior, and that I'm not just suppressing warnings).

The long-form would be to cast explicitly after the multiplication like so:

x = (int)(x * 0.5);

but the compound-operator notation is easier to read.

So, is there a way to cast like this? I've tried putting "(int)" in every location I could think of, but none of them seem to be valid C++ :(

Upvotes: 5

Views: 1054

Answers (4)

dirkgently
dirkgently

Reputation: 111120

As per the OP's comments, you are probably best advised to use an appropriate function from <cmath> depending on the sort of rounding behavior you want (biased/un-biased).

For example floor typically does biased rounding (biased towards negative infinity, because it always chooses the lower integer number) i.e. floor( -7.5 ) would give you -8 and you will need to roll-your-own should you want a symmetric rounding i.e. want floor( -7.5 ) to be -7 (as floor( 7.5 ) gives 7).

round however can be tweaked to produce an unbiased rounding. Typically, it would produce 10 from round( 10.3 ), 11 from round( 10.6 ) (or greater). There is still the problem with rounding at the middle (tie-breaking) i.e. what round( 10.5 ) should provide (it would typically produce 11). In case, this behavior is not suitable for you, you may want to look up at some alternatives like Banker's Rounding/Alternate Rounding etc.

Upvotes: 1

Mesop
Mesop

Reputation: 5263

The result of a multiplication of an int and a float is a float.

If you want to convert the int to a float, you are likely to need to round the float to remove the decimal value. If you simply cast it, you can have rounding errors.

For example this function does rounding (there are other way of rounding numbers):

int round(float x)
{
  return static_cast<int>((x > 0.5) ? ceil(x) : floor(x));
} 

Then you just have to call it that way:

  int x = 5;
  float y = 0.33f;
  x = round(x * y);

And you have no warnings and the float is properly rounded and cast to an int.

I don't have a proper solution for the *= operator with a good rounding, so with this solution you will have to replace the *=.

Upvotes: 0

Daniel Daranas
Daniel Daranas

Reputation: 22624

The warning is in place - you should be warned of the possible loss of data.

Any ways to avoid the warning involves using a syntax which clearly expresses your intent. This can be done in the following ways:

  1. Create a function which does what you want.
  2. Do not use the unary operator. Instead, use the binary operator, and explicitly truncate the result: x = static_cast<int>(x * 0.5);

With the unary operator * you cannot suppress the warning easily because that operator was intended to be user in a clear and straighforward way, with no casting involved - and your case does not fulfill this requirement. So it is a good thing that you cannot do it.

Upvotes: 2

Cat Plus Plus
Cat Plus Plus

Reputation: 129754

Instead of multiplying by 0.5, divide by 2. With two ints integer division will be used and there will be no warning.

And if you really want to multiply by floats/doubles, don't use int to store the result.

Upvotes: 3

Related Questions