2012-11-30 14 views
5

Tôi đã viết một hàm có tên analyze_the_shape lấy danh sách các đỉnh 2D sao cho danh sách theo thứ tự của một chiều ngang theo chiều kim đồng hồ của các đỉnh trong không gian 2D Euclide.Tại sao tôi nhận được ValueError: lỗi miền toán học?

Tôi gọi điện thoại trong thông dịch viên và cung cấp [(0, 0), (0, 4.0), (4.0, 4.0), (4.0, 0)] làm đầu vào nhưng tôi nhận được ValueError : math domain error. Tôi hy vọng sẽ thấy return ["SQUARE", 4.0]. Tôi có thể làm gì ?

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] 

Đây là lỗi tôi nhận được:

>>> 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 

Trả lời

1

Khi tôi chạy mã của bạn, stack trace tôi nhận được là:

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 

Tôi biết math.acos chỉ chấp nhận những giá trị mà -1.0 <= x <= 1.0 . Nếu tôi in ra cos_angle < -1.0 ngay trước dòng angle = math.degrees(math.acos(cos_angle)), nó sẽ in True. Nếu tôi in ra cos_angle, nó sẽ in -1.0.

Tôi đoán vấn đề ở đây là cách cửa hàng Python cos_angle không hoàn hảo và giá trị bạn tạo cho cos_angle chỉ vừa đủ ít hơn -1.0.

Có lẽ sẽ tốt hơn, nếu thay vì kiểm tra abs(angle - 90.0) < 0.001, bạn đã kiểm tra xem abs(cos_angle) < 0.001 hay chưa.

Sửa:

Tôi nghĩ rằng bạn có một lỗi trong dòng này:

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

Nó có lẽ nên được:

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

Lưu ý các dấu ngoặc thêm khoảng (d3)**2 + (d4)**2. Điều này đảm bảo rằng việc bổ sung được thực hiện trước khi bạn trừ số lượng đó khỏi hypo**2.

+0

'abs (góc - 90.0) <0,001' và' abs (cos_angle + 1) <0,001' không có nghĩa là giống nhau. Nếu 'góc = 90',' cos_angle = 0'. Nếu 'cos_angle = -1',' angle = 180'. –

+0

Bắt tốt! Tôi nghĩ rằng có một lỗi mà OP đặt 'cos_angle' - tôi đã chỉ ra rằng trong câu trả lời của tôi. –

+0

"cách cửa hàng Python' cos_angle' không hoàn hảo ". Điều này nên "các con số điểm trôi nổi được biểu diễn trên một máy tính không hoàn hảo, và do đó các lỗi tính toán là không thể tránh khỏi". Python hoàn toàn không có gì để làm với điều này. – Bakuriu

8

Trường hợp ngoại lệ này có nghĩa là cos_angle không phải là thông số hợp lệ cho math.acos.

Cụ thể, trong ví dụ này, chỉ dưới -1, nằm ngoài định nghĩa acos.

Bạn có thể có thể cố gắng ép buộc bạn trở cos_angle trong [-1,1] với một cái gì đó như:

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

Tuy nhiên, điều này sẽ không quay trở lại SQUARE, vì cos_angle là nhiều hơn hoặc ít tương đương với -1 trong ví dụ của bạn, và angle do đó bằng 180. Có thể có vấn đề với tính toán của bạn trước khi ngoại lệ.

0

Thử làm tròn cos_angle. Tôi có vấn đề này như nhau; trong tập lệnh của tôi, giá trị của x trong math.acos(x) xuất hiện thành -1.0000000000000002. Để khắc phục nó, tôi chỉ làm tròn giá trị cho x đến sáu chữ số thập phân để nó xuất hiện ở -1.0.

2

Tôi gặp vấn đề tương tự và chỉ ra @crld là đúng. giá trị đầu vào của tôi có nghĩa vụ phải được trong khoảng [-1, 1], nhưng ...

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

Vì vậy, như một quy luật chung, tôi đề nghị làm tròn tất cả các phao nổi bạn ăn vào math.acos.

Các vấn đề liên quan