2011-08-08 22 views
9

Tôi có một số toán (trong C++) mà có vẻ là để tạo ra một số rất nhỏ, gần bằng không, số (tôi nghi ngờ các hàm gọi trig là vấn đề thực sự của tôi), nhưng tôi muốn phát hiện những trường hợp này để tôi có thể nghiên cứu chi tiết hơn.Làm thế nào để kiểm tra và xử lý các con số rất gần với số

Tôi hiện đang thử những điều sau, có đúng không?

if (std::abs(x) < DBL_MIN) { 
    log_debug("detected small num, %Le, %Le", x, y); 
} 

Thứ hai, bản chất của toán học là lượng giác trong tự nhiên (hay còn gọi là sử dụng rất nhiều lần chuyển đổi radian/độ và sin/cos/tan cuộc gọi, vv), những gì sắp xếp của biến đổi tôi có thể làm để tránh các lỗi toán học ?

Rõ ràng đối với phép nhân tôi có thể sử dụng log transform - còn gì nữa?

+0

Chúng ta có thể vui lòng xem một ví dụ về toán học đã nói, để chúng ta có thể nghĩ ra một điều gì đó thanh lịch? Những gì tôi có trong tâm trí của tôi là những thứ như 'cos x - 1' khi bạn có thể nhận được từ từ thay đổi kết quả khoảng không, và phải chọn cẩn thận khoan dung. –

+1

Đối với các phép biến đổi để tránh các dòng dưới, điều trực tiếp nhất là Taylor mở rộng các biểu thức của bạn và sử dụng những gì xuất hiện cho các đối số nhỏ. Ví dụ, thay vì '1-cos (x)' sử dụng 'x * x/2' cho' x' nhỏ hơn một số ngắt. –

Trả lời

2

Nếu x là gấp đôi, thì một vấn đề với phương pháp này là bạn không thể phân biệt giữa x là số không hợp pháp và x là giá trị dương nhỏ hơn DBL_MIN. Vì vậy, điều này sẽ làm việc nếu bạn biết x không bao giờ có thể hợp pháp bằng không, và bạn muốn xem khi nào xảy ra tràn.

Bạn cũng có thể thử bắt tín hiệu SIGFPE, sẽ kích hoạt trên hệ thống tuân thủ POSIX bất kỳ lúc nào có lỗi toán học bao gồm cả tràn dòng động. Xem: http://en.wikipedia.org/wiki/SIGFPE

EDIT: Để được rõ ràng, DBL_MIN KHÔNG phải là giá trị âm lớn nhất mà một đôi có thể giữ, đó là nhỏ tích cực normalized giá trị mà một đôi có thể giữ. Vì vậy, cách tiếp cận của bạn là tốt miễn là giá trị không thể bằng không.

Một hằng số hữu ích khác là DBL_EPSILON là giá trị gấp đôi nhỏ nhất có thể được thêm vào 1.0 mà không cần lấy lại 1.0. Lưu ý rằng đây là một giá trị lớn hơn nhiều so với DBL_MIN. Nhưng nó có thể hữu ích cho bạn vì bạn đang làm các hàm lượng giác có thể có xu hướng hướng tới 1 thay vì hướng tới 0.

2

Vì bạn đang sử dụng C++, thành ngữ nhất là sử dụng std::numeric_limits từ tiêu đề <limits>.

Ví dụ:

template <typename T> 
bool is_close_to_zero(T x) 
{ 
    return std::abs(x) < std::numeric_limits<T>::epsilon(); 
} 

Dung sai thực tế sẽ được sử dụng chủ yếu phụ thuộc vào vấn đề của bạn. Vui lòng hoàn thành câu hỏi của bạn với trường hợp sử dụng cụ thể để tôi có thể nâng cao câu trả lời của mình.

Ngoài ra còn có std::numeric_limits<T>::min()std::numeric_limits<T>::denorm_min() có thể hữu ích. Giá trị đầu tiên là giá trị không chuẩn hóa dương nhỏ nhất của loại T (bằng FLT/DBL/LDBL_MIN từ <cfloat>), giá trị thứ hai là giá trị dương nhỏ nhất của loại T (không có <cfloat> tương đương).

[Bạn có thể tìm this document hữu ích để đọc nếu bạn không thoải mái với các số dấu phảy đại diện.]

+0

Có thể sau ngày hôm nay, sau khi tôi tìm ra phần nào của eqns đang gây ra sự cố. Cảm ơn bạn đã mua Tidbit C++! – Petriborg

+0

'DBL_MIN' là giá trị nhỏ nhất ** được chuẩn hóa **' double', vì vậy nó sẽ tương ứng với 'min()' và không phải 'denorm_min()'. –

+0

@DanielFischer: Thật vậy, cảm ơn. Đã sửa. –

0

Các if kiểm tra đầu tiên sẽ thực sự chỉ là đúng khi giá trị của mình là zero.

Đối với câu hỏi thứ hai, bạn ngụ ý nhiều chuyển đổi. Thay vào đó, hãy chọn một đơn vị (deg hoặc rad) và thực hiện tất cả các hoạt động tính toán của bạn trong đơn vị đó. Sau đó, ở cuối cùng làm một chuyển đổi duy nhất với giá trị khác nếu bạn cần.

+0

'DBL_MIN' là giá trị kép dương ** nhỏ nhất ** chuẩn hóa, có số nguyên dương nhỏ hơn' double'. –

5

Trái ngược với niềm tin phổ biến, DBL_MIN không phải là giá trị dương nhỏ nhất double nhưng giá trị dương nhỏ nhất được chuẩn hóadouble giá trị. Thông thường - đối với ieee754 64 bit doubles - đó là 2 -1022, trong khi giá trị dương nhỏ nhất double là 2 -1074. Do đó

Tôi hiện đang thử những điều sau đây, có đúng không?

if (std::abs(x) < DBL_MIN) { 
    log_debug("detected small num, %Le, %Le", x, y); 
} 

có thể có câu trả lời chắc chắn. Điều kiện kiểm tra xem x có phải là không chuẩn hóa (còn được gọi là số bất thường) hoặc số ± 0.0. Nếu không biết nhiều hơn về tình hình cụ thể của bạn, tôi không thể nói rằng thử nghiệm đó có phù hợp không. Các số không chuẩn hóa có thể là kết quả hợp lý của phép tính hoặc kết quả làm tròn mà kết quả chính xác là 0. Nó cũng có thể làm tròn số có độ lớn lớn hơn DBL_MIN khi kết quả chính xác toán học là 0, vì vậy ngưỡng lớn hơn nhiều có thể hợp lý.

+0

Cảm ơn bạn đã đầu vào về vấn đề này - vấn đề vẫn đang diễn ra, nhưng tôi chưa có thời gian để quay lại và làm việc với nó. Có lẽ tôi sẽ cố gắng đăng một câu hỏi thông minh hơn đôi khi. – Petriborg

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