C++中的对数函数 log 与指数函数 exp
困难14指数函数 exp 和对数函数 log:互为“最亲密”的数学朋友
你有没有听说过“指数爆炸”——比如一张纸对折42次就能从地球到月球?或者玩《我的世界》时,小村民数量每5分钟翻一番?这些都是指数函数在生活中的影子。在C++中,exp(x) 就是计算 自然常数 e 的 x 次方(e ≈ 2.71828),而 log(x) 则是它的“反操作”:告诉你“要把多少e乘起来才能得到x”。它们就像一对形影不离的好朋友,一个扩张,一个还原。下面我们就用零花钱、细菌和复利来认识它们。
一、认识指数函数 exp:翻倍、复利和细菌
exp(x) 做的事很简单:计算 e^x。e 是一个神奇的无理数,约等于 2.71828。为什么非要用e?因为自然界中很多连续增长的现象(比如细菌每时每刻都在分裂)用 e 描述最自然。
举个零花钱的例子:假设你妈妈每天给你存零花钱,但方式很特别——她按“连续复利”存钱。如果你有1元本金,年利率是100%,那么一年后你的钱会变成 e^1 ≈ 2.718元。如果年利率是200%(翻两倍),两年后就是 e^2 ≈ 7.389元。这里利率就是指数中的 x。
代码看看 exp 的威力:
#include <iostream>
#include <cmath> // 包含 exp 和 log
using namespace std;
int main() {
double days = 5.0; // 翻倍次数(相当于利率)
double factor = exp(days); // 计算 e^5 ≈ 148.413
cout << "e的" << days << "次方 = " << factor << endl;
// 细菌每20分钟翻倍,问2小时后(6次翻倍)有多少个?
int start = 1; // 初始1个细菌
double growth = exp(6.0); // e^6 ≈ 403.429
cout << "2小时后,细菌数量约为 " << start * growth << " 个" << endl;
return 0;
}
生活小贴士:如果你在《植物大战僵尸》里种了向日葵,每个阳光产生器每10秒产出一份阳光,连续工作30秒后,总阳光量不是简单的线性,而是指数增长(因为新的向日葵又产生阳光)。exp 可以帮你估算最大产量。
二、认识对数函数 log:把“大数字”压缩成“小数字”
log(x) 是 exp 的反函数,它回答这个问题:“e 的多少次方等于 x?” 例如 log(7.389) ≈ 2,因为 e² = 7.389。
需要特别记住:C++ 中的 log 默认是自然对数(以 e 为底)。如果你想要以 10 为底的对数(常用对数),请用 log10(x);以 2 为底用 log2(x)(C++11起支持)。
生活中的对数无处不在:
- 声音的分贝:人耳能听到的声音强度范围极广(从轻声耳语到火箭发射),用分贝(对数尺度)来表示。比如 100 分贝是 80 分贝强度的 100 倍(因为每增加20分贝,强度×10)。
- 地震的里氏震级:震级每增加 1 级,释放的能量约增加 31.6 倍(即 10^1.5 倍)。震级是实际能量的对数。
- 考试排名:如果全班成绩差距很大,老师有时会用对数分数来平衡不同分数段的区分度。
代码例子:计算一个声音强度对应的分贝值。
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double intensity = 1000.0; // 强度,单位倍(相对基准)
double dB = 10 * log10(intensity); // 分贝 = 10*log10(相对强度)
cout << "强度 " << intensity << " 倍对应的分贝值 = " << dB << " dB" << endl;
// 反过来,知道分贝求强度
double dB_value = 30.0;
double original = pow(10, dB_value / 10); // 1000倍
cout << dB_value << " dB 对应的强度倍数为 " << original << endl;
return 0;
}
三、互为反函数:exp(log(x)) = x 和 log(exp(x)) = x
这是最核心的关系:指数和对数互为逆运算,就像加法和减法、乘法和除法。无论你先做指数再做对数,还是先对数再指数,只要参数合适,结果一定回到原数。
下面的代码验证这一点(保留了原示例并稍微扩展):
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double x = 2.0;
double exp_x = exp(x); // 计算 e^2
double log_exp = log(exp_x); // 再取对数,应该回到x
cout << "exp(2) = " << exp_x << endl;
cout << "log(exp(2)) = " << log_exp << " (应该等于2)" << endl;
double y = 10.0;
double log_y = log(y); // 计算 ln(10)
double exp_log = exp(log_y); // 再取指数,应该回到10
cout << "log(10) = " << log_y << endl;
cout << "exp(log(10)) = " << exp_log << " (应该等于10)" << endl;
// 额外:试试负数不行吧?
double negative = -5.0;
// double bad = log(negative); // ❌ 错误:log(负数) 会返回 NaN(非数字)
// cout << "log(-5) = " << bad << endl; // 取消注释会看到 nan
cout << "注意:log()的参数不能是负数或0" << endl;
return 0;
}
为什么不能对负数或0取对数? 因为任何正数的指数都不可能等于负数或0(e^x 永远 > 0),所以 log(负数或0) 没有意义。C++中会返回一个特殊值 NaN(Not a Number),继续计算可能会导致程序异常。
四、新手最容易犯的 3 个错误
错误1:忘了包含头文件 <cmath>
如果不写 #include <cmath>,直接使用 exp 或 log,编译器会报错“未定义标识符”。
错误2:误把 log 当作以 10 为底的常用对数
很多人从数学课习惯 log 表示常用对数,但在 C++ 中 log(x) 是自然对数。如果需要以 10 为底,请用 log10(x);以 2 为底用 log2(x)。
错误3:对负数和 0 取对数
double invalid = log(-3.0); // 返回 nan
double zero = log(0.0); // 返回 -inf(负无穷)
编程时要先检查参数是否为正数,可以这样保护:
double safe_log(double num) {
if (num <= 0) {
cout << "错误:数字必须大于0" << endl;
return -1; // 或返回一个错误标记
}
return log(num);
}
五、完整可运行的示例:模拟零花钱的复利增长
假设你有一笔初始零花钱 本金 = 100 元,银行按 年利率 5% 连续复利 计算。那么 t 年后的总金额公式为:金额 = 本金 × e^(利率 × t)。反过来,如果想达到某个目标金额,需要多少年?用对数求解。
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double principal = 100.0; // 本金 100 元
double rate = 0.05; // 年利率 5%
double year = 10.0; // 存 10 年
// 计算 10 年后的本息和
double amount = principal * exp(rate * year);
cout << "存 " << year << " 年后总金额 = " << amount << " 元" << endl;
// 假如想达到 200 元(翻倍),需要多少年?
double target = 200.0;
double years_needed = log(target / principal) / rate; // 反推年数
cout << "想要达到 " << target << " 元,需要 " << years_needed << " 年" << endl;
// 检查:把算出的年数代回去
double check = principal * exp(rate * years_needed);
cout << "验证:经过 " << years_needed << " 年,金额 = " << check << " 元" << endl;
return 0;
}
输出结果(近似):
存 10 年后总金额 = 164.872 元
想要达到 200 元,需要 13.8629 年
验证:经过 13.8629 年,金额 = 200 元
这个例子完美展示了 exp 和 log 如何配合解决实际问题:用 exp 正向计算,用 log 反向求解。
六、总结与相关指引
exp(x):计算 e^x,用于模拟连续增长(复利、细菌、放射性衰变)。log(x):计算自然对数 ln(x),用于压缩大范围数据或反向推算指数中的指数。- 记住它们互为反函数:
exp(log(x)) = x(x>0),log(exp(x)) = x。 - 若要计算其他底数的指数或对数,可以用换底公式:
log_a(b) = ln(b) / ln(a),或者直接使用pow(a, b)计算 a^b。
相关知识点:
pow函数 计算任意底数的幂,比如pow(10, 3) = 1000。- 三角函数
sin、cos、tan也在<cmath>中,它们与指数函数通过欧拉公式联系。 - 数学常数
M_E和M_PI定义在<cmath>中(需要#define _USE_MATH_DEFINES预处理),可以直接使用。
下次你听到“指数增长”或者“对数刻度”,别忘了打开 C++ 的 <cmath>,用 exp 和 log 来和数字玩耍——就像用加法和减法一样自然!
例题精讲
在C++中,使用<cmath>头文件后,函数log(x)返回的是?
以下哪个表达式正确计算了e的a次方(其中e是自然常数)?
在C++中,log(1)的返回值为0。
计算一个正数的自然对数后,再取指数,应回到原数。补全以下代码:
#include <cmath>
using namespace std;
double x = 5.0;
double y = log(x);
double z = exp(y);
// 此时z的值等于___以下程序从键盘读取一个正数,输出其自然对数,保留两位小数。补全代码:
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
double x;
cin >> x;
double result = log(___);
cout << fixed << setprecision(2) << result << endl;
return 0;
}