转自若流芳千古
当一个数非常大时,如何求出其前几位呢?
如果是给定一个特定的数,当然可以逐步取出每一位即可。如
a得个位,a/10得百位,a/10/10得千位。
但是,当求x^y的前几位时怎么办呢?若x,y都非常大,则显然很难解决:也许可以用大数乘法,暴力求解,结果自然是既占内存,又耗时间。
还有,此题斐波拉契数列的前几位,显然求出每个斐波拉契数是不现实的。因此,可以采用取对数的方法来解决。
先看对数的性质,loga(b^c)=c*loga(b),loga(b*c)=loga(b)+loga(c);假设给出一个数10234432,那么log10(10234432)=log10(1.0234432*10^7)=log10(1.0234432)+7
log10(1.0234432)就是log10(10234432)的小数部分.
log10(1.0234432)=0.010063744
10^0.010063744=1.023443198,
要求该数的前4位,则将1.023443198*1000即可。
因此,pow(10.0,x的小数部分)即可方便求出x的前几位。
求一数的前4位的对数方法可以表述为:
double x,temp;
while(scanf("%lf",&x)!=EOF)
{
temp=log(x)/log(10.0);
temp=temp-floor(temp); //floor(temp)函数求出小于temp的最大整数
temp=pow(10.0,temp);
while(temp<1000)
temp*=10;
//printf("%.0lf\n",temp); //采用浮点表达法时会四舍五入
printf("%d\n",(int)temp);//此处不需四舍五入,直接舍弃后面的位
}
}
下面给出斐波那契数列通项公式:
但是这个题要是直接套公式还是会超时,所以我们将通项公式左右取对数,化简得
log10(F(n))=-0.5*log10(5.0)+((double)n)*log(s)/log(10.0)+log10(1-((1-√5)/(1+√5))^n)
s = (1+sqrt(5.0))/2.0;
例子转自xieqinghuang
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
//const int N = 2;
struct Mat
{
int matrix[N][N];
};
Mat mat, mt;
int n, m = 10000;
Mat mul(Mat a, Mat b) ///***********************
{
int i, j, k;
Mat c;
for (i = 0; i <2 ; i++) //N
for (j = 0; j < 2; j++) //N
{
c.matrix[i][j] = 0;
for (k = 0; k < 2; k++) //N
{
c.matrix[i][j] += a.matrix[i][k] * b.matrix[k][j];
if (c.matrix[i][j] >= m) //m=10000,即取最后四位。
c.matrix[i][j] %= m;
}
}
return c;
}//****************************************8
Mat solve(int m)
{
Mat mt;
if (m==1)
return mat;
if (m%2==1) //m为奇数时。(m&1)
return mul(solve(m-1), mat);
else //m 为偶数。
{
mt = solve(m / 2);
return mul(mt, mt);
}
}
//*********************************************
inline void init()
{
mat.matrix[0][0] = mat.matrix[0][1] = mat.matrix[1][0] = 1;
mat.matrix[1][1] = 0;
}
int main()
{
int f[40] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
int i;
for (i = 11; i < 40; ++i)
{
f[i] = f[i - 1] + f[i - 2];
}
//freopen("t", "r", stdin);
while (scanf("%d", &n) != EOF)
{
if (n < 40) //小于八位的直接输出!
{
printf("%d\n", f[n]);
continue;
}
double temp = (1 + sqrt(5.0)) / 2.0;
double val = n * log10(temp) - 0.5 * log10(5.0);
temp = val - (int) val;
temp = pow(10.0, temp);
//while(temp < 1000)
temp *= 1000;
printf("%d...", (int) temp); //输出前四位!!
Mat ans; //[1 1]
init(); //********** // [1 0]给矩阵赋值。
ans = solve(n - 1); //*********************???????????????????????????
i = ans.matrix[0][0];
if (i < 10)
printf("000%d\n", i);
else if (i < 100)
printf("00%d\n", i);
else if (i < 1000)
printf("0%d\n", i);
else
printf("%d\n", i);
}
return 0;
}
<提取的公因式s,然后将后面化成两式相乘的形式>