Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert an integer to float with rounding towards zero?

When an integer is converted to floating-point, and the value cannot be directly represented by the destination type, the nearest value is usually selected (required by IEEE-754).

I would like to convert an integer to floating-point with rounding towards zero in case the integer value cannot be directly represented by the floating-point type.

Example:

int i = 2147483647; float nearest = static_cast<float>(i);  // 2147483648 (likely) float towards_zero = convert(i);        // 2147483520 
like image 938
Paweł Bylica Avatar asked Jul 31 '20 13:07

Paweł Bylica


People also ask

Can integer be converted to float?

To convert an integer data type to float you can wrap the integer with float64() or float32. Explanation: Firstly we declare a variable x of type int64 with a value of 5. Then we wrap x with float64(), which converts the integer 5 to float value of 5.00. The %.

Which method is used to convert integer data type to float?

The floatValue() function can convert a given integer value into float. It belongs to the java. lang. Integer class.


Video Answer


2 Answers

Since C++11, one can use fesetround(), the floating-point environment rounding direction manager. There are four standard rounding directions and an implementation is permitted to add additional rounding directions.

#include <cfenv> // for fesetround() and FE_* macros #include <iostream> // for cout and endl #include <iomanip> // for setprecision()  #pragma STDC FENV_ACCESS ON  int main(){     int i = 2147483647;      std::cout << std::setprecision(10);      std::fesetround(FE_DOWNWARD);     std::cout << "round down         " << i << " :  " << static_cast<float>(i) << std::endl;     std::cout << "round down        " << -i << " : " << static_cast<float>(-i) << std::endl;      std::fesetround(FE_TONEAREST);     std::cout << "round to nearest   " << i << " :  " << static_cast<float>(i) << std::endl;     std::cout << "round to nearest  " << -i << " : " << static_cast<float>(-i) << std::endl;      std::fesetround(FE_TOWARDZERO);     std::cout << "round toward zero  " << i << " :  " << static_cast<float>(i) << std::endl;     std::cout << "round toward zero " << -i << " : " << static_cast<float>(-i) << std::endl;      std::fesetround(FE_UPWARD);     std::cout << "round up           " << i << " :  " << static_cast<float>(i) << std::endl;     std::cout << "round up          " << -i << " : " << static_cast<float>(-i) << std::endl;      return(0); } 

Compiled under g++ 7.5.0, the resulting executable outputs

round down         2147483647 :  2147483520 round down        -2147483647 : -2147483648 round to nearest   2147483647 :  2147483648 round to nearest  -2147483647 : -2147483648 round toward zero  2147483647 :  2147483520 round toward zero -2147483647 : -2147483520 round up           2147483647 :  2147483648 round up          -2147483647 : -2147483520 
  • Omitting the #pragma doesn't seem to change anything under g++.

  • @chux comments correctly that the standard doesn't explicitly state that fesetround() affects rounding in static_cast<float>(i). For a guarantee that the set rounding direction affects the conversion, use std::nearbyint and its -f and -l variants. See also std::rint and its many type-specific variants.

  • I probably should have looked up the format specifier to use a space for positive integers and floats, rather than stuffing it into the preceding string constants.

  • (I haven't tested the following snippet.) Your convert() function would be something like

    float convert(int i, int direction = FE_TOWARDZERO){     float retVal = 0.;     int prevdirection = std::fegetround();     std::fesetround(direction);     retVal = static_cast<float>(i);     std::fesetround(prevdirection);     return(retVal); } 
like image 161
Eric Towers Avatar answered Oct 03 '22 23:10

Eric Towers


You can use std::nextafter.

int i = 2147483647; float nearest = static_cast<float>(i);  // 2147483648 (likely) float towards_zero = std::nextafter(nearest, 0.f);        // 2147483520 

But you have to check, if static_cast<float>(i) is exact, if so, nextafter would go one step towards 0, which you probably don't want.

Your convert function might look like this:

float convert(int x){     if(std::abs(long(static_cast<float>(x))) <= std::abs(long(x)))         return static_cast<float>(x);     return std::nextafter(static_cast<float>(x), 0.f); } 

It may be that sizeof(int)==sizeof(long) or even sizeof(int)==sizeof(long long) in this case long(...) may behave undefined, when the static_cast<float>(x) exceeds the possible values. Depending on the compiler it might still work in this cases.

like image 43
jjj Avatar answered Oct 03 '22 23:10

jjj