Простой тест ниже говорит мне, что std::round
работает более чем в 3 раза быстрее на моем компьютере с SSE4, но примерно в 2 раза медленнее, когда SSE4 не включен.
#include <cmath>
#include <chrono>
#include <sstream>
#include <iostream>
#include <opencv2/core/fast_math.hpp>
auto currentTime() { return std::chrono::steady_clock::now(); }
template<typename T, typename P>
std::string toString(std::chrono::duration<T,P> dt)
{
std::ostringstream str;
using namespace std::chrono;
str << duration_cast<microseconds>(dt).count()*1e-3 << " ms";
return str.str();
}
int main()
{
volatile double x=34.234;
volatile double y;
constexpr auto MAX_ITER=100'000'000;
const auto t0=currentTime();
for(int i=0;i<MAX_ITER;++i)
y=std::ceil(x);
const auto t1=currentTime();
for(int i=0;i<MAX_ITER;++i)
y=cvCeil(x);
const auto t2=currentTime();
std::cout << "std::ceil: " << toString(t1-t0) << "\n"
"cvCeil : " << toString(t2-t1) << "\n";
}
Я тестирую с * Опция 1005 * на G CC 8.3.0, glib c -2.27, Ubuntu 18.04.1 x86_64 на Intel Core i7-3930K 3,2 ГГц.
Вывод при компиляции с -msse4
:
std::ceil: 39.357 ms
cvCeil : 143.224 ms
Вывод при компиляции без -msse4
:
std::ceil: 274.945 ms
cvCeil : 146.218 ms
Это легко понять: SSE4.1 вводит инструкцию ROUNDSD
, которая в основном и делает std::round
. Перед этим компилятор должен выполнить некоторые трюки сравнения / условного перемещения, а также убедиться, что они не переполнены. Таким образом, версия cvCeil
, жертвующая четкостью для value>INT_MAX
и для value<INT_MIN
, получает ускорение для значений, для которых она четко определена. Для других он имеет неопределенное поведение (или, по сути, просто дает неправильные результаты).