2012-11-30 31 views
5

我写了一个名为analyze_the_shape的函数,它取得了一个2D顶点列表,使得该列表按照二维欧几里德空间中顶点的顺时针遍历顺序排列。为什么我会得到ValueError:数学域错误?

我在口译员称它为[(0, 0), (0, 4.0), (4.0, 4.0), (4.0, 0)]作为输入,但我得到ValueError : math domain error。我期望看到return ["SQUARE", 4.0]。我能做什么 ?

import math 

def analyze_the_shape(liste): 
    if len(liste) == 2 : 
     d = ((liste[1][0] - liste[0][0])**2 + (liste[1][1] - liste[0][1])**2)**(0.5) 
     return ["LINESEGMENT", d ] 
    if len(liste) == 4 : 
     d1 = abs(((liste[1][0] - liste[0][0])**2 + (liste[1][1] - liste[0][1])**2)**(0.5)) 
     d2 = abs(((liste[2][0] - liste[1][0])**2 + (liste[2][1] - liste[1][1])**2)**(0.5)) 
     d3 = abs(((liste[3][0] - liste[2][0])**2 + (liste[3][1] - liste[2][1])**2)**(0.5)) 
     d4 = abs(((liste[0][0] - liste[3][0])**2 + (liste[0][1] - liste[3][1])**2)**(0.5)) 
     hypo = abs(((liste[2][1] - liste[0][1])**2 + (liste[2][0] - liste[0][0])**2)**(0.5)) 
     cos_angle = float((hypo**2 - (d3)**2 + (d4)**2)/((-2.0)*(d4)*(d3))) 
     angle = math.degrees(math.acos(cos_angle)) 
     if d1 == d2 == d3 == d4 and abs(angle - 90.0) < 0.001 : 
      return ["SQUARE", d1] 

这是我的错误:

>>> import a 
>>> a.analyze_the_shape([(0, 0), (0, 4.0), (4.0, 4.0), (4.0, 0)]) 
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
File "a.py", line 15, in analyze_the_shape 

ValueError: math domain error 

回答

1

当我运行代码,堆栈跟踪我得到的是:

Traceback (most recent call last): 
    File "md.py", line 22, in <module> 
    analyze_the_shape([(0, 0), (0, 4.0), (4.0, 4.0), (4.0, 0)]) 
    File "md.py", line 18, in analyze_the_shape 
    angle = math.degrees(math.acos(cos_angle)) 
ValueError: math domain error 

我知道math.acos只接受值,使得-1.0 <= x <= 1.0 。如果我在行angle = math.degrees(math.acos(cos_angle))之前打印出cos_angle < -1.0,则会打印True。如果我打印出cos_angle,它会打印-1.0

我猜这里的问题是,Python存储cos_angle的方式并不完美,并且您为cos_angle生成的值仅略小于-1.0

也许它会更好,如果不是检查abs(angle - 90.0) < 0.001,而是检查是否abs(cos_angle) < 0.001

编辑

我觉得你在这一行有一个错误:

cos_angle = float((hypo**2 - (d3)**2 + (d4)**2)/((-2.0)*(d4)*(d3))) 

它可能应该是:

cos_angle = float((hypo**2 - ((d3)**2 + (d4)**2))/((-2.0)*(d4)*(d3))) 

注意周围(d3)**2 + (d4)**2额外的括号。这可以确保在之前完成,您从hypo**2中减去该数量。

+0

'abs(angle-90.0)<0.001'和'abs(cos_angle + 1)<0.001'并不意味着相同。如果'angle = 90','cos_angle = 0'。如果'cos_angle = -1','angle = 180'。 –

+0

好赶上!我认为在OP设置“cos_angle”时出现错误 - 我在回答中指出了这一点。 –

+0

“Python存储'cos_angle'的方式并不完美”。这应该是“在计算机上表示浮点数的方式并不完美,因此计算错误是不可避免的”。 Python与此完全无关。 – Bakuriu

8

此例外意味着cos_angle不是math.acos的有效参数。

具体而言,在本例中,它正好低于-1,这是在acos定义之外。

你也许可以尝试强迫你返回内[-1,1]cos_angle的东西,如:

def clean_cos(cos_angle): 
    return min(1,max(cos_angle,-1)) 

但是,这将不会返回SQUARE,因为cos_angle或多或少等于-1在你的榜样,并angle从而等于180。在例外之前,您的计算可能存在问题。

0

尝试舍入cos_angle。我有同样的问题;在我的脚本中,math.acos(x)中的x的值出现为-1.0000000000000002。为了解决它,我只是将x的值舍入到小数点后六位,所以它出现到-1.0。

2

我有同样的问题,事实证明@crld是正确的。 我的输入值应该是在范围[-1,1],但是......

print('{0:.32f}'.format(x)) 
>> 1.00000000000000022204460492503131 

所以,作为一般规则,我建议所有四舍五入你送入math.acos彩车。

相关问题