# 11.11 完整例子:二项式

本节中，我们以一个应用开发者的角度来看一个较为复杂的例子。这里的代码需要使用之前章节所提到的编译技术进行转换，转换成一个正确，且有较高性能OpenCL实现。应用我们选择了二项式期权。注意，我们不会从数学和经济学的角度深度探讨该问题，只是对于编译器作者来说，将其做为一个完整的例子。

```cpp
void binomial_options_gpu(
  std::vector<float> &v_s,
  std::vector<float> &v_x,
  std::vector<float> &v_vdt,
  std::vector<float> &v_pu_by_df,
  std::vector<float> &v_pd_by_df,
  std::vector<float> &call_value)
```

上面的代码就是二项式期权函数的声明，其中call\_value作为存储最终结果的对象，其他的参数都仅作为输入参数。

```cpp
extent<1> e(data_size);
arrar_view<float, 1> av_call_value(e, call_value);
av_call_value.discard_data();
```

为了将输入数据输入内核函数，数据需要通过`C++ AMP`的容器进行包装。本例中，使用`concurrency::array_view`。av\_call\_value对象调用discar\_data，就是用来告诉运行时，这段数据无需从主机端拷贝到设备端。

```cpp
array_view<const float, 1> av_s(e, v_s);
array_view<const float, 1> av_x(e, v_x);
array_view<const float, 1> av_vdt(e, v_vdt);
array_view<const float, 1> av_pu_by_df(e, v_pu_by_df);
array_view<const float, 1> av_pd_by_df(e, v_pd_by_df);

exten<1> ebuf(MAX_OPTIONS * (NUM_STEPS + 16));
array<float, 1> a_call_buffer(ebuf);
```

注意这里av\_s，av\_x，av\_vdt，av\_pu\_by\_df，av\_pd\_by\_df均由array\_view包装，也就是在计算完成后不需要拷贝回主机。

```cpp
extent<1> compute_extent(CACHE_SIZE * MAX_OPTIONS);
parallel_for_each(compute_extent.tile<CACHE_SIZE>(),
  [=, &a_call_buffer]tile_index<CACHE_SIZE> ti)restrict(amp){
    binomial_options_gpu(ti, av_s, av_x, av_vdt, av_pu_by_df, av_pd_by_df, av_call_value, a_call_buffer);
  });
av_call_value.synchronize();
```

`C++ AMP`使用parallel\_for\_each完成计算。在计算完成之后，使用同步成员函数对计算结果进行同步，以确保所有计算结果都已经保存在容器中。所有使用到的数据都会在运行时进行隐式处理。编程者不需要显式的在设备和主机之间进行数据的传递或拷贝。注意parallel\_for\_each使用显式线程划分进行线程局部控制。

```cpp
void binomial_options_kernel(
  tiled_index<CACHE_SIZE> &tidx,
  array_view<const float, 1> s,
  array_view<const float, 1> x,
  array_view<const float, 1> vdt,
  array_view<const float, 1> pu_by_df,
  array_view<const float, 1> pd_by_df,
  array_view<float, 1> call_value,
  array<float, 1> &call_buffer) restrict(amp){

  index<1> tile_idx = tidx.tile;
  index<1> local_idx = tidx.local;

  tile_static float call_a[CACHE_SIZE + 1];
  tile_static float call_b[CACHE_SIZE + 1];

  int tid = local_idx[0];
  int i;

  for (i = tid; i <= NUM_STEPS; i+= CACHE_SIZE){
    index<1> idx(tile_idx[0] * (NUM_STEPS + 16) + (i));
    call_buffer[idx] = expiry_call_value(s[tile_idx], x[tile_idx], vdt[tile_idx], i);
  }

  for (i = NUM_STEPS; i > 0; i -= CACHE_DELTA){
    for (int c_base = 0; c_base < i; c_base += CACHE_STEP){
      int c_start = min(CACHE_SIZE - 1, i - c_base);
      int c_end = c_start - CACHE_DELTA;

      tidx.barrier.wait();
      if (tid <= c_start){
        index<1> idx(tile_idx[0] * (NUM_STEPS + 16) + (c_base + tid));
        call_a[tid] = call_buffer[idx];
      }

      for (int k = c_start - 1; k >= c_end;){
        tidx.barrier.wait();
        call_b[tid] = pu_by_df[tile_idx] * call_a[tid + 1] + pd_by_df[tile_idx] * call_a[tid];
        k--;

        tidx.barrier.wait();
        call_a[tid] = pu_by_df[tile_idx] * call_b[tid + 1] + pd_by_df[tile_idx] * call_b[tid];
        k--;
    }

    tidx.barrier.wait();
    if (tid <= c_end){
      index<1> idx(tile_idx[0] * (NUM_STEPS + 16) + (c_base + tid));
      call_buffer[idx] = call_a[tid];
    }
  }

  if (tid == 0){
    call_value[tile_idx] = call_a[0];
  }
}
```

声明为tile\_static类型的数据将在同一工作组内进行共享。为了确保共享数据的一致性，我们这里使用了tidx.barrier.wait函数。在同一工作组内的工作项将会在这个调用点进行等待，直到工作组内所有线程都到达该调用点为止。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://chenxiaowei.gitbook.io/heterogeneous-computing-with-opencl2-0/11.0-chinese/11.11-chinese.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
