Int or Unsigned Int to float without getting a warning - c++

Sometimes I have to convert from an unsigned integer value to a float. For example, my graphics engine takes in a SetScale(float x, float y, float z) with floats and I have an object that has a certain size as an unsigned int. I want to convert the unsigned int to a float to properly scale an entity (the example is very specific but I hope you get the point).
Now, what I usually do is:
unsigned int size = 5;
float scale = float(size);
My3DObject->SetScale(scale , scale , scale);
Is this good practice at all, under certain assumptions (see Notes)? Is there a better way than to litter the code with float()?
Notes: I cannot touch the graphics API. I have to use the SetScale() function which takes in floats. Moreover, I also cannot touch the size, it has to be an unsigned int. I am sure there are plenty of other examples with the same 'problem'. The above can be applied to any conversion that needs to be done and you as a programmer have little choice in the matter.

My preference would be to use static_cast:
float scale = static_cast<float>(size);
but what you are doing is functionally equivalent and fine.

There is an implicit conversion from unsigned int to float, so the cast is strictly unnecessary.
If your compiler issues a warning, then there isn't really anything wrong with using a cast to silence the warning. Just be aware that if size is very large it may not be representable exactly by a float.

Related

Copying bytes directly from float to an unsigned int in C++ Visual Studio?

I am trying to convert a float directly into an unsigned integer WITHOUT ANY OF THE IMPLICIT CONVERSION MATH, (so not the C style or static casts) just copying the bytes directly to the other. In Windows Visual Studio 2015, the sizes for a float and a unsigned integer are the same, (4 Bytes) so I don't think there is any problem on that end . . . I came up with a solution but there has got to be a better way to do what I want.
unsigned int x = 3;
float y = 2.4565;
*reinterpret_cast<float*>(&x) = y;
This does what I want and sets X to 1075656524.
I would prefer a cross-platform solution, if there is one. I know the sizes of types can vary from platform to platform, so that might be impossible.
EDIT: To clarify, I want all of the bytes of the float copied into the unsigned int unchanged. Every single bit stored in the float should be stored in the unsigned integer. Also is there a solution that does not use memcpy? I want to avoid using deprecated functions.
I am trying to convert a float directly into an unsigned integer WITHOUT ANY OF THE IMPLICIT CONVERSION MATH, (so not the C style or static casts) just copying the bytes directly to the other
It seems like all you want to do is copy the bit pattern from one memory location to another. The standard library function memcpy can be used for that. Just realize that if sizeof(int) is different than sizeof(float), all of this is moot.
unsigned int x = 3;
float y = 2.4565;
static_assert(sizeof(int) == sizeof(float), "Can't memcpy a float to an int");
memcpy(&x, &y);
A more portable solution would be to use an array of uint8_t or int8_t.
uint8_t x[sizeof(float)];
float y = 2.4565;
memcpy(x, &y);
Now you can examine the bit pattern by examining the values of the elements of the array.

Floating point computation changes if stored in intermediate "double" variable

I am trying to write a simple log base 2 method. I understand that representing something like std::log(8.0) and std::log(2.0) on a computer is difficult. I also understand std::log(8.0) / std::log(2.0) may result in a value very slightly lower than 3.0. What I do not understand is why putting the result of a the calculation below into a double and making it an lvalue then casting it to an unsigned int would change the result compared to casting the the formula directly. The following code shows my test case which repeatedly fails on my 32 bit debian wheezy machine, but passes repeatedly on my 64 bit debian wheezy machine.
#include <cmath>
#include "assert.h"
int main () {
int n = 8;
unsigned int i =
static_cast<unsigned int>(std::log(static_cast<double>(n)) /
std::log(static_cast<double>(2)));
double d =
std::log(static_cast<double>(n)) / std::log(static_cast<double>(2));
unsigned int j = static_cast<unsigned int> (d);
assert (i == j);
}
I also know I can use bit shifting to come up with my result in a more predictable way. I am mostly curious why casting the double that results int he operation is any different than sticking that value into a double on the stack and casting the double on the stack.
In C++, floating point is allowed to do this sort of thing.
One possible explanation would be that the result of the division is calculated internally in a higher precision than double, and stored in a register with higher precision than double.
Converting this directly to unsigned int gives a different result to first converting this to double and then to unsigned int.
To see exactly what is going on , it might be helpful to look at the assembly output generated by your compiler for the 32-bit case.
Needless to say, you shouldn't write code that relies on exactness of floating point operations.

Convert range limited float to unsigned int maintaining sort order and precision?

I have a float z_f that is clamped between 0.0f and 1.0f and I want to convert this to an unsigned integer that maintains sort order.
A simple way to do this might be:
float z_f = 0.5;
unsigned int z_ui = (unsigned int) z_f*(MAX_UINT32);//Scale to full range of uint32
Will this work?
Will this cause a loss in precision?
Is there a better way to achieve same result?
The type conversion (unsigned int) z_f has higher precedence than the binary *, so you are effectively multiplying MAX_UINT32 with 0 or 1.
There are many possible values of z_f that would map to the same integer (think of the many floats that are very close to zero). This could potentially affect the sort order.
There's also the precedence bug pointed out by #Oswald.
As to a better way, I am not sure (other than keeping the numbers as floats).
I would first avoid the C style casts, for precedence reasons. The second thing is that you don't want to do this operation on a float due to precission issues, but rather in a double.
unsigned int z_ui
= static_cast<unsigned int>(satic_cast<double>(z_f)*MAX_UINT32);

Should I always use the appropriate literals for number types?

I'm often using the wrong literals in expressions, e.g. dividing a float by an int, like this:
float f = read_f();
float g = f / 2;
I believe that the compiler will in this case first convert the int literal (2) to float, and then apply the division operator. GCC and Clang have always let stuff like that pass, but Visual C++ warns about an implicit conversion. So I have to write it like this:
float f = read_f();
float g = f / 2.0f;
That got me wondering: Should I always use the appropriate literals for float, double, long etc.? I normally use int literals whenever I can get away with it, but I'm not sure if that's actually a good idea.
Is this a likely cause of subtle errors?
Is this only an issue for expressions or also for function parameters?
Are there warning levels for GCC or Clang that warn about such implicit conversions?
How about unsigned int, long int etc?
You should always explicitly indicate the type of literal that you intend to use. This will prevent problems when for example this sort of code:
float foo = 9.0f;
float bar = foo / 2;
changes to the following, truncating the result:
int foo = 9;
float bar = foo / 2;
It's a concern with function parameters as well when you have overloading and templates involved.
I know gcc has -Wconversion but I can't recall everything that it covers.
For integer values that fit in int I usually don't qualify those for long or unsigned as there is usually much less chance there for subtle bugs.
There's pretty much never an absolutely correct answer to a "should" question. Who's going to use this code, and for what? That's relevant here. But also, particularly for anything to do with floats, it's good to get into the habit of specifying exactly the operations you require. float*float is done in single-precision. anything with a double is done double-precision, 2 gets converted to a double so you're specifying different operations here.
The best answer here is What Every Computer Scientist Should Know About Floating-Point Arithmetic. I'd say don't tl;dr it, there are no simple answers with floating point.

Is const double cast at compile time?

It makes sense to define mathematical constants as double values but what happens when one requires float values instead of doubles? Does the compiler automatically interpret the doubles as floats at compile-time (so they are actually treated as they were const floats) or is this conversion made at runtime?
If by "defining", you mean using #define, here's what happens:
Say you have:
#define CONST1 1.5
#define CONST2 1.12312455431461363145134614 // Assume some number too
// precise for float
Now if you have:
float x = CONST1;
float y = CONST2;
you don't get any warning for x because the compiler automatically makes CONST1 a float. For y, you get a warning because CONST2 doesn't fit in a float, but the compiler casts it to float anyway.
If by "defining", you mean using const variables, here's what happens:
Say you have
const double CONST1=1.5;
const double CONST2=1.12312455431461363145134614; // Assume some number too
// precise for float
Now if you have:
float x = CONST1;
float y = CONST2;
there is no way for the compiler to know the values of CONST1 and CONST2(*) and therefore cannot interpret the values as float at compile them. You will be given two warnings about possible loss of data and the conversion will be done at runtime.
(*) Actually there is a way. Since the values are const, the optimizer may decide not to take a variable for them, but replace the values throughout the code. This could get complicated though, as you may pass the address to these variables around, so the optimizer may decide not to do that. That is, don't count on it.
Note that, this whole thing is true for any basic type conversions. If you have
#define CONST3 1
then you think CONST3 is int, but if you put it in a float, it would become float at compile-time, or if you put it in a char, it would become char at compiler-time.