int log2_(ulong n)
{
if (n==0) return -1;
#define M(n, i, base, S) ( n >= (ulong(1)<<(i)) ? S(n, i+base/2) : S(n, i-(base+1)/2) )
#define S_0(n, i) i
#define S_1(n, i) M(n, i, 1, S_0)
#define S_2(n, i) M(n, i, 2, S_1)
#define S_4(n, i) M(n, i, 4, S_2)
#define S_8(n, i) M(n, i, 8, S_4)
#define S_16(n, i) M(n, i, 16, S_8)
#define S(n) M(n, 32, 32, S_16)
return S(n);
}
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
Деление на два замедляет ? Попробовать заменить сдвигом ? Подозрение, что вычисляемые константы - надо вычислять сразу (в этом случае - и сдвиг в дефайне - также надо заменить константой).
Кроме того - "вопросик" - как я знаю, это довольно спорный оператор, когда-то, двадцать лет назад проверяли на С++, иногда "вопросик" генерирует более длинный код, чем обычный оператор if. Может и здесь так ?
И, я бы сделал код возврата uint - вдруг там какие-то проверки идут при преобразовании знаковых и беззнаковых величин ?
Пока нет возможности поэксперементировать самому - процессор загружен под завязку... Даже текст набирается "с пробуксовками"...
Деление на два замедляет ? Попробовать заменить сдвигом ? Подозрение, что вычисляемые константы - надо вычислять сразу (в этом случае - и сдвиг в дефайне - также надо заменить константой).
Кроме того - "вопросик" - как я знаю, это довольно спорный оператор ...
Замена деления сдвигом не влияет. Я подозреваю, что получающееся выражение слишком длинное, поэтому компилятор его не оптимизировал до конца.
Однако это я проводил тесты при Optimize=0. А при включении оптимизации всё встало на свои места: второй вариант быстрее примерно в полтора раза. Бинго!
Если же оптимизация отключена, то второй вариант чуть медленнее при небольших значениях, но чуть быстрее при больших. Короче говоря, второй вариант определённо лучше.
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
Все верно - Ваш вариант самый быстрый.
Просто тест холостой. Очень часто при тесте на производительность забывают один важный момент: если вычисляемое значение нигде не используется, то компилятор просто напросто не производит вычисления.
Ведь это логично - какой смысл? Это как в квантовой суперпозиции. Зачен существовать луне, если на нее никто не смотрит. "Неужели Луна существует только потому, что на нее смотрит мышь?" (Альберт Эйнштейн). :))
Поэтому такой вариант теста с вычислением контрольной суммы и печати её будет правильнее:
Просто тест холостой. Очень часто при тесте на производительность забывают один важный момент: если вычисляемое значение нигде не используется, то компилятор просто напросто не производит вычисления.
Ведь это логично - какой смысл? Это как в квантовой суперпозиции. Зачен существовать луне, если на нее никто не смотрит. "Неужели Луна существует только потому, что на нее смотрит мышь?" (Альберт Эйнштейн). :))
Поэтому такой вариант теста с вычислением контрольной суммы и печати её будет правильнее:
Ваш код запутанный. Переменные, используемые в дефайне, расположены в другом конце кода программы - неудобно разбираться в таком хаосе. Но суть не в этом, а в том, что результаты ваших тестов нельзя считать достоверными, т.к. компилятор заранее знает алгоритм значений, передаваемых в функцию. Поэтому он оптимизирует ваши тесты. Нужно рассчитывать на случайных числах.
Кстати, зачем у вас srand в коде? Я, увидев его, сначала и подумал, что у вас используется рандом, но по факту - нет.
Ваш код запутанный. Переменные, используемые в дефайне, расположены в другом конце кода программы - неудобно разбираться в таком хаосе. Но суть не в этом, а в том, что результаты ваших тестов нельзя считать достоверными, т.к. компилятор заранее знает алгоритм значений, передаваемых в функцию. Поэтому он оптимизирует ваши тесты. Нужно рассчитывать на случайных числах.
Кстати, зачем у вас srand в коде? Я, увидев его, сначала и подумал, что у вас используется рандом, но по факту - нет.
Вот мой код:
код не мой. Я лишь его подправил и выкинул rand, чтобы проверить одинаковость контрольных сумм и убрать из цикла относительно затратные функции rand, а srand просто забыл выкинуть.
Возвращаю rand. Вы правы - компилятор действительно оптимизирует цикл суммы логарифмов из последовательных значений. Хотя я удивлен. Не понимаю, как он это делает. Возможно, что-то мы не учитываем.
Интересно, каким образом у вас получилась везде одинаковая контрольная сумма, если значения рандомные.
srand(45) для всех функций
просто сначала тоже так сделал, но получил разные контрольные суммы, т.к. не учел что rand()*rand() может быть 0, а это ломает контрольную сумму. Сейчас добавил единицу, чтобы уйти от нуля.
просто сначала тоже так сделал, но получил разные контрольные суммы, т.к. не учел что rand()*rand() может быть 0, а это ломает контрольную сумму. Сейчас добавил единицу, чтобы уйти от нуля.
А зачем вам одинаковая контрольная сумма, если речь идёт конкретно о замере скорости? Суть суммы в этом случае - просто не дать компилятору вырезать код, вот и всё. А делая srand(45), вы опять-таки позволяете оптимизировать тест.
Кстати, по поводу нуля. В FastLog2 нет проверки на нуль, это соответственно и фору ему даёт. Но он всё-равно в полтора-два раза медленнее, чем log2, если тестировать корректно )
Alexey Navoykov: А зачем вам одинаковая контрольная сумма, если речь идёт конкретно о замере скорости? Суть суммы в этом случае - просто не дать компилятору вырезать код, вот и всё. А делая srand(45), вы опять-таки позволяете оптимизировать тест.
Здесь Вы переоцениваете возможности компилятора. Уберите srand(45) - контрольные суммы станут разными, но результат скорости сохраниться.
Тем более я руководствовался тем, чтобы вычисления были одинаковыми для чистоты эксперимента, т.к. не вдавался в подробности всех функций. Иногда значение параметра функции могут влиять на время её выполнения.
Тем более заодно проверить правильность алгоритмов.
Вот родился у меня такой вариант:
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
Вот родился у меня такой вариант:
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
Деление на два замедляет ? Попробовать заменить сдвигом ? Подозрение, что вычисляемые константы - надо вычислять сразу (в этом случае - и сдвиг в дефайне - также надо заменить константой).
Кроме того - "вопросик" - как я знаю, это довольно спорный оператор, когда-то, двадцать лет назад проверяли на С++, иногда "вопросик" генерирует более длинный код, чем обычный оператор if. Может и здесь так ?
И, я бы сделал код возврата uint - вдруг там какие-то проверки идут при преобразовании знаковых и беззнаковых величин ?
Пока нет возможности поэксперементировать самому - процессор загружен под завязку... Даже текст набирается "с пробуксовками"...
Деление на два замедляет ? Попробовать заменить сдвигом ? Подозрение, что вычисляемые константы - надо вычислять сразу (в этом случае - и сдвиг в дефайне - также надо заменить константой).
Кроме того - "вопросик" - как я знаю, это довольно спорный оператор ...
Замена деления сдвигом не влияет. Я подозреваю, что получающееся выражение слишком длинное, поэтому компилятор его не оптимизировал до конца.
Однако это я проводил тесты при Optimize=0. А при включении оптимизации всё встало на свои места: второй вариант быстрее примерно в полтора раза. Бинго!
Если же оптимизация отключена, то второй вариант чуть медленнее при небольших значениях, но чуть быстрее при больших. Короче говоря, второй вариант определённо лучше.
Вот родился у меня такой вариант:
По идее, это самый быстрый из всех возможных. Все вычисления производятся с константами, поэтому рассчитываются при компиляции. Итого, всё сводится лишь к 6 последовательным сравнениям, и ничего более. Однако, этот вариант у меня работает медленнее, чем предыдущий. Не могу понять, в чём причина.
Все верно - Ваш вариант самый быстрый.
Просто тест холостой. Очень часто при тесте на производительность забывают один важный момент: если вычисляемое значение нигде не используется, то компилятор просто напросто не производит вычисления.
Ведь это логично - какой смысл? Это как в квантовой суперпозиции. Зачен существовать луне, если на нее никто не смотрит. "Неужели Луна существует только потому, что на нее смотрит мышь?" (Альберт Эйнштейн). :))
Поэтому такой вариант теста с вычислением контрольной суммы и печати её будет правильнее:
Результат:
А второе место все же _FastLog2, а не log2 :))Просто тест холостой. Очень часто при тесте на производительность забывают один важный момент: если вычисляемое значение нигде не используется, то компилятор просто напросто не производит вычисления.
Ведь это логично - какой смысл? Это как в квантовой суперпозиции. Зачен существовать луне, если на нее никто не смотрит. "Неужели Луна существует только потому, что на нее смотрит мышь?" (Альберт Эйнштейн). :))
Поэтому такой вариант теста с вычислением контрольной суммы и печати её будет правильнее:
Ваш код запутанный. Переменные, используемые в дефайне, расположены в другом конце кода программы - неудобно разбираться в таком хаосе. Но суть не в этом, а в том, что результаты ваших тестов нельзя считать достоверными, т.к. компилятор заранее знает алгоритм значений, передаваемых в функцию. Поэтому он оптимизирует ваши тесты. Нужно рассчитывать на случайных числах.
Кстати, зачем у вас srand в коде? Я, увидев его, сначала и подумал, что у вас используется рандом, но по факту - нет.
Вот мой код:
Ваш код запутанный. Переменные, используемые в дефайне, расположены в другом конце кода программы - неудобно разбираться в таком хаосе. Но суть не в этом, а в том, что результаты ваших тестов нельзя считать достоверными, т.к. компилятор заранее знает алгоритм значений, передаваемых в функцию. Поэтому он оптимизирует ваши тесты. Нужно рассчитывать на случайных числах.
Кстати, зачем у вас srand в коде? Я, увидев его, сначала и подумал, что у вас используется рандом, но по факту - нет.
Вот мой код:
код не мой. Я лишь его подправил и выкинул rand, чтобы проверить одинаковость контрольных сумм и убрать из цикла относительно затратные функции rand, а srand просто забыл выкинуть.
Возвращаю rand. Вы правы - компилятор действительно оптимизирует цикл суммы логарифмов из последовательных значений. Хотя я удивлен. Не понимаю, как он это делает. Возможно, что-то мы не учитываем.
Результат:
Текущий победитель _FastLog2
Результат:
Текущий победитель _FastLog2
Интересно, каким образом у вас получилась везде одинаковая контрольная сумма, если значения рандомные.
Интересно, каким образом у вас получилась везде одинаковая контрольная сумма, если значения рандомные.
srand(45) для всех функций
просто сначала тоже так сделал, но получил разные контрольные суммы, т.к. не учел что rand()*rand() может быть 0, а это ломает контрольную сумму. Сейчас добавил единицу, чтобы уйти от нуля.
srand(45) для всех функций
просто сначала тоже так сделал, но получил разные контрольные суммы, т.к. не учел что rand()*rand() может быть 0, а это ломает контрольную сумму. Сейчас добавил единицу, чтобы уйти от нуля.
А зачем вам одинаковая контрольная сумма, если речь идёт конкретно о замере скорости? Суть суммы в этом случае - просто не дать компилятору вырезать код, вот и всё. А делая srand(45), вы опять-таки позволяете оптимизировать тест.
Кстати, по поводу нуля. В FastLog2 нет проверки на нуль, это соответственно и фору ему даёт. Но он всё-равно в полтора-два раза медленнее, чем log2, если тестировать корректно )
А зачем вам одинаковая контрольная сумма, если речь идёт конкретно о замере скорости? Суть суммы в этом случае - просто не дать компилятору вырезать код, вот и всё. А делая srand(45), вы опять-таки позволяете оптимизировать тест.
Здесь Вы переоцениваете возможности компилятора. Уберите srand(45) - контрольные суммы станут разными, но результат скорости сохраниться.
Тем более я руководствовался тем, чтобы вычисления были одинаковыми для чистоты эксперимента, т.к. не вдавался в подробности всех функций. Иногда значение параметра функции могут влиять на время её выполнения.
Тем более заодно проверить правильность алгоритмов.