Sự khác biệt lớn đáng kinh ngạc khi tiến hành nhận dạng lượng giác với NumPy


8

Theo Wolfram Alpha và hệ thống đại số máy tính Sage , danh tính sau giữ:

cos(arctan(l1l2d))=11+(l1l2)2d2

Tuy nhiên, khi tôi cố gắng xác minh nó bằng một ví dụ tùy ý trong NumPy, tôi nhận thấy một sự khác biệt khá lớn trong các giá trị thực tế được tính toán bởi cả hai mặt của sự bình tĩnh. Tôi đã sử dụng mã sau đây:

    l1 = 10; l2 = 8; d = 17
    from numpy import arctan2, cos, sin, sqrt

    alpha = arctan2((l1-l2),d)
    left = cos(alpha)

    right = sqrt(1 + ((l1-l2)**2)/(d**2))

Đánh giá kết quả leftrightmang lại kết quả như sau:

    left = 0.99315060432287616
    right = 1.0

Thật là hấp dẫn khi viết nó ra chỉ đơn giản là một lỗi số, nhưng vì tôi có rất ít kinh nghiệm về cách các lỗi số lớn có thể nhận được, tôi không chắc lắm. Điều này có thể hay tôi đang thiếu một cái gì đó (rõ ràng)?


2
của bạn rightđược nhập không chính xác. đó là right = 1/sqrt() khi tôi nhập công thức vào Ti-89, tôi nhận được một trận đấu có 12 chữ số tại 0,99315 ...
Godric Seer

Vâng, tôi nghĩ rằng anh ta đã bắt được rằng nếu biểu thức căn bậc hai đã được đánh giá chính xác.
Michael Grant

vâng, khi tôi nhập vào biểu hiện của anh ấy, tôi đã nhận được 1.007, điều chắc chắn sẽ được nhìn thấy.
Godric Seer

1
Ồ, thật đấy. Đó là lúng túng. Cảm ơn đã chú ý.
Daniel Eberts

Đã phạm sai lầm này trước bản thân mình.
Michael Grant

Câu trả lời:


10

Tôi có một nghi ngờ rằng biểu thức Python của bạn cho phía bên phải đang thực hiện phân chia số nguyên, không phải phân chia dấu phẩy động. Kết quả là, ((l1-l2)**2)/(d**2)được đánh giá là 0 và thuật ngữ bên trong căn bậc hai là một.

Trên thực tế, bạn cũng quên mất tính tương hỗ trong biểu hiện bên tay phải, nhưng đó không phải là vấn đề đầu tiên ...

Trong MATLAB:

>> l1 = 10; l2 = 8; d = 17;
>> alpha = atan2((l1-l2),d)
alpha =
    0.1171
>> left = cos(alpha)
left =
    0.9932
>> right = 1/sqrt(1 + ((l1-l2)^2)/(d^2))
right =
    0.9932

6
Tôi đã có thói quen sử dụng from __future__ import divisionở đầu tất cả các tập lệnh python của tôi cho mục đích này.
Geoffrey Irving

@GeoffreyIrving, biến điều đó thành một câu trả lời và tôi cá là bạn sẽ nhận được một số đại diện nghiêm túc cho điều đó. Lời khuyên tốt.
Michael Grant

7

Như Michael C. Grant đã chỉ ra, vấn đề là phép toán chia là phép chia số nguyên, không phải phép chia dấu phẩy động. Trong các phiên bản của Python trước 3, chia hai số nguyên bằng cách sử dụng số làm /tròn thành số nguyên. Hành vi này có thể được thay đổi bằng cách thêm

from __future__ import division

ở đầu tập lệnh của bạn. Lưu ý rằng khai báo này thay đổi hành vi /chỉ cho tệp hiện tại. Nếu bạn muốn hành vi ban đầu thỉnh thoảng, sử dụng //(dấu gạch chéo kép). Điều này được thảo luận chi tiết hơn ở đây:

PEP 238 - Thay đổi Người vận hành Bộ phận

Lưu ý rằng trong khi hầu hết các ngôn ngữ bao gồm C có ngữ nghĩa tương tự để phân chia, thì ngữ nghĩa lại khó hiểu hơn trong Python vì các số nguyên thường không được quảng bá thành float khi được truyền cho các hàm. Do đó, một hàm được viết như thể nó đang hoạt động trên phao trên thực tế có thể hoạt động trên các số nguyên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.