Я делал более быструю функцию mod(x,2) в C++ с помощью GCC (скомпилированную с использованием -O3 -ffast-math) и столкнулся с разницей в результатах между GCC и Octave:
float fast_fmod2(float x){ // over 50x faster than std::fmod(x, 2.0f)
x *= 0.5f;
return 2.0f * ( x - std::floor(x));
}
Результат (мод (ввод, 2.0f)):
Input : -7.8539786
std::fmod() : -1.853978633881
Octave mod(): 0.146021366119
fast_fmod2 : 0.146021366119
...
Input : 7.8539805
std::fmod() : 1.853980541229
Octave mod(): 1.853980541229
fast_fmod2 : 1.853980541229
Я также проверил пару других математических программ, и похоже, что по крайней мере Sollya и Wolfram | Alpha поддерживают результаты Octave, и ранее упомянутое задокументировало то же определение для функции, что и Octave.
ССАГПЗ определяет функцию мода как:
mod(A, P) = A - (int(A/P) * P)
Солья и Октава определяют как:
mod(a, b) = a - (b * floor(a / b))
Из-за того, что int(a/b) округляется иначе, чем floor(a/b), определение GCC дает другой ответ для отрицательных A.
>> int16(-2.19/2)
ans = -1
>> floor(-2.19/2)
ans = -2
Это ошибка в версии GCC или что-то еще за разницей?
Octave и C++ — разные языки, поэтому они могут иметь разные определения mod
. Нет причин полагать, что в наборе инструментов GCC C++ есть ошибка только потому, что он отличается от какого-то другого языка. Кроме того, какая конкретная функция вас беспокоит, и можете ли вы предоставить ссылку на нее или какой-нибудь пример кода, который ее использует (полная компилируемая программа, включая все необходимые заголовки)? Я не могу найти std::mod
в стандарте C++.
Это интересно std::fmod
gcc инфаркт гораздо медленнее, но для клана нет разницы.
@MarekR, float fast_mod_ab(float a, float b){return a - (b * floor(a / b));}
слишком быстрее, чем std::fmod(a,b) (при компиляции в gcc с использованием -O3 -ffast-math).
@JuhaP Я не проверял сборку, и этот тест не измеряет то, что он предполагает. Извини за это. Оптимизатор удалил вашу функцию. Вот фиксированная версия теперь ваша функция самая медленная (но близка к std::remainder
). Это доказывает, насколько сложными и коварными являются измерения производительности в C/C++. По какой-то странной причине первоначальная версия теста не компилируется на godbolt.
@MarekR, вы имеете в виду, что с -ffast-math делитель является постоянным, а функция встроена или что вы подразумеваете под «удалено»?
Я предполагаю, что вы имеете в виду std:fmod
вместо std::mod
(в официальном стандарте С++ нет std::mod
)
Причина этой разницы в том, что std::fmod
не делает того, что вы думаете.
std::fmod
вычисляет остаток, а нет — арифметический модуль.
Computes the floating-point remainder of the division operation
x
/y
Если вам нужен арифметический модуль, вам нужно вместо этого использовать std::remainder
:
Computes the IEEE remainder of the floating point division operation
x
/y
. The IEEE floating-point remainder of the division operationx/y
calculated by this function is exactly the valuex - n*y
, where the valuen
is the integral value nearest the exact valuex/y
. When|n-x/y| = ½
, the valuen
is chosen to be even.
Это даст ожидаемый результат в вашем примере:
std::cout << std::remainder(-7.8539786f, 2.0f) << std::endl; // 0.146021
Итак, чтобы ответить на ваш вопрос: это не ошибка, это предполагаемое поведение. Просто в C++ функции названы по-другому (хотя и с немного запутанной схемой именования).
Да, std::fmod под вопросом.
Таким образом, речь идет о другой цели, даже о похожем именовании функций. Я приму ваш ответ.
@JuhaP да, именно так :) std::fmod
делает эквивалент rem
в октаве, а std::reminder
будет эквивалентом mod
в октаве.
Сравнение производительности fast_fmod2
и std::fmod
и std::remainder
на gcc и лязг
@MarekR, в этом сравнении есть небольшая проблема - и gcc, и clang удалось полностью удалить вызов fast_fmod2
, так что тестовый пример для него - это просто noop (его время также равно панели noop в quickbench) божественная стрела
Вот более честное сравнение: gcc - лязг. Таким образом, в gcc он примерно равен std::remainder
, в clang он немного быстрее (в 7 раз), чем std::remainder
.
Я использую этот бенчмарк — godbolt.org/z/b7sdaonzj (читайте примечание от автора бенчмарка).
Опускает ли Quick-bench переключатель -ffast-math (там отображается только -O3) ... поскольку он явно влияет на производительность функции стандартной библиотеки.
@Turtlefight Мне было лень проверять сборку :(, извините за это, это лучше и показывает, что подход OP самый медленный. Странно, что моя первая версия теста не компилируется на godbolt, а документация бенчмарка google говорит, что должен.
@MarekR Я тоже столкнулся с этой проблемой, поэтому я заменил шаблонную тестовую функцию тремя отдельными в своих тестах. не уверен, почему он компилируется без проблем для quickbench, но не для godbolt. @JuhaP также имейте в виду, что std::remainder
делает несколько дополнительных вещей, которых нет у вашей fast_fmod2
функции — в основном специальная обработка и гарантии для 0, Infinity и NaN. Справка
@Turtlefight, вы имеете в виду, что с -ffast-math делитель является постоянным, а функция встроена или что вы подразумеваете под «удалено»?
@JuhaP инструкций не осталось - и gcc, и clang были достаточно умны, чтобы доказать, что результат fast_fmod2
не используется, и поэтому полностью удалили вызов. По сути, бенчмарк тестировал производительность пустого цикла (for (auto _ : state) { /* NOTHING */ }
) — что, конечно, намного быстрее, чем стандартные функции :) — вы можете увидеть это на разборке (божественная стрела): обратите внимание, что MessureModFast
не содержит НИКАКИХ операций с плавающей запятой. - он буквально просто вызывает StartKeepRunning()
, за которым следует FinishKeepRunning()
.
@Turtlefight, вот еще одна проверенная функция (в комментариях под вопросом) - quick-bench.com/q/NB9AUf4unxMIu55qZeYbACNjsU0 ... она страдает так же? quick-bench.com/q/r-oeO3PcShdbBHS2RUI8dgVpXRw
У первого связанный бенчмарк именно такая проблема, со вторым все в порядке. Вот правильные: Без фастмата: gcc - лязг / с фастматом: gcc - лязг
Result:
что представляет собой этот «результат»?GCC defines mod function as:
Sollya and Octave defines as:
Не могли бы вы дать ссылки на это?