Files
python/TangDou/AcWing/Log/对数知识推导及应用.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

9.1 KiB
Raw Blame History

对数知识推导及应用

一、对数知识

1、对数概念

如果\large N=a^x,那么数$x$称为以$a$为底$N$的对数。记做:

\large x=log_aN

其中,$a$称做底数,$N$称做真数。需要注意的是底数$a$的限制条件:$a>0,a \neq 1$。

2、对数与指数关系

对数与指数互为逆运算:

  • 指数运算: 求$10$的$2$次方,即:\large 10^2=100
  • 对数运算:求$10$的多少次方等于$100$,即:\large log_{10}100=2

3、对数形式

  • 常用对数:以$10$为底的对数记做:\large log_{10}N=lgN

  • 自然对数:以无理数$e=2.71828...$为底数的对数简记为:lnN 自然底数$e$的含义

  • 一般对数:log_aN

4、对数性质

$1$的对数 $1$的对数是0: $$\large log_a1=0$$

积的对数 $$\large log_aMN=log_aM+log_aN$$

证明:设\large log_aM=p,log_aN=q 则\large a^p=M,a^q=N,代入\large log_aMN, 得$\large log_aMN=log_a({a^p\cdot a^q})=log_a{a^{p+q}}=p+q=log_aM+log_aN$ 

证毕


商的对数 $$\large log_a{\frac{M}{N}}=log_aM-log_aN$$ 证明:设\large log_aM=p,log_aN=q 则\large a^p=M,a^q=N,代入\large \displaystyle log_a{\frac{M}{N}}, 得\large \displaystyle log_a{\frac{M}{N}}=log_a{(\frac{a^p}{a^q})}=log_a{a^{p-q}}=p-q=log_aM-log_aN

证毕


幂的对数 $$\large log_aM^b=b\cdot log_aM$$ 证明:设\large log_aM=p,则\large a^p=M 则\large a^p=M,代入 \large log_aM^b 得\large log_aM^b=log_a{(a^p)^b}=log_a{a^{p\cdot b}}=pb=b\cdot log_aM

证毕


对数恒等式 $$\large a^{log_aM}=M$$ 证明: 设\large \displaystyle log_aM=p,则\large \displaystyle a^p=M,代入\large \displaystyle a^{log_aM} 得\large \displaystyle a^{log_aM}=a^{log_aa^p}=a^p=M

证毕


5、换底公式

\large log_bN=\frac{log_aN}{log_ab}

证明: 设\large log_bN=x,则\large b^x=N 两边同时取以$a$为底的对数 $$\large log_ab^x=log_aN \ x\cdot log_ab=log_aN \ x=\frac{log_aN}{log_ab} \ 即log_bN=\frac{log_aN}{log_ab}



--- 

#### 6、其他公式
<font color='red' size=4><b>$$\large log_{a^n}a=\frac{1}{n}$$</b></font>
证明:
设$\large log_{a^n}a=p$
则$\large (a^n)^p=a$,即$\large a^{np}=a$
两边同时取以$10$为底对数,$$\large lga^{np}=lga \\
\Rightarrow  np \cdot lga=lga \\ 
\Rightarrow 
np=1 \\ 
\Rightarrow p=\frac{1}{n}

证毕


$$\large \frac{1}{log_ab}=log_ba $$ 证明: 用换底公式:

\large \frac{1}{log_ab}=\frac{1}{\frac{lgb}{lba}}=\frac{lga}{lgb}=log_ba

证毕


$$\large log_{a^n}M=\frac{1}{n}\cdot log_aM $$

证明:设\large log_aM=p 则\large a^p=M,代入\large log_{a^n}M

\large log_{a^n}a^p=p\cdot log_{a^n}a=\frac{1}{n}\cdot p=\frac{1}{n}\cdot log_aM

证毕


二、典型应用

1、求数$a$的位数

暴力解法

#include <stdio.h>
int a,b;
int main(){   
    scanf("%d",&a);
    while(a){
        a=a/10;
        b++;
    }
    printf("%d ",b);
    return 0;
}

可以吗?可以,就是如果算的数太多,而且每个数很大,就太慢了,人总是贪婪的,想要更快的办法:

公式

\large a的位数 = log_{10}(a) + 1

证明:

假设 10^{x-1} <= a < 10^{x},(想一想 100,$999$和1000) ,可见$a$的位数为 x 位。

我们再对上式用 log_{10}

\large log_{10}10^{x-1}<=log_{10}a<log_{10}10^x

得 \large x-1 <= log_{10}a < x

则 $$\large x-1 = log_{10}a \ \Rightarrow \ x = log_{10}a + 1$$

所以:$a$的位数为 \large log_{10}a + 1

证毕

$C++$语言中只有$log$(以$e$为底)和$log10$(以$10$为底)两种函数。

如果想表达log_ab 那么可以使用换底公式:$log(b)/log(a)$来解决。

#include<iostream>
#include<cmath>
using namespace std;
int main(){
    int n;
    cin>>n;
    cout<<(int)(log10(n))+1;
    return 0;
}

2、求数$n!$的位数

1、递推法 先利用一下求数字$a$的位数公式:

\large n!的位数=log_{10}(n!)+1

展开一下阶乘的概念

\large =log_{10}(n\times(n-1)\times(n-2)\times...\times1)+1

利用积的对数性质

\large =log_{10}(n)+log_{10}(n-1)+…+log_{10}(1)+1

编程时,利用这个递推的关系由小到大进行递推即可。

练习题

POJ $1423$

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;
/*
思想:底数相同的两个数相乘底数不变,指数相加。
通过log10(x)得到指数,依次相加即可,即可以得到阶乘的位数
*/
const int N = 10000010;
int a[N];

int main() {
    //预处理出阶乘的位数
    double x = 0;
    for (int i = 1; i < N; i++) {
        x += log10((double)i); // POJ对于log10(i)会报编译错误,需要转为double
        a[i] = x + 1;
    }

    // T次询问
    int T;
    scanf("%d", &T);
    while (T--) {
        int n;
        scanf("%d", &n);
        printf("%d\n", a[n]);
    }
    return 0;
}

这样的做法时间复杂度为 O(n) ,当$n$的范围特别大时就不好用了,下面我们来找到$O(1)$的做法 斯特林公式 :

2、斯特林(Stirling)公式 斯特林公式 : 是一条用来 计算$n$的阶乘近似值 的数学公式。一般来说,当$n$很大的时候,$n$阶乘的计算量十分大,所以斯特林公式十分好用,即使在$n$很小的时候,斯特林公式的取值也十分准确。

\LARGE n!=\sqrt{2\pi n}(\frac{n}{e})^n
  • 用斯特林公式求n!
  • 再用求$a$的位数公式计算$n!$的位数:\displaystyle \LARGE log_{10}( \sqrt{2\pi n} *(\frac{n}{e})^n)+1

变形一下: $$\LARGE log_{10}(2\pi n)/2+nlog_{10}(n/e)+1$$

练习题

POJ $1423$

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <queue>
#include <algorithm>
#include <math.h>
#include <cstdio>

#define PI acos(-1)
#define E exp(1.0)

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n;
        scanf("%d", &n);
        int y = log10(2 * PI * n) / 2 + log10(n / E) * n + 1;
        printf("%d\n", y);
    }
}
  • 主要是利用利用数学函数中的反三角函数,但是要注意一定引入$math$包\LARGE acos(-1)=\pi

3、求$2^p-1$的位数

首先我们知道$\large 2^p-1$与$\large 2^p$有着相同的位数,因为$2$的次方满足了最后一位不为零的要求,所以减一后位数并不会改变,那么我们可以直接求$\large 2^p$的位数。

使用的知识是:求数字$a$的位数办法:

$$\LARGE 2^p位数=log_{10}2^p+1= p\cdot log_{10}{2}+1$$。

练习题: P1045 [NOIP2003 普及组] 麦森数

#include <bits/stdc++.h>

using namespace std;
const int N = 1e5 + 10;
int a[N], al;
int b[N], bl;

void mul(int a[], int &al, int b[], int bl) {
    int c[N] = {0}, cl = al + bl;
    for (int i = 1; i <= al; i++)
        for (int j = 1; j <= bl; j++)
            c[i + j - 1] += a[i] * b[j];

    int t = 0;
    for (int i = 1; i <= al + bl; i++) {
        t += c[i];
        c[i] = t % 10;
        t /= 10;
    }
    memcpy(a, c, sizeof c);
    al = min(500, cl);
    //前导0
    while (al > 1 && a[al] == 0) al--;
}

//快速幂+高精度 x^k
void qmi(int x, int k) {
    a[++al] = 1, b[++bl] = x; // 2 ^100 b[1]=2
    while (k) {
        if (k & 1) mul(a, al, b, bl);
        k >>= 1;
        mul(b, bl, b, bl);
    }
}

int main() {
    //计算 2^p-1的值
    int y;
    cin >> p;
    //利用快速幂,计算2^p
    qmi(2, p);
    //最后一位减去一个1,因为2^k最后一位肯定不是0,所以减1不会产生借位,直接减去即可!
    a[1]--;

    //一共多少位
    printf("%d\n", (int)(p * log10(2) + 1));

    for (int i = 500; i; i--) {
        printf("%d", a[i]);
        //该换行了,就是到了第二行的行首
        if ((i - 1) % 50 == 0) puts("");
    }
    return 0;
}