По-видимому, MSVС++ 2017 toolset v141 (конфигурация релиза x64) не использует инструкцию сборки FYL2X
x86_64 с помощью встроенного C/С++, но вместо того, чтобы использовать С++ log()
или log2()
, возникает реальный вызов которая, по-видимому, реализует приближение логарифма (без использования FYL2X
). Производительность, которую я измерил, также странная: log()
(натуральный логарифм) в 1.7667 раз быстрее, чем log2()
(логарифм базы 2), хотя логарифм базы 2 должен быть проще для процессора, поскольку он хранит экспоненту в двоичном формате (и мантисса тоже), и, похоже, почему команда CPU FYL2X
вычисляет логарифм базы 2 (умноженный на параметр).
Вот код, используемый для измерений:
#include <chrono>
#include <cmath>
#include <cstdio>
const int64_t cnLogs = 100 * 1000 * 1000;
void BenchmarkLog2() {
double sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for(int64_t i=1; i<=cnLogs; i++) {
sum += std::log2(double(i));
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
double nSec = 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
printf("Log2: %.3lf Ops/sec calculated %.3lf\n", cnLogs / nSec, sum);
}
void BenchmarkLn() {
double sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int64_t i = 1; i <= cnLogs; i++) {
sum += std::log(double(i));
}
auto elapsed = std::chrono::high_resolution_clock::now() - start;
double nSec = 1e-6 * std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
printf("Ln: %.3lf Ops/sec calculated %.3lf\n", cnLogs / nSec, sum);
}
int main() {
BenchmarkLog2();
BenchmarkLn();
return 0;
}
Выход для Ryzen 1800X:
Log2: 95152910.728 Ops/sec calculated 2513272986.435
Ln: 168109607.464 Ops/sec calculated 1742068084.525
Чтобы разъяснить эти явления (без использования FYL2X
и странной разницы в производительности), я также хотел бы проверить производительность FYL2X
, а если быстрее, используйте его вместо функций <cmath>
. MSVС++ не разрешает встроенную сборку на x64, поэтому необходима функция файла сборки, которая использует FYL2X
.
Не могли бы вы ответить на ассемблерный код для такой функции, которая использует FYL2X
или лучшую инструкцию, выполняющую логарифм (без необходимости конкретной базы), если есть какие-либо новые процессоры x86_64?