【问题标题】:Casting from (long)double to size_t从 (long)double 转换为 size_t
【发布时间】:2019-05-20 04:16:00
【问题描述】:

我正在尝试尽可能高效地实施埃拉托色尼筛法。我想将我的素数数组的长度设置为 pi(n) < 1.25506n / ln n 但我不确定如何进行转换以安全地进行转换,也不知道哪种类型组合最适合。

我的列表的最大长度将受到数组的最大大小的限制。

我的猜测是,理想的组合取决于 size_t 在内部的实现方式及其上限。

我希望得到的结果接近 ceil( 1.25506n / ln n) 没有得到更小的数字。

对如何做到这一点有任何建议吗?

【问题讨论】:

  • n 的大小是多少?
  • 请将代码和结果发布为文本,而不是图像。
  • @NathanOliver 您如何建议将公式作为文本发布?我想学习如何做到这一点!
  • @SergeyA 那么第一个可以写成pi(n) < 1.25506n / ln n。第二个是ceil(1.25506n / ln n)。这并不完美,但现在看不到或屏蔽 imgur 的人至少可以理解 Q 的要求。
  • 阵列的最大大小可能受到您可以在 RAM 上花费的最大金额的限制。在 64 位平台上,size_t 将是 2^64 个元素,确实是一个巨大的数字,UINT_MAX 将是巨大的,例如 18446744073709551615。

标签: c++ casting floating-point type-conversion precision


【解决方案1】:

这是一种方法:

#include <cstddef>
#include <cfloat>
#include <cmath>

std::size_t piUpperBound(std::size_t n) {
    double x = n;
    double num = nextafter(x, DBL_MAX);

    x = log(x);
    double den = nextafter(x, -DBL_MAX);

    double result = num/den;
    result = nextafter(1.25506, DBL_MAX)*nextafter(result, DBL_MAX);
    result = nextafter(result, DBL_MAX);

    return ceil(result);
}

此代码假设log 最多有 1 个 ulp 错误。

基本思想是使用nextafter,它为我们提供了下一个可能的浮点数。每次操作后,我都会调用nextafter,以某种方式修改数字,使生成的表达式保持为上限。

如果我们假设除法和乘法正确舍入(对于 IEEE-754 是正确的),则可以创建更好的界限,并且我们可以调整舍入模式(始终向上或向下舍入)而不是 nextafter

注意事项:

  • 对原始表达式使用ceil 可能比较保守。例如,如果 pi(...)=12.2,质数最多有 12 个,而不是 13 个。
  • 这个公式很保守,你可以看到here。所以,实际上,整个浮点业务是不需要的。即使代码稍微计算错误,它仍然是一个很大的上限。

【讨论】:

  • 当你写1.25506时,你不会得到125506/100000。大多数 C++ 编译平台都会为您提供最接近有理数的double,它可以低于它。本着同样的精神,你可能想写nextafter(1.25506, DBL_MAX)
  • @PascalCuoq:幸运的是,最接近的数字在它上面:) 但你是对的,我会编辑我的答案,谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-09-30
  • 2015-08-23
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-01-20
  • 1970-01-01
  • 2019-06-30
相关资源
最近更新 更多