在工作中,我们可以会遇到这样的问题,两组大量的小数相乘,然后比较两组结果的大小。例如100个0.0001相乘与100个0.0002相乘,哪个结果大?很显然,100个0.0002相乘的结果比较大。但是在计算机中,太多的小数相乘,会遇到下溢问题,即变量小时位数太多,无法完全存储。例如本例中,两组结果小时位数都将达到400位,这时候输出两组结构,都将是0,这时候就无法比较大小了,解决这个问题的方法,是对结果取自然对数。
这里使用到对数的两个特性:
第一个是对应f(x)和ln(f(x)),他们在相同的区间内,虽然结果不一样,但是都具有相同的单调性,即同时增加同时减小
第二个是ln(a*b)=ln(a)+ln(b)
第一个特性,我们可以通过下图直观的看到:
对于两个数,对较大的数取自然对数,结果也一定大于对较小的数取自然对数的结果。比如:ln(0.123)>ln(0.122)
回到本例中,如果先计算0.0001^100和0.0002^100,其结果已经下溢为0了,然后再他们取自然对数,那他们的结果肯定是相等的,所以这里就要使用对数的第二个特性:ln(a*b)=ln(a)+ln(b)将先乘再取对数,转换为先求对数,再求和。在本例中就是
m=ln(0.0001^100)=ln(0.001)+ln(0.001)+ln(0.001)……
n=ln(0.0002^100)=ln(0.002)+ln(0.002)+ln(0.002)……
最后得到的结果必定n>m
以下为python的测试代码:
a=[0.0001]*100 #初始化1个个包含100个0.0001的列表
b=[0.0002]*100 #初始化1个个包含100个0.0002的列表
m=1
n=1
for d in a: #直接计算两个列表中元素的乘积
m*=d
for d in b:
n*=d
print('m=:'+str(m)+',n='+str(n)) #输出结果,可以得知,m,n的结果都是0
print(n>m)
for d in a: #转换成自然对数的求和
m+=log(d)
for d in b:
n+=log(d)
print('m=:'+str(m)+',n='+str(n)) #输出m,n的值
print(n>m) #比较m,n得到正确的结果
输出结果:
runfile('C:/Users/Administrator/untitled5.py', wdir='C:/Users/Administrator')
m=:0.0,n=0.0
False
m=:-921.034037198,n=-851.719319142
True