比较一个 32 位浮点数和一个 32 位整数而不强制转换为双精度,当任何一个值都可能太大而无法完全适合另一种类型时

Posted

技术标签:

【中文标题】比较一个 32 位浮点数和一个 32 位整数而不强制转换为双精度,当任何一个值都可能太大而无法完全适合另一种类型时【英文标题】:Compare a 32 bit float and a 32 bit integer without casting to double, when either value could be too large to fit the other type exactly 【发布时间】:2017-05-09 06:35:32 【问题描述】:

我有一个 32 位浮点数 f 数(已知为正数),我需要将其转换为 32 位无符号整数。它的大小可能太大而无法容纳。此外,下游计算需要一些空间。我可以将最大可接受值m 计算为 32 位整数。如果 f <= m 在数学上,我如何在受约束的 32 位机器(ARM M4F)上有效地确定 C++11。请注意,这两个值的类型不匹配。以下三种方法各有其问题:

static_cast<uint32_t>(f) <= m:如果f 不适合 32 位整数,我认为这会触发未定义的行为 f <= static_cast<float>(m):如果m太大而无法精确转换,则转换后的值可能大于m,这样后续比较在某些极端情况下会产生错误的结果 static_cast<double>(f) <= static_cast<double>(m):在数学上是正确的,但需要转换为 double 并使用 double,出于效率原因,我想避免这种情况

当然必须有一种方法可以将整数直接转换为具有指定舍入方向的浮点数,即保证结果的大小不超过输入。我更喜欢 C++11 标准解决方案,但在最坏的情况下,平台内在函数也可以符合条件。

【问题讨论】:

您应该只需要查看指数以查看尾数是否会滑出 32 位整数的顶部。所以移位、屏蔽并进行大于或小于比较。 @old_timer:事实上,无符号整数比较在应用于正 IEEE 754 浮点数的二进制表示时提供了正确的排序,即使考虑到尾数也是如此。因此,移位和掩码操作都不是必需的。棘手的部分是找到对应于运行时无符号整数值m 的正确指数,这是整数到浮点数转换的要点。 如果您在没有进行数值转换的情况下获得了从浮点到整数的干净二进制转换,请确保您可以进行两次或几次比较以隔离指数 Comparing uint64_t and float for numeric equivalence, How to properly compare an integer and a floating-point value?的可能重复 这能回答你的问题吗? How to properly compare an integer and a floating-point value? 【参考方案1】:

我认为你最好的选择是有点平台特定。 2³² 可以用浮点数精确表示。检查f 是否太大而无法容纳,然后转换为无符号并检查m

const float unsigned_limit = 4294967296.0f;
bool ok = false;
if (f < unsigned_limit)

    const auto uf = static_cast<unsigned int>(f);
    if (uf <= m)
    
        ok = true;
    

不喜欢双重比较,但很清楚。

如果f 通常显着小于m(或通常显着大于),则可以针对float(m)*0.99f(分别为float(m)*1.01f)进行测试,然后在异常情况下进行精确比较。如果分析表明性能提升值得额外的复杂性,那可能才值得这样做。

【讨论】:

确实,双重比较有点令人失望,但可能尽可能高效。我会等待接受更多,以防在某个地方隐藏另一个巧妙的解决方案...... 32 位浮点数通常只有 24 位精度。 2³² 可以精确表示,但 2³²-1 不能。

以上是关于比较一个 32 位浮点数和一个 32 位整数而不强制转换为双精度,当任何一个值都可能太大而无法完全适合另一种类型时的主要内容,如果未能解决你的问题,请参考以下文章

将 32 位浮点数转换为 16 位 PCM 范围

将一个 32 位浮点数转换为两个 16 位 uint 数,然后再次转换回该 32 位浮点数

c语言NULL是啥意思?

c# 默认赋值

AVX 将 64 位整数转换为 64 位浮点数

有没有办法用 xor 翻转 32 位浮点数的符号位?