【问题标题】:Round arbitrary-length floats to n digits将任意长度的浮点数舍入到 n 位
【发布时间】:2017-02-20 17:48:13
【问题描述】:

我已经阅读了与“四舍五入到 n 位”相关的大部分 SO 问题。我相信这个问题是分开的,因为它与任意长度浮点数的舍入更相关。

0.56714329040978387299996866221035554975381578718651250813513107922304579308668456669321944696175229455773495728285284421635951688

上面的数字是我正在使用的数字类型的一个示例。

我了解如何在 C++ 中对数字进行四舍五入,这相当简单。但是,我不明白如何将任意长度的数字四舍五入到 n 位。

例如,我可能有一个 192 位长的数字需要四舍五入到 84 位,或者一个 1831 位的数字需要四舍五入到 293 位。如何使用一个函数(或类似函数)来做到这一点?

为了清楚起见,使用伪代码,但我实际上使用 Boost 多精度 cpp_dec_float 进行任意精度浮点数而不是标准浮点数:

float round(float num, int digits){
    //returns num rounded to n digits
}

我遇到的另一个问题是在尝试将非常长的浮点数舍入为少量数字时。

例如,如果我有一个 1000 位长的数字,并且我想将它四舍五入到 n 位,我必须执行类似floor(num * 10^1000)/10^1000) 的操作。这不起作用,因为 10^1000 非常大。解决此问题的方法是使用较小的指数多次进行乘法和除法。

【问题讨论】:

  • 只要确保我能正确回答问题。两者中的哪一个:舍入到数字计数(相对精度)或“舍入到单位”(绝对精度)。例如。 round(0.253e+5,2digits)==0.25e+5(相对)与round(0.253e+5, 100units)==0.253e+5)?
  • @AdrianColomitchi 我说的更多是 0.0236 舍入到 3 位返回 0.024 如果这就是你在说的话?
  • “我实际上是在使用 Boost 多精度来实现任意精度的浮点数”——你必须比这更具体。
  • 你有它:round(x, precision_unit)=trunc(x/precision_unit+0.5)*precision_unit; - 我的答案中的代码
  • 您的0.5671432... 不是任意长度的浮点数。它是值的文本表示,编译器会将其转换为浮点值。我所知道的每个系统上的浮点值不支持 192 位精度,更不用说 1000 位(通常,double 可以容纳大约 16 位)。一旦超出了浮点值的精度,您显示的任何数字本质上都是无稽之谈。因此,无论您想对所有这些数字做什么,都必须对文本表示进行处理,而不是浮点类型。

标签: c++ rounding arbitrary-precision


【解决方案1】:

[已编辑 - 更好的解决方案]

四舍五入可以基于:

round(x, precision_unit)=trunc(x/precision_unit+0.5)*precision_unit;

类似:

  using namespace boost::multiprecision;

  const uint lower_prec_digits=28;

  typedef number<cpp_dec_float<100>> higher_prec;
  typedef number<cpp_dec_float<lower_prec_digits>> lower_prec;

  const higher_prec eps_div=
      std::numeric_limits<
          number<cpp_dec_float<lower_prec_digits+1>>
      >::epsilon()
  ;

  higher_prec pi(
    "3.1415926535"
      "8979323846"
      "2643383279"
      "5028841971"
      "6939937510"
      "5820974944"
      "5923078164"
      "0628620899"
      "8628034825"
      "3421170679"
  );

  lower_prec round_pie=lower_prec(trunc(pi/eps_div+0.5)*eps_div);

  std::cout.precision(100);
  std::cout << round_pie << std::endl << pi << std::endl;

结果:

3.1415926535897932384626433833
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068

【讨论】:

  • 不要使用std::endl,除非你需要它的额外功能。 '\n' 结束一行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多