在Python 3中,我正在检查给定值是否为三角形,也就是说,对于某个正整数n,它可以表示为n(n + 1)/ 2
我可以写一下:
import math
def is_triangular1(x):
num=(1/2) * (math.sqrt(8*x+1)-1 )
return int(num)==num
或者我需要这样做吗? :
epsilon = 0.000000000001
def is_triangular2(x):
num=(1/2) * (math.sqrt(8*x+1)-1 )
return abs(int(num) - num)<epsilon
我检查了两个函数返回x的相同结果,最多为1,000,000。但我不确定一般来说int(x)== x将始终正确地确定一个数字是否为整数,因为例如5的情况表示为4.99999999999997等。
据我所知,第二种方法是正确的,如果我用C语言,但我不确定Python 3。
答案 0 :(得分:25)
python float类型中有is_integer
函数:
>>> float(1.0).is_integer()
True
>>> float(1.001).is_integer()
False
>>>
答案 1 :(得分:10)
您的实施都存在问题。实际上可能会发生最终类似4.999999999999997
的内容,因此使用int()
不是一种选择。
我会采用一种完全不同的方法:首先假设你的数字是三角形,并计算n
在这种情况下的情况。在第一步中,您可以慷慨地进行回合,因为如果实际的数字是三角形,则只需要得到正确的结果。接下来,为此n * (n + 1) / 2
计算n
,并将结果与x
进行比较。现在,您正在比较两个整数,因此没有任何不准确之处。
通过扩展
可以简化n
的计算
(1/2) * (math.sqrt(8*x+1)-1) = math.sqrt(2 * x + 0.25) - 0.5
并利用
round(y - 0.5) = int(y)
表示积极y
。
def is_triangular(x):
n = int(math.sqrt(2 * x))
return x == n * (n + 1) / 2
答案 2 :(得分:8)
你会想做后者。在 Python 3编程中,以下示例是最准确的比较方法
def equal_float(a, b):
#return abs(a - b) <= sys.float_info.epsilon
return abs(a - b) <= chosen_value #see edit below for more info
此外,由于epsilon是“机器可以区分两个浮点数的最小差异”,因此您需要在函数中使用&lt; =。
编辑:在阅读了下面的评论之后,我回头看了一下这本书,它特别说明了“这是一个简单的函数,用于比较浮点数的相等性和机器精度的极限”。我相信这只是将浮点数与极端精度进行比较的一个例子,但事实上,许多浮点计算引入了错误,这种情况应该很少使用。我把它描述为在我的答案中比较的“最准确”的方式,在某种意义上它是正确的,但很少在将浮点数或整数与浮点数进行比较时的意图。根据函数的“问题域”而不是使用sys.float_info.epsilon选择值(例如:0.00000000001)是正确的方法。
感谢S.Lott和Sven Marnach的更正,如果我带领任何人走错路,我道歉。
答案 3 :(得分:5)
Python确实有一个Decimal
类(在the decimal
module中),您可以使用它来避免浮点数的不精确。
答案 4 :(得分:4)
浮点数可以精确地表示其范围内的所有整数 - 浮点相等只是在关注点之后的位时才是棘手的。因此,只要公式中的所有计算都返回您感兴趣的案例的整数,int(num)== num就完全安全了。
所以,我们需要证明,对于任何三角形数字,你所做的每一个数学运算都可以用整数运算来完成(任何以非整数形式出现的数据都必须意味着x不是三角形):
首先,我们可以假设x必须是一个整数 - 这在'三角数'的定义中是必需的。
在这种情况下,8 * x + 1也将是一个整数,因为整数在+和*下关闭。
math.sqrt()返回float;但如果x是三角形,则平方根将是一个整数 - 即,再次精确表示。
因此,对于应该在函数中返回true的所有x,int(num)== num将为true,因此istriangular1将始终有效。正如该问题的评论中所提到的,唯一的关键点是默认情况下Python 2以与C - int / int =&gt;相同的方式进行整数除法。 int,如果结果不能完全表示为int,则截断。所以,1/2 == 0.这在Python 3中得到修复,或者通过行
来修复from __future__ import division
靠近代码顶部。
答案 5 :(得分:2)
我认为模块十进制是你需要的
答案 6 :(得分:1)
您可以将您的号码四舍五入到小数点后14位:
>>> round(4.999999999999997, 14)
5.0
PS:双精度约为15位小数
答案 7 :(得分:1)
很难与标准争论。
在C99和POSIX中,将float舍入为int的标准由nearbyint()定义。重要的概念是舍入方向和特定于语言环境的舍入约定。
假设约定是common rounding,这与Python中的C99约定相同:
#!/usr/bin/python
import math
infinity = math.ldexp(1.0, 1023) * 2
def nearbyint(x):
"""returns the nearest int as the C99 standard would"""
# handle NaN
if x!=x:
return x
if x >= infinity:
return infinity
if x <= -infinity:
return -infinity
if x==0.0:
return x
return math.floor(x + 0.5)
如果您想要更多地控制舍入,请考虑使用Decimal module并选择您希望使用的舍入约定。例如,您可能希望使用Banker's Rounding。
确定约定后,舍入为int并与其他int进行比较。
答案 8 :(得分:1)
考虑使用NumPy,他们会照顾好一切。
import numpy as np
result_bool = np.isclose(float1, float2)
答案 9 :(得分:0)
Python仍然使用相同的浮点表示和C操作,所以第二个是正确的方法。
答案 10 :(得分:0)
在引擎盖下,Python的float类型是C double。
最强大的方法是将最接近的整数设置为num,然后测试整数是否满足您所追求的属性:
import math
def is_triangular1(x):
num = (1/2) * (math.sqrt(8*x+1)-1 )
inum = int(round(num))
return inum*(inum+1) == 2*x # This line uses only integer arithmetic