我正在尝试使用以下公式计算Champernowne constant C10:
在上面的公式中,我用 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;
}
以下是代码的细分:
我首先定义一个变量arbFloat
,其精度为100位(经常更改 - 所以我不想使用cpp_dec_float_100
)。
该公式有两个求和块,所以我使用两个for循环实现它们。在最里面的for循环中,我计算以k = 1
开头的总和,以k <= n
floor(log10(k))
为条件。
我已经确认在floor()
上使用log10()
和cpp_dec_float
会以正确的精度返回变量。
c
之前将c += n / pow(10, n + sub)
转换为字符串 - 然后在进行计算后将其转换为字符串。如果字符串相同,我结束计算,因为已经超出了精度(进一步的计算将是多余的)。我还使用了这个设置(使用字符串转换和比较来检查超出的精度)来计算其他变量 - 并且效果非常好。
c += n / pow(10, n + sub)
的最外部总和 - 使用pow()
以这种方式 保持精度。最后,我返回c
。当我运行这个程序时,我得到以下变量:
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 < n
,k <= n + 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;
}