使用Boost计算Champernowne常数C10

时间:2017-07-17 18:40:37

标签: c++ math boost arbitrary-precision

我正在尝试使用以下公式计算Champernowne constant C10

C_b=sum_(n=1)^inftyn/(b^(n+sum_(k=1)^(n)|_log_bk_|))

在上面的公式中,我用 b 代替10来计算C10。我希望能够使用Boost cpp_dec_float来计算任何精度的常数。

这是我的代码:

#include <boost/multiprecision/cpp_dec_float.hpp>

const long long PRECISION = 100;

typedef boost::multiprecision::number<
    boost::multiprecision::cpp_dec_float<PRECISION> > arbFloat;

arbFloat champernowne()
{
    arbFloat c, sub, n, k;
    std::string precomp_c, postcomp_c;

    for(n = 1; n == 1 || precomp_c != postcomp_c; ++n) {
        for(k = 1; k <= n; ++k) {
            sub += floor(log10(k));
        }

        precomp_c = static_cast<std::string>(c);
        c += n / pow(10, n + sub);
        postcomp_c = static_cast<std::string>(c);
    }

    return c;
}

以下是代码的细分:

  1. 我首先定义一个变量arbFloat,其精度为100位(经常更改 - 所以我不想使用cpp_dec_float_100)。

    < / LI>
  2. 该公式有两个求和块,所以我使用两个for循环实现它们。在最里面的for循环中,我计算以k = 1开头的总和,以k <= n floor(log10(k))为条件。

  3. 我已经确认在floor()上使用log10()cpp_dec_float会以正确的精度返回变量。

    1. 因为最外面的总和一直到无穷大,所以我必须在某个时刻停止计算。为了检查是否已超出精度,我在计算c之前将c += n / pow(10, n + sub)转换为字符串 - 然后在进行计算后将其转换为字符串。如果字符串相同,我结束计算,因为已经超出了精度(进一步的计算将是多余的)。
    2. 我还使用了这个设置(使用字符串转换和比较来检查超出的精度)来计算其他变量 - 并且效果非常好。

      1. 接下来,我计算c += n / pow(10, n + sub)的最外部总和 - 使用pow()以这种方式 保持精度。最后,我返回c
      2. 当我运行这个程序时,我得到以下变量:

        0.1234567891001100120001300001400000150000001600000001700000000180000000001900000000002000000000000210
        

        VS。 真实的 Champernowne常数C10:

        0.1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253546
        

        只有前11位数字正确,其余数字则不正确。我无法找到我错的地方。我尝试过以下方法:

        • 尝试用c += n / pow(10, n + sub)替换c += n / pow(static_cast<arbFloat>(10), n + sub)以检查pow()是否无法保持精确度 - 但它没有改变任何内容。

        • 尝试使用将floor()转换为字符串的方法替换log10(k)并“舍入”字符串(仅保留.之前的字符) - 但它没有更改任何东西。

        • 尝试将k <= n更改为k < nk <= n + 1 - 以防万一我误解了总和 - 但这只会使其更加不准确。

        如果我需要解释更多,请告诉我。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

sub的前一个值在每次迭代时继续进行;在循环中声明它。

arbFloat champernowne() {
    arbFloat c;

    for (int n = 1;; ++n) {
        arbFloat sub;

        for (int k = 1; k <= n; ++k) {
            sub += floor(log10(k));
        }

        arbFloat const last = c;
        c += n / pow(10, n + sub);

        if (c == last) {
            break;
        }
    }

    return c;
}