01. Vector Addition

From arrays x and y of length N, compute z[i] = x[i] + y[i]. You combine the array allocation, views, for_each, and host-side readout from Chapter 7.

What to implement

  1. Set N = 1000 and prepare three arrays x, y, and z as Array1D<double, Backend> (Backend is defined as in the Practice introduction).

  2. Get a view from each array with view().

  3. Initialize with for_each and MISO_LAMBDA: x[i] = 0.37 * i and y[i] = 1.3 * i.

  4. Compute z[i] = x[i] + y[i] in a separate for_each.

  5. Prepare an Array1D<double, backend::Host>, copy z into it with copy_from, and check the result.

The elements of an Array1D are not initialized just by allocating it, so fill every element in step 3 before reading in step 4. Inside the lambda, use views, not Array1D.

Checking the result

On the host, compute the same initialization expressions separately and add the two values to make the expected value. z[0] = 0, and z[999] is about 1668.33. Compute the difference for every element and print the maximum absolute error.

Also print the number of elements that pass a comparison allowing differences up to 1e-15 * max(1, |expected|), and the number of elements that match exactly. Some expected values are 0, so do not use a relative error that divides by the expected value itself.

Once this check passes on the CPU, you can move on to the next assignment.

Running on the GPU

After reading Chapter 9, build the same source in a separate build folder for CUDA. Use the same inputs and perform the same comparison as on the CPU. On the GPU, rounding can differ from the CPU because of optimizations such as FMA, which merges a multiplication and an addition into one instruction. Check with the tolerance-based comparison, not only the count of exact matches.