我现在要做的是翻译此解决方案,该解决方案将数字的mantissa计算为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)."
我的尝试(由数学和this code引发)失败了......:
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
m:0
n ^ m:1
计算的尾数:1.16334
n:2
m:1
n ^ m:2
计算的尾数:2.32667
n:2
m:2
n ^ m:4
计算的尾数:4.65335
n:2
m:98
n ^ m:3.16913e + 29
计算的尾数:8.0022
n:2
m:99
n ^ m:6.33825e + 29
计算的尾数:2.16596
答案 0 :(得分:3)
我为此避免pow
。众所周知,正确实施起来非常困难。有很多SO问题,人们在标准库中被错误的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的幂时,你会看到最差的foo
的ulp是2 -29 。这尤其意味着,即使完美实现,使用long double
也不能超过此方法的8位数。
some_epsilon
将是最小long double
,使expl(foo)
始终超出数学上正确的结果;我还没准确计算出来,但它应该是1e-9
的顺序。
鉴于这里的精确困难,我建议使用像MPFR这样的库来代替long double
。您也可以使用double double
技巧和四元精度exp
,log
和fmod
来获得一些效果。