【问题标题】:Convert uint32_t to double between 0 and 1 [closed]将 uint32_t 转换为 0 和 1 之间的双倍 [关闭]
【发布时间】:2021-07-14 19:01:33
【问题描述】:

我有一个可耻的幼稚问题:uint32_t 转换为介于0 和1 之间的double 的最佳方法是什么?

我的幼稚方式是

double myconvert(uint32_t a)
{
    double n = static_cast<double>(std::numeric_limits<uint32_t>::max() - std::numeric_limits<uint32_t>::min());
    return static_cast<double>(a) / n;
}

但我想知道是否有更好的方法?

【问题讨论】:

  • 也许我已经过时了,但我发现 static_cast&lt;double&gt; 的数学代码难以阅读。我更喜欢在开始时使用1.0 隐式提升一个术语中的所有系数。
  • 嗯。天真过时......这有点推动它。 :-)
  • 我不明白目的。因此,您将 uint32 输入转换为双精度,然后将其除以 0x41EFFFFFFE00000,这是最大 uint32 转换为双精度。
  • 请注意,问题中的代码中的任何强制转换都不需要。
  • 客观而言,您认为哪个更好?

标签: c++


【解决方案1】:

可以安全地假设std::numeric_limits&lt;uint32_t&gt;::min() 将为零(unsigned 整数小于这个?),因此您可以大大简化您的公式:

double myconvert(uint32_t a)
{
    return static_cast<double>(a) / std::numeric_limits<uint32_t>::max();
}

【讨论】:

    【解决方案2】:

    std::numeric_limits&lt;uint32_t&gt;::min() 为 0。虽然删除减法并不会改进生成的程序集,因为它在编译时是已知的,但它可以简化函数。

    另一个潜在的改进是计算除数的补码并使用乘法。您可能认为优化器会自动执行该转换,但由于 IEEE-754 的严格规则,浮点通常无法实现。

    例子:

    return a * (1.0 / std::numeric_limits<uint32_t>::max());
    

    请注意,在用于计算补码的除法中,两个操作数在编译时都是已知的,因此除法是预先计算的。

    如您所见here,GCC 确实自动进行优化。如果您使用 -ffast-math 以牺牲 IEEE-754 一致性为代价,它会这样做

    我查看了Agner Fog的指令tables,随机选择了Zen3架构,双除的延迟是乘法的3倍左右。

    【讨论】:

    • 现在只需将std::numeric_limits&lt;uint32_t&gt;::max() 替换为uint32_t(-1),然后重新排列:return .0 / uint32_t(-1) * a;
    【解决方案3】:

    1.0 * a / std::numeric_limits&lt;uint32_t&gt;::max()

    是一种方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多