Большинство функций в concurrency::fast_math
не гарантируют возврат правильного значения. Некоторые из них (например, tanh) могут даже возвращать значения NaN. На моем HD 6870 быстрое число всех чисел больше 90 возвращает NaN.
Вот несколько приемов, которые помогут решить эту проблему.
Вы можете "привязать" аргумент Tanh к 10
float Tanh(float val) restrict(amp)
{
if (val > 10)
return 1;
else if (val < -10)
return-1;
return Concurrency::fast_math::tanh(val);
}
Это не приведет к потере точности, поскольку точность числа с плавающей запятой составляет всего 7 цифр, а разница между Tanh(10) и 1 составляет 4*10-9
Кроме того, вы можете реализовать свою собственную функцию Tanh, которая не будет иметь таких ограничений.
float Tanh(float val) restrict(amp)
{
float ax = fabs(val);
float x2 = val * val;
float z = val * (1.0f + ax + (1.05622909486427f + 0.215166815390934f * x2 * ax) * x2);
return (z / (1.02718982441289f + fabs(z)));
}
Нашел это приближение tanh где-то давно. Это довольно быстро и довольно точно.
Однако, если вам нужен очень точный tanh, вы можете заменить concurrency::fast_math
на concurrency::precise_math
. Но у этого варианта есть большой недостаток: precise_math
не может работать на многих графических процессорах (например, на моем 6870). Из здесь.
Эти функции, в том числе функции с одинарной точностью, требуют расширенной поддержки двойной точности в ускорителе. Вы можете использовать элемент данных accelerator::supports_double_precision, чтобы определить, можете ли вы запускать эти функции на конкретном ускорителе.
Кроме того, precise_math
может быть более чем в 10 раз медленнее, чем fast_math
, особенно на непрофессиональных видеокартах.
Если вы запускаете параллельный код не в блоке parallel_for_each
, похоже, что вы на самом деле не используете GPU. Таким образом, все, что вы оцениваете, оценивается на процессоре без ошибок, связанных с графическим процессором. На самом деле, если вы запустите этот код
float t = 0.65;
arr_view[1] = concurrency::fast_math::tanh(t);
parallel_for_each(e, [=](index<1> idx) restrict(amp)
{
arr_view[0] = concurrency::fast_math::tanh(t);
});
std::cout << arr[0] << "," << arr[1] << std::endl;
arr_view.synchronize();
std::cout << arr[0] << "," << arr[1] << std::endl;
std::cout << arr[0] - arr[1] << std::endl;//may return non-zero value, depending on gpu
вы можете увидеть результат первого tanh перед синхронизацией, в то время как для получения результата блока parallel_for_each это требуется. Кроме того, для меня он возвращает немного другие результаты, но это может зависеть от оборудования.
person
Drobor
schedule
16.01.2016
(e^x+e^-x)/(e^x-e^-x)
с большим x я мог получить плохие результаты. - person Yakk - Adam Nevraumont   schedule 11.01.2016