开方计算与浮点数的问题

最近一直纠结于一个点,在于二分法中的延申题,就是给出一个列表和一个数X,要我们在其中找出两个数a,b使a**n+b**n=X的数学问题,为了方便描述,以下中n取3.

其实很简单,首先我们要建立一个升序列表。

import random
random.seed(10) #保证每次随机选的数相同
A=[random.randint(1,10000) for _ in range(100000)] #尽量大一点,尽量取到每一个数
A.sort()

下面我们再定义一个二分搜索的函数

def binary_search(A,x): #搜索列表A找数x
    i,j = 0,len(A)-1
    while i<= j:
        k=(i+j)//2
        if A[k]==x:
            return k
        if x>A[k]:
            i=k+1
        else:
            j=k-1
    return -1 #没找到返回-1

基本思路是遍历A中的前n-1个数(留一个数用于匹配,此数记为a),并计算相应的立方根值((X-a**3)**(1/3)),看看这个值是否在A中,如果在就返回,不在就继续找,直到找完还没有就返回-1

这是正确的代码

import random

#二分查找
def binary_search(A, x):
    ########## begin ##########
    # 请在此填写代码,找到x返回索引号,没找到返回-1
    i,j = 0,len(A)-1
    while i<=j:
        k=(i+j)//2
        if x==A[k]:
            return k
        elif x<A[k]:j=k-1
        else:i=k+1
    return -1 #没找到返回-1        
    ########## end ##########

random.seed(10) 
A=[random.randint(1,10000) for i in range(100000)]
A.sort()
X=eval(input())

founded=False
for i, a in enumerate(A[:-1]):#遍历前n-1个数
    ########## begin ##########
    # 请在此填写代码,输出找到的a和b,没找到返回-1
    
    Y=X-a**3
    if Y<0:continue #注意Y有可能小于0
    b=-1
    for i in range(int(Y**0.5)):#判断Y的三次方根是否为整数 那么必然在一定的范围能能找到i**3=Y
        if i**3==Y: 
          b=i
          break    
    
    if b==-1:continue
    
    idx = binary_search(A[i+1:], b) #logn
    if idx != -1:
        print(a, int(b))
        founded = True
        break    
    ########## end ##########
if not founded:print('-1')

可以发现这个算法用了一个很聪明的办法判断Y的立方根是不是整数,那就是先开0.5次方,再遍历找开立方根得到的数i。因为如果Y是可开三次方根的整数,则i=Y**(1/3)一定是整数,稍微将幂指数放大一点就可以找到这个i了(因为range是左闭右开的),如果在这个范围内没有符合条件的那么就说明Y不是整数。


我想到了模除运算,整数模除1一定是0,便用了这个性质。

错误的代码

c=X-a**3
if c<0:continue
b=c**(1/3)
if b%1==0:
    idx=binary_search(A[m+1:],b]
if idx!=-1:
    print(a,b)

试了很多遍,都不能过评测


原因是但是这样与开方的运算结合是有问题的

开方运算返回的是浮点数,而浮点数在计算机中实际上是以二进制的形式保存的,有些数并不精确,它内层有自己的保存方法,只是返回给我们的是十进制。小数的二进制的换算方法是采用“除二取整,再排序”

具体实操是:将小数乘以2,取整数部分,余下的小数部分再继续乘以2,直到小数部分为0.

0.1*2=0.2  取整数部分0

0.2*2=0.4  取整数部分0

0.4*2=0.8  取整数部分0

0.8*2=1.6  取整数部分1

0.6*2=1.2  取整数部分1

0.2*2=0.4  取整数部分0

0.4*2=0.8  取整数部分0

0.8*2=1.6  取整数部分1

0.6*2=1.2  取整数部分1 可以发现这样会无限循环下去

但是内存有限呀,不可能一直算下去,因此python内层会默认算到第X位,就不管了,默认算完了,因此是有小的误差的,python会默认将其返回。0.1与0.2都是这样,因此1.1+2.2的结果并不是3.3。

也即是说再python的运算中,浮点数并不是最终的结果。能不用就尽量不用。

这也就解释了开三次根号得不到整数的原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一袍清酒付825

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值