python利用math.pow, pow和 ** 进行指数运算的问题
1、问题说明
在刷力扣的时候碰到这样两道题,剑指Offer14-1和剑指Offer14-2,发现解题方法思路相同,但是用不用的办法算最后的结果,值竟然不一样,于是开始寻找问题。具体代码和结果如下:
class Solution:
def cuttingRope(self, n: int) -> int:
if n <= 3: return n - 1
a, b, p = n // 3, n % 3, 1000000007
print(a, b)
print(math.pow(3, a) % p)
print(int(3 ** float(a)) % p)
if b == 0: return 3 ** a % p
if b == 1: return 3 ** (a - 1) * 4 % p
return 3 ** a * 2 % p
输入: 120
输出:
40 0
953271157.0
953271190
可以看到,这个时候都是计算3的a次幂,但是值却不一样了。
2、接下来对math.pow(),pow() 和 ** 进行简单介绍
- math.pow(x, y)
这个函数是math里面的函数,会自动将y转为浮点数进行计算,这个时候得到的结果也是浮点数。 - ** 运算符,(x ** y)返回的值类型是取决于y,如果y为int型,则会返回int型;如果是float型,则返回float型。
- pow()是与**一样的,因为pow里面返回的就是它,pow函数说明如下,接下来我们仅围绕math.pow()和 * * 运算符方式进行讨论。
3、进行实验
我们进行了如下实验,发现了一些问题:
import math
a = math.pow(3, 40)
b = math.pow(3, float(40))
c = 3 ** 40
d = 3 ** float(40)
>>>a - c
0.0
>>>a - b
0.0
>>>a - d
0.0
>>>a == b
True
>>>a == c
False
>>>a == d
True
>>>b == c
False
变量值:
- 发现(1)
通过这四种方式算得的值,仅有第三种是int形式,同时做差发现都为0.0,这个时候我们以为他们是相等的。
- 发现(2)
发现虽然我们做差都是等于0.0.看似相等,但是真正用==判断的时候,却不相等。
- 发现(3)
虽然发现(1)看似相等,但是这个时候我们将a or b or d
三个float类型的数据进行int转换,这个时候再去减就存在较大差值了。而我们将c
转为float,再去最差和==,都是没问题的。这个时候我们怀疑是int的时候,存在数据损失,而float则没什么问题。
>>>int(a) - c
-33
>>>int(a) == c
False
>>>a - float(c)
0.0
>>>a == float(c)
True
- 发现(4)
这时候回到那两道力扣题,offer 14-1解题如下,他是遵循math.pow()的结果:
Offer14-2解题如下,它遵循**运算:
小结,两种方法在遇见比较大的数的时候,其实是有问题的,但是这两道题却遵循不同的方法,这让我十分困惑,并且没有找到解决方案。
4、 进一步的实验
我们想确定,math.pow()和 ** 运算哪个不准,所以我们就行了如下实验:
import math
for i in range(10,100):
print(i)
# 查看i是int型时,最后的值
print('int num: %d' % 3 ** i)
# 查看i是float型时,最后的值
print('flo num: %20.2f' % math.pow(3, float(i)))
print(math.pow(3, float(i)) == 3 ** i)
print('---------------')
输出:
33
int num: 5559060566555523
flo num: 5559060566555523.00
True
---------------
34
int num: 16677181699666569
flo num: 16677181699666568.00
False
---------------
上述实验发现,在i=34的时候,两种方法算的值不再相同了。
认真观测可以发现,在i=33的时候,两个值相等,证明都没有问题,但是再乘3,就不对了吗,重点是i==33时,int型的值乘3是等于i=34时的数值的,说明i=34的时候,int型(通过* *计算)的值是没问题的,而而是浮点数值出错。
以上,其实我并没有弄清楚为什么,但是希望大家能都知道这个问题的存在,欢迎大家交流指正。