鱼C论坛

 找回密码
 立即注册
查看: 2622|回复: 11

[已解决]如何判断一个数是不是有理数的平方

[复制链接]
发表于 2020-1-11 23:41:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
请教各位朋友,如何在python中判断一个数是不是任意有理数的平方呢?
最佳答案
2020-1-12 14:20:30
本帖最后由 Croper 于 2020-1-12 14:22 编辑

恩。。。楼主说的是一个数,是不是任意有理数的平方。
那么也包括浮点数。
所以开方取整再平方的做法肯定是不对的


另一方面,平常使用的float,在python内部存储时也是使用的二进制方式。
而二进制的小数是无法正确表示大部分十进制的小数的,
比如十进制的1.1,以二进制表示,则为1.00011001100110011001...的无限循环小数。
所以,大部分float也是经过了近似处理的,

对于1.21这种,其虽然是1.1的平方,但是:

  1. n=1.1
  2. a=sqrt(n)
  3. b=n**0.5
  4. print(a**2)  #等于1.2100000000000002
  5. print(b**2)  #等于1.2100000000000002
复制代码

因为浮点数取近似的关系,也不能做到完全正确
所以,开方再平方的做法也不能取得正确的结果。

既然以上已经说到,大部分float在计算机内部并不能精确存储。
而要精确存储一个有理数,最好的方法就是使用分数,
那么这个问题就转化成了:找到一个最接近float的,(比较简单的)分数。
比如0.3333333333能划为1/3
0.142857142857能划为1/7
1.21能划为121/100

python是自带一个分数库fractions的,但是其把小数划为分数的能力有点惨不忍睹:
  1. from fractions import Fraction
  2. a=Fraction(1.21)
  3. print(a)   #输出1362338887279575/1125899906842624
复制代码

这似乎把1.21对应的2进制近似值转化成了分数。

要解决这个问题,可以使用连分数法:
https://baike.baidu.com/item/%E8%BF%9E%E5%88%86%E6%95%B0/2715871?fr=aladdin
下面是我写的一个使用连分数法把小数划为分数的代码:
  1. def float2fraction(n):
  2.     stk=[]
  3.     for i in range(10):
  4.         a=int(round(n))
  5.         stk.append(a)
  6.         if (abs(n-a)<0.00001): break
  7.         n=1/(n-a)
  8.     num=0
  9.     den=1
  10.     for i in reversed(stk):
  11.         num,den=den,num+i*den
  12.     num,den=den,num
  13.     return fractions.Fraction(num,den)
复制代码

最多连分10次,并且当某一次结果的剩下的绝对值小于0.00001时停止迭代

来试一试这个函数:
  1. print(float2fraction(0.1))  #输出1/10
  2. print(float2fraction(1.21)) #输出121/100
  3. print(float2fraction(0.1111111111111)) #1/9
复制代码


能划为分数之后剩下的问题就简单多了,只要分子和分母都是完全平方数就说明这个有理数是另一个有理数的平方:
  1. def isSquareNum(n:int):
  2.     if (isinstance(n,int)):
  3.         return int(n**0.5)**2==n
  4.     f=float2fraction(n)
  5.     return isSquareNum(f.numerator) and isSquareNum(f.denominator)
复制代码


测试:
  1. print(isSquareNum(2))   #FALSE
  2. print(isSquareNum(4))   #TRUE
  3. print(isSquareNum(0.1)) #FALSE
  4. print(isSquareNum(0.01))#TRUE
  5. print(isSquareNum(1.44))#TRUE
  6. print(isSquareNum(1.444))#FALSE
复制代码

基本符合要求

当然,因为无法取得float的精确值,所以每种做法都是有缺陷的。这是我觉得缺陷比较小的做法,对于某些特定值,肯定也是会出错的。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-1-11 23:54:19 | 显示全部楼层
数学中怎么判断,它就怎么判断。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 02:51:08 | 显示全部楼层
本帖最后由 Judie 于 2020-1-11 19:39 编辑

emmmm,这样子?
202001111350.PNG
  1. import math
  2. while True:
  3.     n = float(input()) #接受用户输入 赋值n
  4.     a = math.sqrt(n) #取n的平方根 赋值a
  5.     b = a*a #取(n的平方根)的平方 赋值b
  6.     if b == n: #判断(n的平方根)的平方是否等于n 即 b是否等于n
  7.         print('是',a,'的平方')#等于则是
  8.     else:
  9.         print('不是')#不等于则不是

  10. #有理数是整数(正整数、0、负整数)和分数的统称,是整数和分数的集合。
  11. #整数也可看做是分母为一的分数。
  12. #不是有理数的实数称为无理数,即无理数的小数部分是无限不循环的数。

  13. #应该就是这样子的吧~
  14. #可能不是很完美,但感觉运行上去还可的样子
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 07:42:41 From FishC Mobile | 显示全部楼层
Judie 发表于 2020-1-12 02:51
emmmm,这样子?

开平方根后取整再乘方看是否相等
这个开平方根可用系统函数,也可自己写
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 07:43:38 From FishC Mobile | 显示全部楼层
Judie 发表于 2020-1-12 02:51
emmmm,这样子?

回错了,以为你是楼主
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 08:40:45 | 显示全部楼层
wp231957 发表于 2020-1-11 18:42
开平方根后取整再乘方看是否相等
这个开平方根可用系统函数,也可自己写

嗯,我的思路就是这样
能帮我看看我的code对不对吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 08:48:47 | 显示全部楼层
Judie 发表于 2020-1-12 02:51
emmmm,这样子?
  1. float(input()) ** 0.5
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 10:01:40 | 显示全部楼层

哦!然后这样就相当于取代了sqrt那步是么?也不用import math了?!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 10:03:43 | 显示全部楼层
Judie 发表于 2020-1-12 10:01
哦!然后这样就相当于取代了sqrt那步是么?也不用import math了?!


是。因为一个数的平方根 = 那个数 ^ (1 / 2),一个数的立方根 = 那个数 ^ (1 / 3),以此类推。

例如:

  1. >>> 8 ** (1 / 3)
  2. 2.0
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 10:49:19 | 显示全部楼层
zltzlt 发表于 2020-1-11 21:03
是。因为一个数的平方根 = 那个数 ^ (1 / 2),一个数的立方根 = 那个数 ^ (1 / 3),以此类推。

例如 ...

数学使人头秃。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-1-12 14:20:30 | 显示全部楼层    本楼为最佳答案   
本帖最后由 Croper 于 2020-1-12 14:22 编辑

恩。。。楼主说的是一个数,是不是任意有理数的平方。
那么也包括浮点数。
所以开方取整再平方的做法肯定是不对的


另一方面,平常使用的float,在python内部存储时也是使用的二进制方式。
而二进制的小数是无法正确表示大部分十进制的小数的,
比如十进制的1.1,以二进制表示,则为1.00011001100110011001...的无限循环小数。
所以,大部分float也是经过了近似处理的,

对于1.21这种,其虽然是1.1的平方,但是:

  1. n=1.1
  2. a=sqrt(n)
  3. b=n**0.5
  4. print(a**2)  #等于1.2100000000000002
  5. print(b**2)  #等于1.2100000000000002
复制代码

因为浮点数取近似的关系,也不能做到完全正确
所以,开方再平方的做法也不能取得正确的结果。

既然以上已经说到,大部分float在计算机内部并不能精确存储。
而要精确存储一个有理数,最好的方法就是使用分数,
那么这个问题就转化成了:找到一个最接近float的,(比较简单的)分数。
比如0.3333333333能划为1/3
0.142857142857能划为1/7
1.21能划为121/100

python是自带一个分数库fractions的,但是其把小数划为分数的能力有点惨不忍睹:
  1. from fractions import Fraction
  2. a=Fraction(1.21)
  3. print(a)   #输出1362338887279575/1125899906842624
复制代码

这似乎把1.21对应的2进制近似值转化成了分数。

要解决这个问题,可以使用连分数法:
https://baike.baidu.com/item/%E8%BF%9E%E5%88%86%E6%95%B0/2715871?fr=aladdin
下面是我写的一个使用连分数法把小数划为分数的代码:
  1. def float2fraction(n):
  2.     stk=[]
  3.     for i in range(10):
  4.         a=int(round(n))
  5.         stk.append(a)
  6.         if (abs(n-a)<0.00001): break
  7.         n=1/(n-a)
  8.     num=0
  9.     den=1
  10.     for i in reversed(stk):
  11.         num,den=den,num+i*den
  12.     num,den=den,num
  13.     return fractions.Fraction(num,den)
复制代码

最多连分10次,并且当某一次结果的剩下的绝对值小于0.00001时停止迭代

来试一试这个函数:
  1. print(float2fraction(0.1))  #输出1/10
  2. print(float2fraction(1.21)) #输出121/100
  3. print(float2fraction(0.1111111111111)) #1/9
复制代码


能划为分数之后剩下的问题就简单多了,只要分子和分母都是完全平方数就说明这个有理数是另一个有理数的平方:
  1. def isSquareNum(n:int):
  2.     if (isinstance(n,int)):
  3.         return int(n**0.5)**2==n
  4.     f=float2fraction(n)
  5.     return isSquareNum(f.numerator) and isSquareNum(f.denominator)
复制代码


测试:
  1. print(isSquareNum(2))   #FALSE
  2. print(isSquareNum(4))   #TRUE
  3. print(isSquareNum(0.1)) #FALSE
  4. print(isSquareNum(0.01))#TRUE
  5. print(isSquareNum(1.44))#TRUE
  6. print(isSquareNum(1.444))#FALSE
复制代码

基本符合要求

当然,因为无法取得float的精确值,所以每种做法都是有缺陷的。这是我觉得缺陷比较小的做法,对于某些特定值,肯定也是会出错的。

评分

参与人数 1荣誉 +6 鱼币 +6 收起 理由
zltzlt + 6 + 6

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-30 00:08:51 | 显示全部楼层
Croper 发表于 2020-1-12 14:20
恩。。。楼主说的是一个数,是不是任意有理数的平方。
那么也包括浮点数。
所以开方取整再平方的做法肯定 ...

非常非常感谢您的耐心解答,最近一直没有上线。问题的确就是您说的那个意思,您的解答我还要慢慢学习哦
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-18 10:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表