Определение модуля GCC ()

Я делал более быструю функцию 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 или что-то еще за разницей?

Result: что представляет собой этот «результат»? GCC defines mod function as:Sollya and Octave defines as: Не могли бы вы дать ссылки на это?
KamilCuk 05.04.2022 18:47

Octave и C++ — разные языки, поэтому они могут иметь разные определения mod. Нет причин полагать, что в наборе инструментов GCC C++ есть ошибка только потому, что он отличается от какого-то другого языка. Кроме того, какая конкретная функция вас беспокоит, и можете ли вы предоставить ссылку на нее или какой-нибудь пример кода, который ее использует (полная компилируемая программа, включая все необходимые заголовки)? Я не могу найти std::mod в стандарте C++.

David Grayson 05.04.2022 18:52

Это интересно std::fmodgcc инфаркт гораздо медленнее, но для клана нет разницы.

Marek R 05.04.2022 19:16

@MarekR, float fast_mod_ab(float a, float b){return a - (b * floor(a / b));} слишком быстрее, чем std::fmod(a,b) (при компиляции в gcc с использованием -O3 -ffast-math).

Juha P 05.04.2022 20:10

@JuhaP Я не проверял сборку, и этот тест не измеряет то, что он предполагает. Извини за это. Оптимизатор удалил вашу функцию. Вот фиксированная версия теперь ваша функция самая медленная (но близка к std::remainder). Это доказывает, насколько сложными и коварными являются измерения производительности в C/C++. По какой-то странной причине первоначальная версия теста не компилируется на godbolt.

Marek R 06.04.2022 11:00

@MarekR, вы имеете в виду, что с -ffast-math делитель является постоянным, а функция встроена или что вы подразумеваете под «удалено»?

Juha P 06.04.2022 12:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
107
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я предполагаю, что вы имеете в виду 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 operation x/y calculated by this function is exactly the value x - n*y, where the value n is the integral value nearest the exact value x/y. When |n-x/y| = ½, the value n is chosen to be even.

Это даст ожидаемый результат в вашем примере:

std::cout << std::remainder(-7.8539786f, 2.0f) << std::endl; // 0.146021

пример божественной стрелы


Итак, чтобы ответить на ваш вопрос: это не ошибка, это предполагаемое поведение. Просто в C++ функции названы по-другому (хотя и с немного запутанной схемой именования).

  • Октава mod == C++ std::reminder
  • Октава rem == C++ std::fmod

Да, std::fmod под вопросом.

Juha P 05.04.2022 19:05

Таким образом, речь идет о другой цели, даже о похожем именовании функций. Я приму ваш ответ.

Juha P 05.04.2022 19:16

@JuhaP да, именно так :) std::fmod делает эквивалент rem в октаве, а std::reminder будет эквивалентом mod в октаве.

Turtlefight 05.04.2022 19:22

Сравнение производительности fast_fmod2 и std::fmod и std::remainder на gcc и лязг

Marek R 05.04.2022 19:30

@MarekR, в этом сравнении есть небольшая проблема - и gcc, и clang удалось полностью удалить вызов fast_fmod2, так что тестовый пример для него - это просто noop (его время также равно панели noop в quickbench) божественная стрела

Turtlefight 05.04.2022 19:55

Вот более честное сравнение: gcc - лязг. Таким образом, в gcc он примерно равен std::remainder, в clang он немного быстрее (в 7 раз), чем std::remainder.

Turtlefight 05.04.2022 20:13

Я использую этот бенчмарк — godbolt.org/z/b7sdaonzj (читайте примечание от автора бенчмарка).

Juha P 05.04.2022 20:58

Опускает ли Quick-bench переключатель -ffast-math (там отображается только -O3) ... поскольку он явно влияет на производительность функции стандартной библиотеки.

Juha P 05.04.2022 22:55

С -ffast-math: gcc - лязг .

Turtlefight 06.04.2022 10:43

@Turtlefight Мне было лень проверять сборку :(, извините за это, это лучше и показывает, что подход OP самый медленный. Странно, что моя первая версия теста не компилируется на godbolt, а документация бенчмарка google говорит, что должен.

Marek R 06.04.2022 11:04

@MarekR Я тоже столкнулся с этой проблемой, поэтому я заменил шаблонную тестовую функцию тремя отдельными в своих тестах. не уверен, почему он компилируется без проблем для quickbench, но не для godbolt. @JuhaP также имейте в виду, что std::remainder делает несколько дополнительных вещей, которых нет у вашей fast_fmod2 функции — в основном специальная обработка и гарантии для 0, Infinity и NaN. Справка

Turtlefight 06.04.2022 11:17

@Turtlefight, вы имеете в виду, что с -ffast-math делитель является постоянным, а функция встроена или что вы подразумеваете под «удалено»?

Juha P 06.04.2022 12:56

@JuhaP инструкций не осталось - и gcc, и clang были достаточно умны, чтобы доказать, что результат fast_fmod2 не используется, и поэтому полностью удалили вызов. По сути, бенчмарк тестировал производительность пустого цикла (for (auto _ : state) { /* NOTHING */ }) — что, конечно, намного быстрее, чем стандартные функции :) — вы можете увидеть это на разборке (божественная стрела): обратите внимание, что MessureModFast не содержит НИКАКИХ операций с плавающей запятой. - он буквально просто вызывает StartKeepRunning(), за которым следует FinishKeepRunning().

Turtlefight 06.04.2022 13:33

@Turtlefight, вот еще одна проверенная функция (в комментариях под вопросом) - quick-bench.com/q/NB9AUf4unxMIu55qZeYbACNjsU0 ... она страдает так же? quick-bench.com/q/r-oeO3PcShdbBHS2RUI8dgVpXRw

Juha P 06.04.2022 13:49

У первого связанный бенчмарк именно такая проблема, со вторым все в порядке. Вот правильные: Без фастмата: gcc - лязг / с фастматом: gcc - лязг

Turtlefight 06.04.2022 16:11

Другие вопросы по теме