2012-03-04 16 views
17

Sử dụng NumPy, tôi có định nghĩa này của một hàm:Deal với tràn trong exp sử dụng NumPy

def powellBadlyScaled(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001 
    return f1 + f2 

Chức năng này được đánh giá một số lượng lớn các lần trên một thói quen tối ưu hóa. Nó thường làm tăng ngoại lệ:

RuntimeWarning: overflow encountered in exp 

Tôi hiểu rằng toán hạng không thể được lưu trữ trong không gian được phân bổ cho phao. Nhưng làm thế nào tôi có thể khắc phục vấn đề?

+2

Bạn cần điều chỉnh thuật toán của mình. Nếu giá trị không vừa, nó không vừa. Tìm một cách khác để diễn tả phép tính không tràn. –

+1

Điều duy nhất hợp lý bạn có thể làm là nhìn vào hành vi tiệm cận của chức năng của bạn. Nếu đó là hợp lý, sau đó trên một số ngưỡng bạn có thể thay thế tính toán rõ ràng bằng giá trị tiệm cận. Nếu giá trị tiệm cận không hợp lý thì vấn đề rất có thể là do bạn chọn thuật toán, chứ không phải trong mã. – DaveP

+1

DaveP, hành vi tiệm cận của exp là exp ... –

Trả lời

16

Bạn có thể sử dụng gói bigfloat. Nó hỗ trợ các hoạt động điểm chính xác tùy ý.

http://packages.python.org/bigfloat/

import bigfloat 
bigfloat.exp(5000,bigfloat.precision(100)) 
# -> BigFloat.exact('2.9676283840236670689662968052896e+2171', precision=100) 

Bạn đang sử dụng một khuôn khổ chức năng tối ưu hóa? Họ thường thực hiện các ranh giới giá trị (sử dụng các điều khoản hình phạt). Hãy thử điều đó. Các giá trị có liên quan thực sự là cực đoan? Trong tối ưu hóa nó không phải là không phổ biến để giảm thiểu log (f). (khả năng đăng nhập gần đúng, v.v.). Bạn có chắc chắn muốn tối ưu hóa trên giá trị đó và không đăng nhập (exp (f)) == f. ?

Hãy nhìn vào câu trả lời của tôi cho câu hỏi này: logit and inverse logit functions for extreme values

Btw, nếu tất cả các bạn cần làm là giảm thiểu powellBadlyScaled (x, y) thì tối thiểu là x -> + inf và y -> + inf, vì vậy không cần cho số.

+1

Chính xác, trong ngữ cảnh tối ưu hóa, và theo như hàm Powell Badly Scaled được sử dụng để kiểm tra, tôi áp đặt một số ràng buộc về hộp. Kịch bản đầu tiên tôi chạy cho tràn đã mất những ràng buộc vào tài khoản để khởi tạo (một số mẫu trong hộp được ủy quyền), nhưng không phải trong thói quen chính (tôi đã không kiểm tra các ràng buộc hộp nữa). Lấy các ràng buộc vào tài khoản, toán hạng không tràn. Tôi sẽ cố gắng bigfloat anyway một cái gì đó sau đó. Cảm ơn! – octoback

1

Có lẽ bạn có thể cải thiện thuật toán bằng cách kiểm tra xem bạn nhận được cảnh báo nào (có thể sẽ đặt một số giá trị nhất định cho X [0], X [1]) và thay thế kết quả bằng một số thực sự lớn. Bạn cần xem chức năng của bạn hoạt động như thế nào, tôi điều bạn nên kiểm tra ví dụ: exp(-x)+exp(-y)+x*y

0

Tùy thuộc vào nhu cầu cụ thể của bạn , có thể hữu ích khi cắt đối số đầu vào thành exp(). Nếu bạn thực sự muốn có được inf nếu nó tràn hoặc bạn muốn nhận được số lượng khổng lồ vô lý, thì các câu trả lời khác sẽ thích hợp hơn.

def powellBadlyScaled(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    f2 = numpy.exp(-numpy.float(X[0])) + numpy.exp(-numpy.float(X[1])) - 1.0001 
    return f1 + f2 


def powellBadlyScaled2(X): 
    f1 = 10**4 * X[0] * X[1] - 1 
    arg1 = -numpy.float(X[0]) 
    arg2 = -numpy.float(X[1]) 
    too_big = log(sys.float_info.max/1000.0) # The 1000.0 puts a margin in to avoid overflow later 
    too_small = log(sys.float_info.min * 1000.0) 
    arg1 = max([min([arg1, too_big]), too_small]) 
    arg2 = max([min([arg2, too_big]), too_small]) 
    # print(' too_small = {}, too_big = {}'.format(too_small, too_big)) # Uncomment if you're curious 
    f2 = numpy.exp(arg1) + numpy.exp(arg2) - 1.0001 
    return f1 + f2 

print('\nTest against overflow: ------------') 
x = [-1e5, 0] 
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x))) 
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x))) 

print('\nTest against underflow: ------------') 
x = [0, 1e20] 
print('powellBadlyScaled({}) = {}'.format(x, powellBadlyScaled(x))) 
print('powellBadlyScaled2({}) = {}'.format(x, powellBadlyScaled2(x))) 

Kết quả:

Test against overflow: ------------ 
*** overflow encountered in exp 
powellBadlyScaled([-100000.0, 0]) = inf 
powellBadlyScaled2([-100000.0, 0]) = 1.79769313486e+305 

Test against underflow: ------------ 
*** underflow encountered in exp  
powellBadlyScaled([0, 1e+20]) = -1.0001 
powellBadlyScaled2([0, 1e+20]) = -1.0001 

ý rằng powellBadlyScaled2 không qua/underflow khi bản gốc powellBadlyScaled đã làm, nhưng phiên bản sửa đổi cho 1.79769313486e+305 thay vì inf thuộc một trong các bài kiểm tra. Tôi tưởng tượng có rất nhiều ứng dụng trong đó 1.79769313486e+305 thực tế là inf và điều này sẽ ổn, hoặc thậm chí được ưa thích bởi vì 1.79769313486e+305 là một số thực và inf thì không.

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