Math Library for C++ AMP

Visual C++ developers in need of math functions know to go <cmath>. In this blog post I’ll describe the equivalent in C++ AMP.

<amp_math.h>

With C++ AMP, if you want to use a math function in your restrict(amp) functions, you need to bring in <amp_math.h> . In amp_math.h you’ll find two namespaces under the outer concurrency namespace and they are fast_math and precise_math. Under those namespaces you’ll find the function that you are looking for.

concurrency::fast_math

The functions in this namespace only support single-precision do not require double precision support.

These functions sacrifice accuracy for speed. They are wrapper functions around existing HLSL intrinsics, e.g. C++ AMP’s concurrency::fast_math::sqrt function is equivalent to HLSL’s sqrt function.

concurrency::precise_math

The functions in this namespace require and leverage full double precision support. In fact, and this is important to know, even if you use a function that takes and returns single-precision float types (i.e. seemingly has single precision requirements), the implementation still requires the accelerator to provide full double precision support. By using double precision features even for the implementation of some single precision functions, we can provide the higher accuracy of functions in this namespace.

Unlike the implementation of the functions in the fast_math namespace, the implementation of the precise_math functions was written from scratch for C++ AMP. So if you wanted to use the equivalent of the sqrt function mentioned in the previous section, you’d use concurrency::precise_math::sqrt.

By the numbers

For those of you that are curious, currently cmath contains 22 functions, fast_math 35, and precise_math contains 68 functions.

From a single precision perspective, precise_math is a superset of fast_math, which itself is a superset of cmath. From a double precision perspective, precise_math is a superset of cmath.

Code example

Consider the following full code listing (create empty C++ project, add empty cpp file, paste the 16 lines that follow)

 #include <amp.h>
#include <amp_math.h>
using namespace concurrency;
using namespace concurrency::precise_math; // 4
void main()
{
    float a = 2.2f, b = 3.5f;
    float result = pow(a,b); // 8
    std::vector<float> v(1);
    array_view<float> av(1,v);
    parallel_for_each(av.extent, [=](index<1> idx) restrict(amp)
    {
        av(0) = pow(a,b); // 13
    });
    _ASSERT(av(0) == result); // 15
}

The pow function on line 8 comes from <cmath> whereas the one on line 13 comes from precise_math, and line 15 is fine. If we were to change line 4 to use fast_math (using namespace concurrency::fast_math;) then line 13 would come from fast_math and, as a side effect, line 15 would assert (15.793534 != 15.793537).

Disclaimer about line 15: float comparison should never be done with ==, but that is not the point here. Those results are on my machine with my compiler and my hardware - your mileage may vary.

Changes in Beta, since the Developer Preview

If you used our math functions in Visual Studio 11 Developer Preview, you will have noticed that there was no amp_math.h header file and instead everything was directly under the concurrency namespace in amp.h. You would have also noticed that there were none of the two namespaces described above; instead the fast_math functions were prefixed with “fast_”. Finally, not all of precise_math was implemented so you could have encountered double-precision functions that seemingly worked on non-double supporting hardware, due to a (very slow) stop-gap emulation solution we had in place which is now gone. We hope you find the new design easier and more intuitive to understand and use.