Invalid narrowing conversion from "float" to "int" - c++

I am using the SFML graphics library for C++. My compiler is Visual Studio 2017.
When I was making the function scale I encountered a problem. I had an error saying:
Invalid narrowing conversion from "float" to "int"
So, I put roundf in front of both items in the vector, but this didn't seem to help. Changing the std::vector<int> to std::vector<float> for the return value seems to work but I would like it as an integer. Any ideas? Here's my code:
std::vector<int> scale(sf::RenderWindow *Window, std::vector<int> offset)
{ // Scale objects
float scale = 500;
return { roundf(Window->getSize().x / scale * offset[0]), roundf(Window->getSize().y / scale * offset[1]) };
}

You want lroundf() to convert to a long int rather than round() which returns a float. You may also need to cast the result of lroundf() to int (because that is usually narrower than long).
Like this:
return { int(lroundf(Window->getSize().x / scale * offset[0])), int(lroundf(Window->getSize().y / scale * offset[1])) };

Related

How to resolve the Arithmetic overflow warning messages when comparing the size using C++ [duplicate]

How do I solve these warnings?
// midiNote is a double as it is used in floating point equation
// v is int because that's informative that the function wants whole numbers
void setMidiNote(int v) { midiNote = v-48; }
Warning C26451 Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '-' to avoid overflow (io.2).
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v) { dank = v * 2 + 1; }
Warning C26451 Arithmetic overflow: Using operator '*' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '*' to avoid overflow (io.2).
Warning C26451 Arithmetic overflow: Using operator '+' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator '+' to avoid overflow (io.2).
I believe this is a bug in VS2019. It no longer is flagged in VS2022.
For instance this produces the warning
double test2(int n)
{
return 4.0 * (n - 1);
}
But this doesn't
int test2a(int n)
{
return 4 * (n - 1);
}
Yet, the risk of undefined behavior is much greater for the latter. Multiplying by 4 greatly increases the risk of UB since a far large set of n's will produce UB. How great? Well, there is only one possible value of n out of around 4 billion possible values in the first example that overflows. In the second there are around 3 billion ns that would over/underflow. Why? Because integer arithmetic would be impossible if every expression with more complexity than adding 0 or multiplying by 1 was flagged because it might overflow.
Arguably, for a warning to be set that high virtually any arithmetic operation on ints would be warned.
This answer shows a way to disable this warning in VS 2019 in the code analysis rule set editor.
Warning C26454: Arithmetic overflow: '-' operation produces a negative unsigned result at compile time (io.5)
However, Microsoft, as of VS2022, no longer produces a squiggle C26451 warning for this. Nor does it show up under -Wall. They apparently saw the light.
The warnings are telling you that there is a chance that your calculation will overflow the original (smaller) type before conversion to the result (larger) type. In the first case, if v is MIN_INT (-231), the subtraction will underflow, resulting in Undefined Behavior (likely a large positive number) that will then be stored in midiNote. To avoid the warning, convert to the larger type first:
midiNote = double(v) - 48;
Similarly for your second example.
While you can know that setMidiNote will not be called with values that will have this problem, the compiler doesn't know and issues this warning to alert you to the potential for a problem.
I resolved the problem by looking at some Microsoft Docs, but you could also change your variable into a long long type(over the top, I know). It got rid of the errors for me. Hopefully they address this soon.
I got rid of the warning by change the type of the variable to "unsigned __int64". That's what the Developer Community in Microsoft suggests!
To fix your issue, cast parameter v to a 64 bit type:
void setMidiNote(int v) { midiNote = static_cast<int64_t>(v) - 48; }
void setDarkIntensity(int v) { dank = static_cast<int64_t>(v) * 2 + 1; }
Tested on VS 2019 16.9.6
Source: https://developercommunity.visualstudio.com/t/invalid-error-c26451/279594#T-N404080
https://learn.microsoft.com/en-us/cpp/code-quality/C26451
static_cast<>() is the recommended solution.. The book I'm reading at the moment makes a big deal of this new casting convention.. Just using (v) is regarded as C style.. (According to the literature)..I wonder.. if it will work just to declare v as auto. Sounds like Vector is up to something....
void setDarkIntensity(auto v) { dank = v * 2 + 1; }
Cast to the data type you want as early as possible and then use it all the way through:
// midiNote is a double as it is used in floating point equation
// v is int because that's informative that the function wants whole numbers
void setMidiNote(int v) { midiNote = static_cast<double>(v) - 48.0; }
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v) { dank = static_cast<double>(v) * 2.0 + 1.0; }
It used to be that integer operations were much faster than floating point, but that is no longer true on modern CPUs.
Using 2.0 instead of 2 forces the casting of v to double implicitly but being explicit is always more clear.
Bonus Advice: Consider verifying any assumptions in debug builds. It will help to avoid breaking those assumptions when you change the code in the future. Something like:
// input should be 0 to 10 integer, and dank will be odd integers only
// dank is a double, it is ultimately used in a floating point equation
void setDarkIntensity(int v)
{
assert(v >= 0 && v <= 10);
dank = static_cast<double>(v) * 2.0 + 1.0;
}
Bonus Advice 2: If these functions are not part of a class, I would label them inline so the optimizer has a better chance of doing its thing with these simple functions. If they're part of the class definition, then this is already done implicitly.

Return an integer with GLSL step function

The GLSL function step returns a float (either 0.0f or 1.0f) or vector of floats. Is there a way to have it return an integer instead? I'm trying to use it to offset an index (without introducing an if statement):
const int[8] constIndicies = int[](
0,1,2,3,
1,3,0,2);
...
float ratioEdge = 17.0f;
float myFloatValue = 9.0f;
... constIndicies[4*step(ratioEdge, myFloat)] ...
But with it returning a float, that doesn't work. And casting it to an int seems wrong.
After a digging around, it would seem the closest equivalent of a step function that returns an int is in the constructors of scalars.
int myStepInt = int(myFloat > ratioEdge); // returns integer 1 or 0.
The above is an alternative to
int myStepInt = myFloat > ratioEdge ? 1 : 0;
Whether or not either of the above are more/less branchless than the built-in step function remains a mystery to me though.
The only way is either to cast step(ratioEdge, myFloat) to an int.
constIndicies[4*int(step(ratioEdge, myFloat))]
EDIT:
In response to Rabbid76 I removed the round suggestion.

Locating numerical errors due to Integer division

Is there a g++ warning or other tool that can identify integer division (truncation toward zero)? I have thousands of lines of code with calculations that inevitably will have numerical errors typically due to "float = int/int" that need to be located. I need a reasonable method for finding these.
Try -Wconversion.
From gcc's man page:
Warn for implicit conversions that may
alter a value. This includes
conversions between real and integer,
like "abs (x)" when "x" is "double";
conversions between signed and
unsigned, like "unsigned ui = -1"; and
conversions to smaller types, like
"sqrtf (M_PI)". Do not warn for
explicit casts like "abs ((int) x)"
and "ui = (unsigned) -1", or if the
value is not changed by the conversion
like in "abs (2.0)". Warnings about
conversions between signed and
unsigned integers can be disabled by
using -Wno-sign-conversion.
For C++, also warn for conversions
between "NULL" and non-pointer types;
confusing overload resolution for
user-defined conversions; and
conversions that will never use a type
conversion operator: conversions to
"void", the same type, a base class or
a reference to them. Warnings about
conversions between signed and
unsigned integers are disabled by
default in C++ unless
-Wsign-conversion is explicitly enabled.
For the following sample program (test.cpp), I get the error test.cpp: In function ‘int main()’:
test.cpp:7: warning: conversion to ‘float’ from ‘int’ may alter its value.
#include <iostream>
int main()
{
int a = 2;
int b = 3;
float f = a / b;
std::cout << f;
return 0;
}
I have a hard time calling these numerical errors. You asked for integer calculations, and got the correct numbers for integer calculations. If those numbers aren't acceptable, then ask for floating point calculations:
int x = 3;
int y = 10;
int z = x / y;
// "1." is the same thing as "1.0", you may want to read up on
// "the usual arithmetic conversions." You could add some
// parentheses here, but they aren't needed for this specific
// statement.
double zz = 1. * x / y;
This page contains info about g++ warnings. If you've already tried -Wall then the only thing left could be the warnings in this link. On second look -Wconversion might do the trick.
Note: Completely edited the response.
Remark on -Wconversion of gcc:
Changing the type of the floating point variable from float to double makes the warning vanish:
$ cat 'file.cpp'
#include <iostream>
int main()
{
int a = 2;
int b = 3;
double f = a / b;
std::cout << f;
}
Compiling with $ g++-4.7 -Wconversion 'file.cpp' returns no warnings (as $ clang++ -Weverything 'file.cpp').
Explanation:
The warning when using the type float is not returned because of the totally valid integer arithmetics, but because float cannot store all possible values of int (larger ones cannot be captured by float but by double). So there might be a change of value when assigning RHS to f in the case of float but not in the case of double. To make it clear: The warning is not returned because of int/int but because of the assignment float = int.
For this see following questions: what the difference between the float and integer data type when the size is same in java, Storing ints as floats and Rounding to use for int -> float -> int round trip conversion
However, when using float -Wconversion could still be useful to identify possible lines which are affected but is not comprehensive and is actually not intended for that. For the purpose of -Wconversion see docs/gcc/Warning-Options.html and here gcc.gnu.org/wiki/NewWconversion
Possibly of interest is also following discussion 'Implicit casting Integer calculation to float in C++'
The best way to find such error is to have really good unit tests. All alternatives are not good enough.
Have a look at this clang-tidy detection.
It catches cases like this:
d = 32 * 8 / (2 + i);
d = 8 * floatFunc(1 + 7 / 2);
d = i / (1 << 4);

Int or Unsigned Int to float without getting a warning

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.

C++ Integer overflow problem when casting from double to unsigned int

I need to convert time from one format to another in C++ and it must be cross-platform compatible. I have created a structure as my time container. The structure fields must also be unsigned int as specified by legacy code.
struct time{
unsigned int timeInteger;
unsigned int timeFraction;
} time1, time2;
Mathematically the conversion is as follows:
time2.timeInteger = time1.timeInteger + 2208988800
time2.timeFraction = (time1.timeFraction * 20e-6) * 2e32
Here is my original code in C++ however when I attempt to write to a binary file, the converted time does not match with the truth data. I think this problem is due to a type casting mistake? This code will compile in VS2008 and will execute.
void convertTime(){
time2.timeInteger = unsigned int(time1.timeInteger + 2209032000);
time2.timeFraction = unsigned int(double(time1.timeFraction) * double(20e-6)*double(pow(double(2),32)));
}
Just a guess, but are you assuming that 2e32 == 2^32? This assumption would make sense if you're trying to scale the result into a 32 bit integer. In fact 2e32 == 2 * 10^32
Slightly unrelated, I think you should rethink your type design. You are basically talking about two different types here. They happen to store the same data, albeit in different results.
To minimize errors in their usage, you should define them as two completely distinct types that have a well-defined conversion between them.
Consider for example:
struct old_time {
unsigned int timeInteger;
unsigned int timeFraction;
};
struct new_time {
public:
new_time(unsigned int ti, unsigned int tf) :
timeInteger(ti), timeFraction(tf) { }
new_time(new_time const& other) :
timeInteger(other.timeInteger),
timeFraction(other.timeFraction) { }
new_time(old_time const& other) :
timeInteger(other.timeInteger + 2209032000U),
timeFraction(other.timeFraction * conversion_factor) { }
operator old_time() const {
old_time other;
other.timeInteger = timeInteger - 2209032000U;
other.timeFraction = timeFraction / conversion_factor;
return other;
}
private:
unsigned int timeInteger;
unsigned int timeFraction;
};
(EDIT: of course this code doesn’t work for the reasons pointed out below.
Now this code can be used frictionless in a safe way:
time_old told; /* initialize … */
time_new tnew = told; // converts old to new format
time_old back = tnew; // … and back.
The problem is that (20 ^ -6) * (2 e32) is far bigger than UINT_MAX. Maybe you meant 2 to the power of 32, or UINT_MAX, rather than 2e32.
In addition, your first line with the integer, the initial value must be less than (2^32 - 2209032000), and depending on what this is measured in, it could wrap round too. In my opinion, set the first value to be a long long (normally 64bits) and change 2e32.
If you can't change the type, then it may become necessary to store the field as it's result in a double, say, and then cast to unsigned int before use.