Benchmarking math.h квадратный корень и Quake квадратный корень - PullRequest
3 голосов
/ 25 сентября 2010

Хорошо, я был на доске и удивлялся, насколько быстрый квадратный корень из math.h по сравнению с тем, в котором есть магическое число (сделанное Quake известным, но SGI).

Но это оказалось в мире боли для меня.

Сначала я попробовал это на Mac, где math.h каждый раз выигрывал раздачи, а затем на Windows, где всегда выигрывал магический номер, но я думаю, что это все из-за моей нубизм.

  1. Компиляция на Mac с «g ++ -o sq_root sq_root_test.cpp» при запуске программы занимает около 15 секунд. Но компиляция в VS2005 при выпуске занимает доли секунды. (на самом деле мне пришлось скомпилировать в отладке только для того, чтобы показать некоторые цифры)

  2. Тест моего бедного человека? это действительно глупо? потому что я получаю 0,01 для математики и 0 для магического числа. (не может быть так быстро, не так ли?)

Не знаю, имеет ли это значение, но Mac - это Intel, а ПК - AMD. Использует ли Mac оборудование для math.h sqroot?

Я получил алгоритм быстрого квадратного корня из http://en.wikipedia.org/wiki/Fast_inverse_square_root

//sq_root_test.cpp

#include <iostream>
#include <math.h>
#include <ctime>


float invSqrt(float x)
{
    union {
        float f;
        int i;
    } tmp;
    tmp.f = x;
    tmp.i = 0x5f3759df - (tmp.i >> 1);
    float y = tmp.f;
    return y * (1.5f - 0.5f * x * y * y);
}

int main() {
    std::clock_t start;// = std::clock();
    std::clock_t end;
    float rootMe;

    int iterations = 999999999;

    // ---

    rootMe = 2.0f;
    start = std::clock();

    std::cout << "Math.h SqRoot: ";

    for (int m = 0; m < iterations; m++) {
        (float)(1.0/sqrt(rootMe));
        rootMe++;
    }

    end = std::clock();

    std::cout << (difftime(end, start)) << std::endl;

    // ---

    std::cout << "Quake SqRoot: ";

    rootMe = 2.0f;
    start = std::clock();

    for (int q = 0; q < iterations; q++) {
        invSqrt(rootMe);
        rootMe++;
    }

    end = std::clock();

    std::cout << (difftime(end, start)) << std::endl;   
}

1 Ответ

5 голосов
/ 25 сентября 2010

Есть несколько проблем с вашими тестами.Во-первых, ваш тест включает в себя потенциально дорогой бросок от int до float.Если вы хотите знать, сколько стоит квадратный корень, вам следует тестировать квадратные корни, а не преобразования типов данных.

Во-вторых, весь ваш тест может быть (и равен ) оптимизирован компилятором, посколькуу него нет видимых побочных эффектов.Вы не используете возвращаемое значение (или храните его в энергозависимой ячейке памяти), поэтому компилятор видит, что может пропустить все это .

Подсказка в том, что вы имелиотключить оптимизации.Это означает, что ваш код тестирования не работает.Никогда никогда не отключайте оптимизацию при тестировании.Вы хотите знать, какая версия работает быстрее всего, поэтому вам следует протестировать ее в условиях, при которых она будет фактически использоваться.Если бы вы использовали квадратные корни в чувствительном к производительности коде, вы бы включили оптимизацию, поэтому то, как она ведет себя без оптимизаций, совершенно не имеет значения.

Кроме того, вы не сравниваете затратывычисления квадратного корня, но обратного квадратного корня .Если вы хотите узнать, какой способ вычисления квадратного корня является самым быстрым, вам нужно переместить деление 1.0/... до версии Quake.(А поскольку деление - довольно дорогая операция, это может сильно повлиять на ваши результаты)

Наконец, стоит отметить, что небольшая хитрость Carmacks была разработана для быстрой работы на 12-летних компьютерах.Как только вы исправите свой эталонный тест, вы, вероятно, обнаружите, что он больше не является оптимизацией, потому что современные процессоры намного быстрее вычисляют «настоящие» квадратные корни.

...