4

我需要帮助的地方...

我现在要做的是翻译这个解决方案,它计算一个数字的尾数到 C++:

n^m = exp10(m log10(n)) = exp(q (m log(n)/q)) where q = log(10)

从结果中查找前 n 位数字可以这样完成:

"the first K digits of exp10(x) = the first K digits of exp10(frac(x))
 where frac(x) = the fractional part of x = x - floor(x)."

我的尝试(由数学和这段代码引发)失败了......:

u l l function getPrefix(long double pow /*exponent*/, long double length /*length of prefix*/)
{
   long double dummy; //unused but necessary for modf
   long double q = log(10);

   u l l temp = floor(pow(10.0, exp(q * modf( (pow * log(2)/q), &dummy) + length - 1));
   return temp;
}

如果那里的任何人都可以正确实施此解决方案,我需要您的帮助!!


编辑

我尝试的示例输出:


n: 2

米:0

n^m: 1

计算尾数:1.16334


n: 2

米:1

n^m: 2

计算尾数:2.32667


n: 2

米:2

n^m: 4

计算尾数:4.65335


n: 2

米:98

n^m: 3.16913e+29

计算尾数:8.0022


n: 2

米:99

n^m: 6.33825e+29

计算尾数:2.16596

4

1 回答 1

3

我会避免pow这样做。众所周知,很难正确实施。有很多这样的问题,人们pow在他们的标准库中被糟糕的实现所烧毁。

您还可以通过使用自然基数而不是基数 10 来为自己省去很多痛苦。您将获得如下所示的代码:

long double foo = m * logl(n);
foo = fmodl(foo, logl(10.0)) + some_epsilon;
sprintf(some_string, "%.9Lf", expl(foo));
/* boring string parsing code here */

计算 的适当类似物m log(n)。请注意,m * logl(n)可能出现的最大值仅比 大一点2e10。当您将其除以 2 64并四舍五入到最接近的 2 次方时,您会看到 ulp 最坏的情况foo是 2 -29long double这尤其意味着,即使使用完美的实现,您也不能使用 s 从该方法中得到超过 8 位数字。

some_epsilon将是最小long double的,expl(foo)总是超过数学上正确的结果;我没有准确计算,但它应该在1e-9.

鉴于这里的精度困难,我可能会建议使用 MPFR 之类的库而不是long doubles。您还可以使用double double技巧和四精度exp,logfmod.

于 2013-07-06T23:25:26.233 回答