2012-01-08 8 views
5

Tôi đang bắt đầu với OpenCL, tôi có thể thấy ví dụ về vector bổ sung và hiểu nó. Nhưng tôi đã nghĩ về phương pháp hình thang. Đây là mã (C) cho phép tính tích phân cho x^2 trong [a, b].Tích hợp số - Cách song song nó?

double f(double x) 
{ 
    return x*x; 
} 

double Simple_Trap(double a, double b) 
{ 
    double fA, fB; 
    fA = f(a); 
    fB = f(b); 
    return ((fA + fB) * (b-a))/2; 
} 

double Comp_Trap(double a, double b) 
{ 
    double Suma = 0; 
    double i = 0; 
    i = a + INC; 
    Suma += Simple_Trap(a,i); 
    while(i < b) 
    { 
     i+=INC; 
     Suma += Simple_Trap(i,i + INC); 
    } 
    return Suma; 
} 

Câu hỏi là ¿cách lấy hạt nhân để tính tích phân bằng phương pháp hình thang?


Vì vậy, tôi đã suy nghĩ về ý tưởng: partials [i] = tích hợp (a, a + offset), và sau đó tạo hạt nhân để tính tổng số partials như đã đề cập Patrick87.

Nhưng, đây là cách tốt nhất?

Trả lời

2

Đây là những gì tôi nghĩ ra. Tôi đã không làm một bài kiểm tra đầu cuối cho hạt nhân này. Tôi sẽ cập nhật khi tôi có thêm chút thời gian.

comp_trap là phương pháp phân chia cơ bản & dựa trên mã bạn có ở trên. comp_trap_multi tăng độ chính xác bằng cách nhận từng mục công việc để chia mục con của mình

Bạn chỉ cần phân bổ một mảng đôi trong máy chủ sao cho mỗi nhóm công việc có một đôi để trả về kết quả của nó. Điều này sẽ giúp cắt giảm phân bổ véc tơ mà bạn muốn tránh.

Vui lòng cho tôi biết nếu có bất kỳ sự cố nào với vấn đề này.

Cập nhật:

1) thay đổi tất cả tài liệu tham khảo đôi nổi, bởi vì đôi là tùy chọn trong OpenCL

2) cứng mã hóa kích thước nhóm làm việc để 64. giá trị này là tối ưu trên hệ thống của tôi, và nên được xác định bằng thực nghiệm. Tôi thích mã hóa cứng giá trị này vượt qua trong một mảng địa phương của phao để sử dụng, bởi vì chương trình máy chủ cuối cùng sẽ chỉ sử dụng giá trị tối ưu trên hệ thống đích.

3) cố định một tính toán không chính xác (a1 đã sai, nên tốt hơn bây giờ)

/* 
numerical-integration.cl 
*/ 

float f(float x) 
{ 
    return x*x; 
} 

float simple_trap(float a, float b) 
{ 
    float fA, fB; 
    fA = f(a); 
    fB = f(b); 
    return ((fA + fB) * (b-a))/2; 
} 

__kernel void comp_trap(
    float a, 
    float b, 
    __global float* sums) 
{ 
/* 
- assumes 1D global and local work dimensions 
- each work unit will calculate 1/get_global_size of the total sum 
- the 0th work unit of each group then accumulates the sum for the 
group and stores it in __global * sums 
- memory allocation: sizeof(sums) = get_num_groups(0) * sizeof(float) 
- assumes local scratchpad size is at lease 8 bytes per work unit in the group 
ie sizeof(wiSums) = get_local_size(0) * sizeof(float) 
*/ 
    __local float wiSums[64]; 
    int l_id = get_local_id(0); 

    //cumpute range for this work item is: a1, b1 
    float a1 = a+((b-a)/get_global_size(0))*get_global_id(0); 
    float b1 = a1+(b-a)/get_global_size(0); 

    wiSums[l_id] = simple_trap(a1,b1); 

    barrier(CLK_LOCAL_MEM_FENCE); 

    int i; 
    if(l_id == 0){ 
     for(i=1;i<get_local_size(0);i++){ 
      wiSums[0] += wiSums[i]; 
     } 
     sums[get_group_id(0)] = wiSums[0]; 
    } 
} 

__kernel void comp_trap_multi(
    float a, 
    float b, 
    __global float* sums, 
    int divisions) 
{ 
/* 
- same as above, but each work unit further divides its range into 
'divisions' equal parts, yielding a more accurate result 
- work units still store only one sum in the local array, which is 
used later for the final group accumulation 
*/ 
    __local float wiSums[64]; 
    int l_id = get_local_id(0); 

    float a1 = a+((b-a)/get_global_size(0))*get_global_id(0); 
    float b1 = a1+(b-a)/get_global_size(0); 
    float range; 
    if(divisions > 0){ 
     range = (b1-a1)/divisions; 
    }else{ 
     range = (b1-a1); 
    } 

    int i; 
    wiSums[l_id] = 0; 
    for(i=0;i<divisions;i++){ 
     wiSums[l_id] += simple_trap(a1+range*i,a1+range*(i+1)); 
    } 

    barrier(CLK_LOCAL_MEM_FENCE); 

    if(l_id == 0){ 
     for(i=1;i<get_local_size(0);i++){ 
      wiSums[0] += wiSums[i]; 
     } 
     sums[get_group_id(0)] = wiSums[0]; 
    } 
} 
+0

Cảm ơn bạn rất nhiều vì mã. Tôi sẽ kiểm tra nó. –

3

Phương pháp hình thang chỉ là một sự tinh chỉnh nhẹ khi thực hiện các khoản tiền Riemann. Để làm điều này song song, bạn sẽ muốn ngắt khoảng thời gian thành nhiều khoảng con như bạn muốn có chủ đề; sau đó, có mỗi thread tích hợp chức năng trên subinterval của nó. Cuối cùng, làm giảm tổng số toàn cầu trên tất cả các tích phân được tính toán trong giai đoạn trước. Bạn có thể thử nghiệm với bao nhiêu chủ đề để sử dụng cho từng giai đoạn.

+0

Có, tôi bắt các khái niệm nhưng làm thế nào để thực hiện nó? Bởi vì Im đọc các chương đầu tiên của hướng dẫn lập trình OpenCl, nhưng nó hoạt động với các cấu trúc dữ liệu song song và khái niệm luồng không được nói. –

+0

Đó là bởi vì OpenCL không có khái niệm luồng, khái niệm tương đương là các mục công việc –

+0

Mmm yup, tôi đoán tôi nên thực hiện song song cho? –