在没有未定义行为的情况下,哪些 float 值无法转换为 int [c++]?

2024-04-25

我刚刚从 C++14 标准中读到了这个(我的重点):

4.9 浮点积分转换 [conv.fpint]

1浮点类型的纯右值可以转换为整数类型的纯右值。转换截断;也就是说,小数部分被丢弃。如果无法截断值,则行为未定义 以目标类型表示。 [...]

这让我思考

  1. 其中,如果有的话,float值不能表示为int截断后? (这取决于实施吗?)
  2. 如果有的话,这是否意味着auto x = static_cast<int>(float)不安全吗?
  3. 正确/安全的转换方式是什么float to int那么(假设你想要截断)?

我们不久前遇到了这个问题,我手动制作了一些表,这些表在各种转换为各种大小的整数的边缘具有精确的浮点数模式。请注意,这假设 iee754 4 字节floats和8个字节doubles和 2 的补码有符号整数 (int32_t4 个字节和int64_t8 字节)。

如果您需要将位模式转换为浮点型或双精度型,您需要输入双关语(技术上为 UB)或memcpy them.

为了回答你的问题,任何太大而无法放入目标整数的东西都是 UB 转换时,并且截断为零的唯一时间是double -> int32_t。因此,使用以下值,您可以将浮点数与相关的最小值/最大值进行比较,并且仅在它们在范围内时才进行转换。

请注意,使用INT_MIN/INT_MAX(或其现代极限对应物)交叉转换然后比较并不总是有效,因为这些大小值的浮点数的准确性非常低。

Inf/NaN 在转换时也是 UB。

// float->int64 edgecases
static const uint32_t FloatbitsMaxFitInt64 = 0x5effffff; // [9223371487098961920] Largest float which still fits int an signed int64
static const uint32_t FloatbitsMinNofitInt64 = 0x5f000000; // [9223372036854775808] the bit pattern of the smallest float which is too big for a signed int64
static const uint32_t FloatbitsMinFitInt64 = 0xdf000000; // [-9223372036854775808] Smallest float which still fits int an signed int64
static const uint32_t FloatbitsMaxNotfitInt64 = 0xdf000001; // [-9223373136366403584] Largest float which to small for a signed int64

// float->int32 edgecases
static const uint32_t FloatbitsMaxFitInt32 = 0x4effffff; // [2147483520] the bit pattern of the largest float which still fits int an signed int32
static const uint32_t FloatbitsMinNofitInt32 = 0x4f000000; // [2147483648] the bit pattern of the smallest float which is too big for a signed int32
static const uint32_t FloatbitsMinFitInt32 = 0xcf000000; // [-2147483648] the bit pattern of the smallest float which still fits int an signed int32
static const uint32_t FloatbitsMaxNotfitInt32 = 0xcf000001; // [-2147483904] the bit pattern of the largest float which to small for a signed int32

// double->int64 edgecases
static const uint64_t DoubleBitsMaxFitInt64 = 0x43dfffffffffffff; // [9223372036854774784] Largest double which fits into an int64
static const uint64_t DoubleBitsMinNofitInt64 = 0x43e0000000000000; // [9223372036854775808] Smallest double which is too big for an int64
static const uint64_t DoubleBitsMinFitInt64 = 0xc3e0000000000000; // [-9223372036854775808] Smallest double which fits into an int64
static const uint64_t DoubleBitsMaxNotfitInt64 = 0xc3e0000000000001; // [-9223372036854777856] largest double which is too small to fit into an int64

// double->int32 edgecases[when truncating(round towards zero)]
static const uint64_t DoubleBitsMaxTruncFitInt32 = 0x41dfffffffffffff; // [~2147483647.9999998] Largest double that when truncated will fit into an int32
static const uint64_t DoubleBitsMinTruncNofitInt32 = 0x41e0000000000000; // [2147483648.0000000] Smallest double that when truncated wont fit into an int32
static const uint64_t DoubleBitsMinTruncFitInt32 = 0xc1e00000001fffff; // [~2147483648.9999995] Smallest double that when truncated will fit into an int32
static const uint64_t DoubleBitsMaxTruncNofitInt32 = 0xc1e0000000200000; // [2147483649.0000000] Largest double that when truncated wont fit into an int32

// double->int32 edgecases [when rounding via bankers method(round to nearest, round to even on half)]
static const uint64_t DoubleBitsMaxRoundFitInt32 = 0x41dfffffffdfffff; // [2147483647.5000000] Largest double that when rounded will fit into an int32
static const uint64_t DoubleBitsMinRoundNofitInt32 = 0x41dfffffffe00000; // [~2147483647.5000002] Smallest double that when rounded wont fit into an int32
static const uint64_t DoubleBitsMinRoundFitInt32 = 0xc1e0000000100000; // [-2147483648.5000000] Smallest double that when rounded will fit into an int32
static const uint64_t DoubleBitsMaxRoundNofitInt32 = 0xc1e0000000100001; // [~2147483648.5000005] Largest double that when rounded wont fit into an int32

所以对于你的例子你想要:

if( f >= B2F(FloatbitsMinFitInt32) && f <= B2F(FloatbitsMaxFitInt32))
    // cast is valid.

其中 B2F 类似于:

float B2F(uint32_t bits)
{
    static_assert(sizeof(float) == sizeof(uint32_t), "Weird arch");
    float f;
    memcpy(&f, &bits, sizeof(float));
    return f;
}

请注意,此转换正确拾取 nans/inf (因为与它们的比较是错误的)unless您正在使用编译器的非 iee754 模式(例如 gcc 上的 ffast-math 或 msvc 上的 /fp:fast)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在没有未定义行为的情况下,哪些 float 值无法转换为 int [c++]? 的相关文章

随机推荐

  • Sublime 代码折叠注释(如 Ace 中)

    在 Cloud9 基于 Ace 编辑器 中 我可以在注释中定义任意代码折叠区域 例如 Descriptor function Code 折叠为 Descriptor lt gt 在这里尝试看看我的意思 http ace c9 io buil
  • ModelClientValidationRule 冲突

    我已将 vs 2011 开发人员预览版与 vs 2010 并排安装 现在 当我在 vs 2010 中运行我的 asp net mvc 3 项目时 我在使用 ModelClientValidationRule 的项目中收到以下错误 Syste
  • 在线代码美化器和格式化程序[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在一个函数中返回两个变量[重复]

    这个问题在这里已经有答案了 考虑以下代码 demo http jsfiddle net m59Fg function test var h Hello var w World return h w var test test alert t
  • Mono 与 CompletableFuture

    CompletableFuture在单独的线程上执行任务 使用线程池 并提供回调函数 假设我有一个 API 调用CompletableFuture 这是 API 调用阻塞吗 线程会被阻塞直到它没有从 API 得到响应吗 我知道主线程 tom
  • 这是从片段中获取字符串资源的正确方法吗?

    在片段中读取字符串资源时 哪种方法通常更好 更安全 我在这里读到getResources getString 直接地 public class SomeFragment extends Fragment public static Some
  • C# - 从客户端检查 TCP/IP 套接字状态

    我想为我的 TCP IP 客户端类提供 CheckConnection 函数 以便我可以检查是否发生了错误 我自己的客户端断开连接 服务器断开连接 服务器卡住等 我有类似的东西 bool isConnectionActive false i
  • 无法在网络视图中滚动图像

    我为 Android 和 iOS 开发了一个 webview 应用程序 我注意到我无法滚动 Android 应用程序中的特定 html 元素 而它可以在 iOS 上运行 这是website https www blizz z de flex
  • 一个 pom 中的多个工件 ID

    有一个maven项目 jar 但现在需要将其分成两个工件 我想要两个像下面这样的 Maven 工件
  • 确保隐式定义始终具有较高/较低优先级的一般方法

    我有一个有点复杂的类型类情况 格式如下 sealed trait TypeClass S lt MyType type Out lt MyType sealed trait LowPriorityTypeClass Case OtherTy
  • Glib — 对 glib 中任何内容的未定义引用? [复制]

    这个问题在这里已经有答案了 我的 S 程序有问题 我需要用这个命令编译它 gcc I usr include glib 2 0 I usr lib x86 64 linux gnu glib 2 0 include lglib 2 0 D
  • ggplot 上的混合比例

    我想制作一个图 最好使用 ggplot2 其中 x 轴具有不同的缩放比例 更准确地说 我希望我的刻度从大约 0 001 到 0 05 是对数的 从 0 05 到 1 0 是非对数的 我当前的绘图代码是 ggplot DF aes x DF
  • 如何*真正*编写 UML 基数?

    我想一劳永逸地知道如何编写 UML 基数 因为我经常不得不争论它们 所以非常欢迎证明和来源 如果我想解释一下a Mother可以有几个Children but a Child有且仅有一个Mother 我应该写 Mother 1 Child
  • 如何在OpenCart 2.3.0.2中设置全局变量?

    当我想在模板中设置全局变量时 tpl文件 我只是使用global在 opencart 2 2 或更早版本中 例如 but 它在最新的 OpenCart 2 3 0 2 中不起作用 因为预定义的global config在控制器中相当不方便
  • 如何使用新的 Google Vision API 生成条形码并将其转换为位图?

    如何使用新的 Google Vision API 生成条形码并将其转换为位图 Barcode barcode new Barcode Barcode Email email new Barcode Email email address e
  • 字符串中最长的单词

    如何获得字符串中最长的单词 Eg string Where did the big Elephant go 回来 Elephant 循环遍历字符串中的单词 跟踪迄今为止最长的单词
  • android 中软键盘上方需要上一个、下一个按钮

    我想在键盘上方显示带有 上一个 下一个 按钮的虚拟键盘 当用户单击 上一个 按钮时 光标应移动到上一个编辑文本输入字段 单击 下一个 按钮应转到视图中的下一个编辑文本字段 如果我们在Android浏览器中打开任何要求输入的页面 我们就可以看
  • 将静态对象添加到资源字典中

    我有一个在多个视图中引用的类 但我希望它们之间只共享该类的一个实例 我已经像这样实现了我的课程 using System public class Singleton private static Singleton instance pr
  • GoDaddy Linux 上的 PHP 共享尝试通过 GMAIL SMTP 发送

    我已经尝试过 StackOverflow 和其他网站上发布的每一个脚本 代码 方法 但没有运气 我在 GoDaddy 上托管 我已经设置了一个 Google App 帐户 设置了 MX 记录所需的一切 使用 GoDaddy 工具 甚至尝试从
  • 在没有未定义行为的情况下,哪些 float 值无法转换为 int [c++]?

    我刚刚从 C 14 标准中读到了这个 我的重点 4 9 浮点积分转换 conv fpint 1浮点类型的纯右值可以转换为整数类型的纯右值 转换截断 也就是说 小数部分被丢弃 如果无法截断值 则行为未定义 以目标类型表示 这让我思考 其中 如