我尝试使用BigInteger.Pow
方法计算类似10 ^ 12345.987654321的内容,但此方法只接受整数作为指数,如下所示:
BigInteger.Pow(BigInteger x,int y)
那么如何在上面的方法中使用双数作为指数?
答案 0 :(得分:5)
C#中没有任意精确的大数字支持,所以这不能直接完成。有一些替代方案(例如寻找第三方库),或者您可以尝试类似下面的代码 - 如果基数足够小,就像您的情况一样。
public class StackOverflow_11179289
{
public static void Test()
{
int @base = 10;
double exp = 12345.123;
int intExp = (int)Math.Floor(exp);
double fracExp = exp - intExp;
BigInteger temp = BigInteger.Pow(@base, intExp);
double temp2 = Math.Pow(@base, fracExp);
int fractionBitsForDouble = 52;
for (int i = 0; i < fractionBitsForDouble; i++)
{
temp = BigInteger.Divide(temp, 2);
temp2 *= 2;
}
BigInteger result = BigInteger.Multiply(temp, (BigInteger)temp2);
Console.WriteLine(result);
}
}
这个想法是使用大整数数学来计算指数的整数部分的幂,然后使用双(64位浮点)数学来计算分数部分的幂。然后,使用
这一事实a ^ (int + frac) = a ^ int * a ^ frac
我们可以将两个值组合成一个大整数。但是简单地将double值转换为BigInteger会失去很多精度,所以我们首先将精度“移动”到bigInteger上(使用上面的循环,以及double
类型使用52位的事实精确度),然后乘以结果。
请注意,结果是近似值,如果想要更精确的数字,则需要一个可以进行任意精度浮点数学运算的库。
更新:如果基数/指数足够小,功率将在double
范围内,我们可以简单地执行Sebastian Piu建议的内容(new BigInteger(Math.Pow((double)@base, exp))
)
答案 1 :(得分:2)
我喜欢carlosfigueira的答案,但当然他的方法的结果只能在第一个(最重要的)15-17位数上正确,因为System.Double
最终会被用作乘数。
值得注意的是,确实存在执行“逆”操作的方法BigInteger.Log
。因此,如果您想计算Pow(7, 123456.78)
,理论上,您可以搜索所有BigInteger
个数字x
,找到一个数字,BigInteger.Log(x, 7)
等于123456.78
或比123456.78
类型的任何其他x
更接近BigInteger
。
当然,对数函数正在增加,因此您的搜索可以使用某种“二分搜索”(二分搜索)。我们的答案位于Pow(7, 123456)
和Pow(7, 123457)
之间,两者都可以准确计算。
如果需要,请跳过其余部分
现在,我们如何提前预测是否存在多个对数为123456.78
的整数,精度为System.Double
,或者实际上没有对数达到该对数的整数具体Double
(理想Pow
函数的确切结果是无理数)?在我们的示例中,将有非常多的整数给出相同的Double
123456.78
因为因子m = Pow(7, epsilon)
(其中epsilon
是最小的正数,因此123456.78 + epilon
具有与Double
本身的表示不同的123456.78
表示,其大小足以使真实答案与真实答案之间的整数乘以m
。
从微积分中记得,数学函数x → Pow(7, x)
的导数是x → Log(7)*Pow(7, x)
,因此所讨论的指数函数图的斜率为Log(7)*Pow(7, 123456.78)
。这个数字乘以上面的epsilon
仍远远大于一,所以有很多整数满足我们的需要。
实际上,我认为carlosfigueira的方法会给出一个“正确”的答案x
,因为Log(x, 7)
与Double
的{{1}}具有相同的代表性123456.78
。但有人试过吗? : - )
答案 2 :(得分:1)
我会提供另一个答案,希望更清楚。重点是:由于System.Double
的精度限制为约。 15-17个十进制数字,任何Pow(BigInteger, Double)
计算的结果将具有更加有限的精度。因此,没有希望比carlosfigueira的答案更好。
让我用一个例子说明这一点。假设我们想要计算
Pow(10, exponent)
在这个例子中,我选择exponent
双精度数
const double exponent = 100.0 * Math.PI;
这当然只是一个例子。 exponent
的值(十进制)可以作为
314.159265358979
314.15926535897933
314.1592653589793258106510620564222335815429687500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
这些数字中的第一个是您通常看到的(15位数)。第二个版本使用exponent.ToString("R")
生成,包含17位数字。请注意,Double
的精度小于17位。上面的第三个表示是exponent
的理论“精确”值。请注意,这与第17位附近的数学数字100π不同。
要弄明白Pow(10, exponent)
应该是什么,我只是对BigInteger.Log10(x)
的{{1}}进行了x
,以了解我如何重现exponent
。因此,此处提供的结果仅反映了.NET Framework的BigInteger.Log10
。
事实证明来自
的任何BigInteger x
0x0C3F859904635FC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
through
0x0C3F85990481FE7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
使Log10(x)
等于exponent
,精度为15位。同样,来自
0x0C3F8599047BDEC0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
through
0x0C3F8599047D667FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
满足Log10(x) == exponent
精度Double
。换句话说,{em>来自后一范围的任何数字与Pow(10, exponent)
的结果同样“正确”,仅仅是因为exponent
的精度非常有限。
(插曲:0
和F
的串联揭示了.NET的实现只考虑了x
的最重要的字节。他们并不关心更好,正是因为Double
类型具有这种有限的精度。)
现在,引入第三方软件的唯一原因是,如果坚持,exponent
将被解释为上面给出的十进制数中的第三个。 (Double
类型允许您准确指定所需的数字真是奇迹,是吗?)在这种情况下,Pow(10, exponent)
的结果将是一个带尾的非理性(但代数)数字永不重复的小数。如果没有舍入/截断,它就无法放入整数。 PS!如果我们将指数作为实数100π,那么数学上的结果会有所不同:我怀疑是一些超越数。