将任意长度的浮点值舍入为n位数字

Round arbitrary-length floats to n digits

本文关键字:舍入 数字 任意长      更新时间:2023-10-16

我已经阅读了大多数与"四舍五入到n数字"相关的SO问题。我认为这个问题是独立的,因为它更多地与任意长度浮点的舍入有关。

0.56714329040978387299996866221035554975381578718651250813513107922304579308668456669321944696175229455773495728285284421635951688

上面的数字是我使用的数字类型的一个例子。

我知道如何在C++中四舍五入一个数字,它相当简单。然而,我不明白如何将任意长的数字四舍五入到n位。

例如,我可能有一个192位的数字,需要四舍五入到84位,或者一个1831位的数字需要四舍五入到293位。如何使用一个函数(或类似函数(来完成此操作?

为了清晰起见,我使用了伪代码,但实际上我使用Boost多精度cpp_dec_foat来处理任意精度的浮点,而不是标准浮点:

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

我遇到的另一个问题是,当试图将很长的浮点值舍入为少量数字时。

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

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

四舍五入可以基于:

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