2013-04-14 41 views
7

Phá vỡ vòng thắt tròn tiêu chuẩn theo quy ước IEEE 754, để làm tròn một nửa tới số chẵn gần nhất. Có cách nào để chỉ định hành vi làm tròn khác nhau, ví dụ: vòng về phía không hoặc hướng tới -inf? Tôi không nói về ceil hoặc sàn, tôi chỉ cần phá vỡ tie khác nhau.Phá vỡ vòng tròn với số lố có kích thước

+3

Ra khỏi tò mò, làm thế nào có thể những quy tắc tie-phá vỡ trở nên thích hợp trong thực tế? Sau khi tất cả, sự khác biệt là trong cùng một thứ tự độ lớn như lỗi lượng tử hóa. – maxy

+1

Tôi đang xây dựng lại một số tính toán phức tạp từ MATLAB trong python. Việc phá vỡ tie có khác nhau, do đó, nó phá hủy một số trường hợp thử nghiệm, khi tôi so sánh kết quả. – Michael

Trả lời

9

NumPy không kiểm soát chế độ làm tròn bên trong. Dưới đây là hai lựa chọn thay thế:

  1. Sử dụng gmpy2, như được nêu trong this answer. Điều này cung cấp cho bạn toàn quyền kiểm soát chế độ làm tròn, nhưng sử dụng gmpy2 cho phép toán phao đơn giản có thể chậm hơn NumPy.
  2. Sử dụng fesetround qua ctypes để đặt chế độ làm tròn theo cách thủ công. Đây là hệ thống cụ thể bởi vì các hằng số có thể thay đổi theo nền tảng; kiểm tra fenv.h để biết giá trị không đổi trên nền tảng của bạn. Trên máy tính của tôi (Mac OS X):

    import numpy as np 
    import ctypes 
    FE_TONEAREST = 0x0000 
    FE_DOWNWARD = 0x0400 
    FE_UPWARD = 0x0800 
    FE_TOWARDZERO = 0x0c00 
    libc = ctypes.CDLL('libc.dylib') 
    
    v = 1./(1<<23) 
    print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0 
    libc.fesetround(FE_UPWARD) 
    print repr(np.float32(1+v) - np.float32(v/2)) # prints 1.0000002 
    
+5

Cảm ơn câu trả lời của bạn! Để hoàn thành: Sử dụng linux, tôi tìm thấy fesetround không có trong libc, nhưng trong libm, do đó, dòng tải là 'libm = ctypes.CDLL ('libm.so.6')'. Các hằng số giống nhau. – Michael

0

Với SWIG phần mềm mã nguồn mở

Để hoàn thành câu trả lời nneonneo, nếu bạn không muốn tải về một gói lớn như gmpy2 không sử dụng một mã hệ thống cụ thể với ctypes, bạn có thể sử dụng một ràng buộc từ C với SWIG (giả sử rằng bạn đã có nó trên máy tính của bạn).

Đây là những gì bạn cần làm (trong bốn bước):

1) Viết đầu tiên một tập tin có tên rounding.i:

%module rounding 
%{ 
/* Put header files here or function declarations like below */ 

void rnd_arr(); 
void rnd_zero(); 
void rnd_plinf(); 
void rnd_moinf(); 
void rnd_switch(); 
%} 

extern void rnd_arr(); 
extern void rnd_zero(); 
extern void rnd_plinf(); 
extern void rnd_moinf(); 
extern void rnd_switch(); 

2) Sau đó, một file rnd_C.cpp

#include <stdio.h> 
#include <stdlib.h> 
#include <fenv.h> 


void rnd_arr() 
{ 
    fesetround(FE_TONEAREST); 
} 


void rnd_zero() 
{ 
    fesetround(FE_TOWARDZERO); 
} 

void rnd_plinf() 
{ 
    fesetround(FE_UPWARD); 
} 

void rnd_moinf() 
{ 
    fesetround(FE_DOWNWARD); 
} 

void rnd_switch() 
{ 
    int r=fegetround(); 

    if (r==FE_UPWARD) 
    r=FE_DOWNWARD; 
    else 
    if (r==FE_DOWNWARD) 
     r=FE_UPWARD; 
    else fprintf(stderr,"ERROR ROUDING MODE \n"); 
    fesetround(r); 
} 

3) Trong terminal của bạn (nếu bạn sử dụng một phiên bản khác hơn python2.7, thay thế python2.7 ở dòng thứ hai):

swig -c++ -python -o rounding_wrap.cpp rounding.i 
g++ -fPIC -c rounding_wrap.cpp rnd_C.cpp -I/usr/include/python2.7 
g++ -shared rounding_wrap.o rnd_C.o -o _rounding.so 

4) nhập _rounding.so thư viện mà bạn vừa tạo bằng cách vỗ nhẹ vào đầu file python của bạn:

from your_path_to_rounding.so import rounding 
Các vấn đề liên quan