【问题标题】:C++ floating point to integer type conversionsC++ 浮点到整数类型的转换
【发布时间】:2011-02-02 10:00:17
【问题描述】:

在 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;
}

【问题讨论】:

标签: c++ floating-point integer type-conversion typecast-operator


【解决方案1】:

您正在寻找的是“类型转换”。类型转换(将你想要的类型知道放在括号中)告诉编译器你知道你在做什么并且很酷。从C继承的旧方式如下。

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

如果你只是尝试写作

int var_b = var_a;

您会收到一条警告,提示您不能将 float 隐式(自动)转换为 int,因为您会丢失小数点。

这被称为旧方法,因为 C++ 提供了一种更好的替代方法,即“静态转换”;这提供了一种从一种类型转换为另一种类型的更安全的方法。等效的方法是(以及你应该这样做的方式)

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

此方法可能看起来有点冗长,但它可以更好地处理诸如意外请求对无法转换的类型进行“静态转换”等情况。有关为什么应该使用静态强制转换的更多信息,请参阅this question

【讨论】:

  • 我没有投反对票,但这可能是因为您在 C++ 代码中使用了 C 样式转换。它的风格很糟糕,因此不受欢迎
  • 我是?真的吗?抱歉,我本来就是这样做的
  • “正确”的方式是静态转换。务实的方式是这样的。我要务实。 =)
  • 哇,说说挖粘贴吧。我想我们都同意接受技术上的、技术上的、C 强制转换仍然是有效的 C++ 并且应该被覆盖......男孩自从我第一次写这个答案以来我学到了很多:P
  • 除了NaN,上面的“旧方式”代码怎么会导致不可转换的类型?我们提前知道var_a 是一个浮点数。
【解决方案2】:

正常的方法是:

float f = 3.4;
int n = static_cast<int>(f);

【讨论】:

  • 有关结果的其他信息会有所帮助。
  • static_cast 优于动态强制转换,即:int n = (int)f;因为静态转换在编译期间已解决,因此开发人员将在编译期间捕获错误(如果有)。而动态转换是一种运行时转换,因此开发人员只有在运行时发生错误时才能捕捉到错误。
【解决方案3】:

某些浮点类型的大小可能超过int 的大小。 此示例显示了使用 int safeFloatToInt(const FloatType &amp;num); 函数将任何浮点类型安全转换为 int

#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;
}

结果:

Unsafe conversion of value:2.2518e+15
2147483647
43
23333

【讨论】:

  • @dgrat 我刚刚将整个内容粘贴到一个在线编译器 (C++14) 中,它编译并运行良好。
  • 难道没有一点点numeric_limits&lt;int&gt;::max() 可以四舍五入到一个稍大的浮点值,然后如果你将这个更大的值准确地传递给safeFloatToInt 它将通过检查(因为它使用严格不等式)但仍未定义?
  • “这个例子展示了一个安全的转换......” 正如 Arthur Tacca 所建议的,这根本不是真的。例如,在 x86-64 clang 12.0.1 上,使用 float b = std::numeric_limits&lt;int&gt;::max() - x; 调用 safeFloatToInt(b) 将导致 0 &lt; x &lt; 64 的 UB。
  • 在近距离拍摄后,观察到的 UB 似乎不是由 Arthur 的建议引起的。虽然我之前的评论仍然成立,但比较每种类型的位数的检查会产生错误的结果,并且可能会颠倒其逻辑。
【解决方案4】:

对于大多数情况(long 表示浮点数,long long 表示 double 和 long double):

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

【讨论】:

    【解决方案5】:

    查看 boost NumericConversion 库。它将允许明确控制您希望如何处理溢出处理和截断等问题。

    【讨论】:

      【解决方案6】:

      我相信您可以使用演员表做到这一点:

      float f_val = 3.6f;
      int i_val = (int) f_val;
      

      【讨论】:

        【解决方案7】:

        最简单的技术就是将float赋给int,例如:

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

        这将截断浮点数后面的所有内容,或者您​​可以将浮点数四舍五入。

        【讨论】:

          【解决方案8】:

          我想补充一点。有时,可能会出现精度损失。您可能希望在转换之前先添加一些 epsilon 值。不知道为什么会这样......但它确实有效。

          int someint = (somedouble+epsilon);
          

          【讨论】:

          • 之所以有效,是因为转换为整数会截断而不是舍入。在某些情况下,您可能希望您的浮点数为 5,但计算机将其存储为 4.999...,因此如果您在没有 epsilon 的情况下转换为 int,它将无意中变为 4
          【解决方案9】:

          如果您不能使用浮点运算,这是将 IEEE 754 浮点数转换为 32 位整数的一种方法。它还具有缩放功能,可以在结果中包含更多数字。缩放器的有用值是 1、10 和 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;
          }
          

          【讨论】:

            猜你喜欢
            • 2011-06-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-02
            • 2013-07-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多