【问题标题】:What is the best way to round large unsigned floating point numbers to integers in C++?在 C++ 中将大型无符号浮点数舍入为整数的最佳方法是什么?
【发布时间】:2020-07-13 16:57:34
【问题描述】:

我需要使用标准的“math.h”中点舍入行为将 64 位双精度值舍入到我的代码中最接近的 uint64_t。其中一些数字具有以下属性:

  • 大于 LLONG_MAX
  • 小于或等于 ULLONG_MAX

我注意到标准库舍入函数没有“无符号”版本。另外,我怀疑当中间双精度值太大而无法放入尾数时,人们用来执行此操作的某些技巧不再起作用。

进行这种转换的最佳方法是什么?

【问题讨论】:

  • 回合如何?只是截断小数位?向零舍入?朝最近的方向四舍五入?上圆,下圆?有 很多 种方法来四舍五入 - 你想怎么做?
  • @JesperJuhl 我已经澄清了这个问题。
  • 你不能创建自己的函数来做到这一点吗?

标签: c++ rounding


【解决方案1】:

我会使用 std::round 然后钳制到 uint64 范围。您还需要决定如何处理 NaN。

std::round 不会转换为整数。请注意,C 和 C++ 中内置的浮点到整数转换会截断和未定义超出范围的值。

std::round 实现标准的“学校”类型四舍五入到最接近的整数,中点大小写向外四舍五入(例如round(1.5) == 2; round(-1.5) = -2)。

当前舍入模式被忽略,这也不是 IEEE754 舍入到最接近的。后者将使用round half to even 并上下四舍五入打破平局以减少统计偏差。

对于long long,一个人会做这样的事情。

double iv = std::round(val);
if (std::isnan(iv)) {
    return 0LL;
} else if (iv > LLONG_MAX)
   return LLONG_MAX;    
} else if (iv < LLONG_MIN) {
   return LLONG_MIN;
} else {
   return (long long)iv;
}

unsigned long long 的情况是做相应的。

double iv = std::round(val);
if (std::isnan(iv)) {
    return 0ULL;
} else if (iv > ULLONG_MAX)   // ok, if you know your values are less this can be spared of course
   return ULLONG_MAX;    
} else if (iv < 0) {
   return 0ULL;
} else {
   return (unsigned long long)iv;
}

【讨论】:

  • 如果需要,这些也可以与std::numeric_limits&lt;T&gt; 统一。
【解决方案2】:

最简单的舍入方法是转换为目标类型:
假设你想将 2.3 舍入到整数根,然后你这样做:

return (int) 2.3;

所以,一般来说,你会这样做:

return (destination_type) x;

但是,这里有一个问题是你总是向下取整,正如你在这个 2.7 示例中看到的那样:

return (int) 2.7;
=> yields 2

如果要四舍五入,需要加0.5再四舍五入:

return (int) (2.7 + 0.5);
=> yields 3

因此,当您想要使用最接近的舍入来舍入到任何目标类型时,您需要:

return (destination_type) (x + 0.5);

【讨论】:

  • 这正是我怀疑当幅度足够大以至于最近的代表性浮点值之间的距离大于 1 时可能会失败的技巧类型。如果我不正确,你可以扩展你的答案为什么?
  • @Chuu:如果幅度足够大,距离大于1,那么所有double的值都已经是整数了,所以加上+.5什么都不做,它仍然是整数它已经是了,并且投射到 int 将把它带入范围,正如你所希望的那样。
猜你喜欢
  • 2010-09-12
  • 2018-07-17
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 2012-08-18
  • 2021-08-05
  • 2012-03-23
相关资源
最近更新 更多