Порядок коммутативных математических операций

У меня любопытный вопрос (задаю его себе, читая грубый фрагмент кода). Посмотрим на выражение:

double a =  c*d*e*2/3*f;

где c, d, e, f - инициализированные переменные типа double. Гарантирует ли стандарт, что он будет рассматриваться как c*d*e*2 (двойной результат), затем разделен на 3 и умножен на f (или подобное поведение). Очевидно, что 2/3, равные 0, нежелательны.

В каком параграфе стандарта это определяется?

@jww сузил вопрос, целью было фактическое положение в стандарте, которое будет применяться здесь

Swift - Friday Pie 27.03.2018 09:45

Как ранее отмечалось YSC, математическая терминология здесь используется очень слабо или даже неправильно. Коммутативность означает переупорядочивание операнды, а не операций, например a*b против b*a. Вы имеете в виду ассоциативность, например (a*b)*c против a*(b*c). Математически умножение является ассоциативным и коммутативным, но умножение FP не ассоциативно из-за потенциально различного округления промежуточных результатов. Однако деление не является ни ассоциативным, ни коммутативным. a*b/c - это особый случай, когда деление является математическим. ассоциативный с умножением.

Arne Vogel 27.03.2018 10:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
317
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

На основе стандарт

[intro.abstract] - Примечание 7 (ненормативный):

Operators can be regrouped according to the usual mathematical rules only where the operators really are associative or commutative.

Математическое правило для MDAS - слева направо (с учетом ассоциативности и приоритета операторов). Итак, это оценивается следующим образом:

(((((c * d) * e) * 2) / 3) * f)

Раздел, на который вы ссылаетесь, посвящен объектам функций. Этой цитаты нет и рядом.

StoryTeller - Unslander Monica 27.03.2018 09:35

Я знал, что это должно было быть там! ваша ссылка указывает не на тот абзац, это в п.4.1.1. Но зная формулировку, нашел.

Swift - Friday Pie 27.03.2018 09:37

Теперь это раздел 1.7, которого просто не существует. Просто поместите в свой ответ раздел название, то есть [chpater.subchapter.etc] с номером абзаца. Это не слишком сильно повлияет на изменения и подтвердит ваш ответ в будущем. К тому же оно информативнее, чем одеяло «эталон».

StoryTeller - Unslander Monica 27.03.2018 09:39

Это [intro.abstract]/7, но это ненормативное примечание (и вы его упоминаете в должен). Должна существовать лучшая цитата.

YSC 27.03.2018 09:45

@YSC Полагаю, я должен быть параноиком и все равно рекомендовать использовать (2.0/3.0)*c*d*e*f

Swift - Friday Pie 27.03.2018 09:54

@Swift нет, вам не следует, но вы также должны писать код с первой целью, чтобы максимизировать читаемость. Так что да, напишите что-нибудь вроде double a = ((c*d*e*2)/3)*f;, чтобы даже новичок мог понять, что происходит. Однако будьте осторожны, умножение с плавающей запятой не ассоциативно ((a*b)*c != a*(b*c)).

YSC 27.03.2018 09:57

@YSC - это не вопрос удобочитаемости, это вопрос правильного выполнения на множестве довольно экзотических платформ с неосновными компиляторами (например, это должен быть C++ 1x, но у него нет constexpr), с жестким ограничением, что это невозможно для тестирования на целевых платформах (их еще нет и с ними невозможно связаться). другие значения в настоящее время не упорядочены ни в каком отношении к ожидаемым значениям, в то время как порядок величины фактически был известен (это часть матрицы фильтра шума)

Swift - Friday Pie 27.03.2018 10:02

@Swift - это всегда читабельность. Если вы пренебрегаете этим, вы получите баги, баги, которые трудно исправить.

YSC 27.03.2018 10:05

@YSC, тогда вы будете в ужасе от большей части кода, это приложение реального времени без каких-либо выделений и много чего сделано в глобальных переменных. И единственный способ увидеть, как происходит ошибка, - либо смоделировать ее теоретически (без автоматизированных моделей оборудования), либо запустить и увидеть, как взрываются многомиллионные объекты [X)]. код был как раз результатом расширения матрицы до множества линейных выражений. Я уже обнаружил несколько несоответствий и ошибок сравнений со знаком / без знака при преобразовании из геоцентрического в NED.

Swift - Friday Pie 27.03.2018 10:08

@Swift Я видел такой код. Это должно быть не потому, что оно существует.

YSC 27.03.2018 10:09

@YSC иначе писать запрещено. по сути, "новый" оператор или все, что его использует, запрещено. Это приложения реального времени ..

Swift - Friday Pie 27.03.2018 10:11

@Swift Откуда взялся этот new? Я говорил о удобочитаемости, а не о динамическом размещении. Я работал над встроенными системами, и это не потому, что у вас есть особенности, которые не позволяют писать легко читаемый код.

YSC 27.03.2018 10:14

@YSC в отношении читаемости материала, поскольку сопоставление его с канонической формой 2.0 / 3.0 по отдельности будет более читаемым, потому что 2/3 присутствует в формуле матрицы фильтра в начале. aбc * d впереди появился по причине, известной только автору (которого здесь больше нет). кроме того, эта функция получила только десять страниц документации

Swift - Friday Pie 27.03.2018 10:17

Одним словом - да.

Искомое свойство называется ассоциативностью операторов. Он определяет, как операторы с одинаковым приоритетом (например, * и /) группируются и упорядочиваются при отсутствии скобок.

В вашем случае и *, и / имеют одинаковый приоритет и оба являются левоассоциативными, то есть они оцениваются слева направо. Это означает, что c будет умножен на d, затем результат на e, затем результат на 2 (что будет сделано с помощью арифметики с плавающей запятой, поскольку вы умножаете double на литерал int), а затем разделите на 3 (опять же, используя арифметику с плавающей запятой) и, наконец, умноженное на f.

Дополнительную информацию см. В эта страница cppreference.

И *, и / имеют одинаковый приоритет и ассоциативны слева направо, это означает, что

a*b*c*d

разбирается как

((a*b)*c)*d

и то же самое верно, если вы замените любой из * на /.

Источник: http://en.cppreference.com/w/cpp/language/operator_precedence

Операции с плавающей запятой @Swift не коммутативны из-за ошибок округления промежуточных результатов. Если вы используете gcc, вы можете использовать --ffast-math, чтобы игнорировать это.

mch 27.03.2018 09:51

@mch Я думаю, вы имели в виду ассоциативный;) Конечно a*b == b*a, но (a*b)*c != a*(b*c).

YSC 27.03.2018 09:59

@mch стою поправлюсь! И нет, ни gcc, ни даже двоичный код IEEE-754. десятичная версия, 192 бит.

Swift - Friday Pie 27.03.2018 10:21

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