62

What are the different techniques used to convert float type of data to integer in C++?

#include <iostream>

using namespace std;
struct database {
  int id, age;
  float salary;
};

int main() {
  struct database employee;
  employee.id = 1;
  employee.age = 23;
  employee.salary = 45678.90;
  /*
     How can i print this value as an integer
     (with out changing the salary data type in the declaration part) ?
   */
  cout << endl << employee.id << endl << employee.
  age << endl << employee.salary << endl;
  return 0;
}
moala
  • 5,094
  • 9
  • 45
  • 66

9 Answers9

100

What you are looking for is 'type casting'. typecasting (putting the type you know you want in brackets) tells the compiler you know what you are doing and are cool with it. The old way that is inherited from C is as follows.

float var_a = 9.99;
int   var_b = (int)var_a;

If you had only tried to write

int var_b = var_a;

You would have got a warning that you can't implicitly (automatically) convert a float to an int, as you lose the decimal.

This is referred to as the old way as C++ offers a superior alternative, 'static cast'; this provides a much safer way of converting from one type to another. The equivalent method would be (and the way you should do it)

float var_x = 9.99;
int   var_y = static_cast<int>(var_x);

This method may look a bit more long winded, but it provides much better handling for situations such as accidentally requesting a 'static cast' on a type that cannot be converted. For more information on the why you should be using static cast, see this question.

Community
  • 1
  • 1
thecoshman
  • 8,394
  • 8
  • 55
  • 77
  • 4
    I didn't downvote, but it may be due to you using C style casts in C++ code. It's frowned upon as it's bad style – Glen Mar 30 '10 at 10:40
  • I am? really? sorry, that was the way I though I was meant to do them – thecoshman Mar 30 '10 at 10:57
  • "Proper" way is static cast. Pragmatic way is this. I'm going for pragmatic. =) – cib May 06 '13 at 14:19
  • 26
    wow, talk about digging up the paste. I think we can all agree that accepting the technically, TECHNICALLY, C casts are still valid C++ and should be covered... boy have I learnt a lot since I first wrote this answer :P – thecoshman May 07 '13 at 08:11
  • 2
    Aside from maybe `NaN`, how could the above "old way" code result in an unconvertible type? We know in advance that `var_a` is a float. – Aaron Franke Nov 02 '18 at 08:54
  • @AaronFranke what do you mean? If you have a float, you can 'C style' cast it to an int, but it's bad practice to use that approach, see the linked question. – thecoshman Nov 02 '18 at 11:05
  • Re: _You would have got a warning_: [I don't see it](https://godbolt.org/z/Man6xMY13). Why? – pmor Nov 22 '21 at 17:56
39

Normal way is to:

float f = 3.4;
int n = static_cast<int>(f);
Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 27
    Additional information on the result would be helpful. – ManuelSchneid3r Oct 30 '16 at 07:48
  • static_cast<> is preferred to dynamic cast which would be : int n = (int)f; because static cast is resolved during compilation so the dev will catch the error (if any) during compilation. whereas dynamic cast is a runtime conversion so the developer can catch the error only if it happens during runtime. – george Sep 21 '20 at 00:02
18

Size of some float types may exceed the size of int. This example shows a safe conversion of any float type to int using the int safeFloatToInt(const FloatType &num); function:

#include <iostream>
#include <limits>
using namespace std;

template <class FloatType>
int safeFloatToInt(const FloatType &num) {
   //check if float fits into integer
   if ( numeric_limits<int>::digits < numeric_limits<FloatType>::digits) {
      // check if float is smaller than max int
      if( (num < static_cast<FloatType>( numeric_limits<int>::max())) &&
          (num > static_cast<FloatType>( numeric_limits<int>::min())) ) {
         return static_cast<int>(num); //safe to cast
      } else {
        cerr << "Unsafe conversion of value:" << num << endl;
        //NaN is not defined for int return the largest int value
        return numeric_limits<int>::max();
      }
   } else {
      //It is safe to cast
      return static_cast<int>(num);
   }
}
int main(){
   double a=2251799813685240.0;
   float b=43.0;
   double c=23333.0;
   //unsafe cast
   cout << safeFloatToInt(a) << endl;
   cout << safeFloatToInt(b) << endl;
   cout << safeFloatToInt(c) << endl;
   return 0;
}

Result:

Unsafe conversion of value:2.2518e+15
2147483647
43
23333
Martin Ba
  • 37,187
  • 33
  • 183
  • 337
zoli2k
  • 3,388
  • 4
  • 26
  • 36
  • @dgrat I just pasted the whole thing into an online compiler (C++14) and it compiled and run fine. – Arthur Tacca Oct 17 '19 at 07:22
  • 2
    Isn't there a slight `numeric_limits::max()` could get rounded to a slightly larger float value, and then if you pass exactly this larger value to `safeFloatToInt` it will pass the checks (because it uses strict inequalities) but still be undefined? – Arthur Tacca Oct 17 '19 at 07:24
  • *"This example shows a safe conversion..."* As suggested by Arthur Tacca, this is simply not true. For example, on x86-64 clang 12.0.1, calling `safeFloatToInt(b)` with `float b = std::numeric_limits::max() - x;` will cause UB for `0 < x < 64`. – 303 Sep 15 '21 at 23:26
  • After having taken a closer took, the observed UB doesn't seem to be caused by what Arthur is suggesting. While my previous comment still holds true, the check that compares the number of digits of each type is producing false results and likely has its logic reversed. – 303 Sep 15 '21 at 23:55
8

For most cases (long for floats, long long for double and long double):

long a{ std::lround(1.5f) }; //2l
long long b{ std::llround(std::floor(1.5)) }; //1ll
3

Check out the boost NumericConversion library. It will allow to explicitly control how you want to deal with issues like overflow handling and truncation.

simong
  • 238
  • 3
  • 5
1

I believe you can do this using a cast:

float f_val = 3.6f;
int i_val = (int) f_val;
Seidr
  • 4,946
  • 3
  • 27
  • 39
1

the easiest technique is to just assign float to int, for example:

int i;
float f;
f = 34.0098;
i = f;

this will truncate everything behind floating point or you can round your float number before.

sanjuro
  • 1,611
  • 1
  • 21
  • 29
1

One thing I want to add. Sometimes, there can be precision loss. You may want to add some epsilon value first before converting. Not sure why that works... but it work.

int someint = (somedouble+epsilon);
asdacap
  • 738
  • 2
  • 9
  • 15
  • 2
    It works because the cast to integer truncates instead of rounding. There might be cases where you want your float to be `5` for instance but the computer stores it as `4.999...`, so if you cast to int without the epsilon it will unintentionally become `4`. – 16807 Feb 28 '21 at 21:41
0

This is one way to convert IEEE 754 float to 32-bit integer if you can't use floating point operations. It has also a scaler functionality to include more digits to the result. Useful values for scaler are 1, 10 and 100.

#define EXPONENT_LENGTH 8
#define MANTISSA_LENGTH 23
// to convert float to int without floating point operations
int ownFloatToInt(int floatBits, int scaler) {
    int sign = (floatBits >> (EXPONENT_LENGTH + MANTISSA_LENGTH)) & 1;
    int exponent = (floatBits >> MANTISSA_LENGTH) & ((1 << EXPONENT_LENGTH) - 1);
    int mantissa = (floatBits & ((1 << MANTISSA_LENGTH) - 1)) | (1 << MANTISSA_LENGTH);
    int result = mantissa * scaler; // possible overflow
    exponent -= ((1 << (EXPONENT_LENGTH - 1)) - 1); // exponent bias
    exponent -= MANTISSA_LENGTH; // modify exponent for shifting the mantissa
    if (exponent <= -(int)sizeof(result) * 8) {
        return 0; // underflow
    }
    if (exponent > 0) {
        result <<= exponent; // possible overflow
    } else {
        result >>= -exponent;
    }
    if (sign) result = -result; // handle sign
    return result;
}