Вы не указали формат, IEEE 754 - популярный, но не единственный зверь.
Как правило, не используйте равенство с плавающей запятой, потому что двоичные форматы с плавающей запятой не совпадают с бесконечно точными числами , Предположим, что в случае, когда у вас есть две операции на одной стороне и одна операция на другой, каждая операция может обрезать, поэтому следует ожидать потери точности на операцию, две операции могут потерять / изменить больше, чем одна операция. Округление, если часть формата и реализации может помочь устранить некоторые из этих потерь в определенных c случаях, но не является полным исправлением, а иногда и вредит.
Так что, как правило, не предполагайте, что это будет работать, но в этом конкретном случае c давайте начнем с формата IEEE в формате 1.fraction, нам не нужно очень много битов мантиссы, чтобы увидеть, как это работает.
1.ab c (a, b, c - единичные биты)
Как указывает Eri c, начать с 2 * a
1abc
+ 1abc
========
1xxx0
независимо от того, что c равно 1 или 0, lsbit равен 0. Фиксированная точка 1abc + 1ab c = 2 * 1ab c, пока мы не переполняем показатель степени:
1abc
+ 1abc
========
1abc0
вы можете пройтись по комбинациям и количеству битов мантиссы, если хотите.
добавление + a + a подходит к этой точке
1abc0
+ 1abc
=======
для случая умножения
1abc
1100
======
0000
0000
1abc
+1abc
===========
, который приходит к этой точке
1abc
+ 1abc0
========
, поэтому они заканчиваются в том же месте, где они равны, да?
округление здесь не является фактором, так как результат младших битов в тех же значениях через любой путь ... да?
Отрицательные числа в IEEE, например, также используют положительный формат 1.f, а знак обрабатывается отдельно. В этом случае путь умножения p * p положителен, p * n отрицателен, поэтому оба пути работают, и вы сохраняете знак (здесь 3 всегда положительно). Для пути сложения результаты либо становятся более отрицательными, либо более положительными, они сохраняют свой знак.
Первое добавление может привести к переполнению показателя, что может привести к NAN, например, в IEEE. Второе дополнение, та же история. Умножение также может привести к созданию NAN, и лучше всего предположить, что по двум путям два результата NAN не являются бинарными, поэтому сравнение не будет работать. Если я правильно помню, один будет сигнализировать, а другой тихо, да?
Другие форматы. Все еще работать над этим должно быть так же легко продемонстрировать, как и в формате (форматах) 1.f. положительная 01. фракция, отрицательная 10.фракция, например.
Ключевым моментом здесь является то, что реализация умножения должна быть такой, чтобы она поддерживала 2 * n необходимого количества бит (для фиксированной точки n бит * n бит = 2 * n бит будет охватывать все случаи 32-битное число умножение на 32-битное число требует 64 бита для его хранения.) Форматы, стремящиеся к принудительной установке единицы в верхнюю часть значения, означают, что вы умножаете 1xxxxx ... * 1xxxxx .... из начальной школы
a.bcd
e.fgh
======
мы сделали бы математику как фиксированную точку abcd * efgh, а затем автоматически переместили бы десятичную точку 6 в результате. Затем двоичная плавающая точка должна будет нормализовать и переместить наиболее значимую 1 или 0 в зависимости от формата чуть левее двоичной точки, корректируя показатель степени, аналогично тому, как мы будем использовать степени 10 в нотации scientifi c для дальнейшего скорректировать результат. В идеале logi c будет использовать достаточно битов, чтобы математика с фиксированной точкой работала правильно, затем нормализовала это, затем обрезала и, возможно, округлила.
Так что в конце дня вы увидите что-то вроде
abcd
abcd
abcd
abcd
+ ...
И для случая 3 * a против a + a +
лучший случай, оставьте c в качестве залипшего бита
1abc0
+ 1abc
=======
xxxxx
худший случай обрезать его
1abc0
+ 1abc
=======
xxxx
для умножения
лучший случай
0000
0000
1abc
+1abc
===========
xxxxxxx`
наихудшее ограничение
0
00
1ab
+1abc
===========
xxxx`
в обоих случаях мы сохраняем / теряем один бит, который будет идти вниз по обоим путям, даст одинаковый результат, если и сложение, и умножение сделают одинаковые оптимизации. Это только тот случай, когда 3 * a против a + a + a, придется пройти через возможности для любого другого уравнения.
В итоге предположим, что уравнения, которые в точности равны с использованием математики с бесконечной точностью, не равны с использованием двоичной математики с плавающей точкой. Но есть такие случаи, которые могут быть показаны равными (в зависимости от реализации), я бы назвал эти исключения не правилом.
Предположим, что в одном случае вы будете счастливы, если это не так, даже лучше, если вы сможете доказать, что это не так (для вашего конкретного c целевого оборудования или формата в целом), а затем запомнить и задокументировать ограничения этого доказательства. Если вы забудете доказательство или не документируете правила, тогда кто-то придет позже и испортит, и математика может / будет неправильной, и программное обеспечение не будет работать. Поэтому будьте очень, очень осторожны, делая математические оптимизации, не продумывая их В частности, если вы ожидаете равного сравнения для работы.
Я работал над системами управления, где мы должны были изменить lsbit мантиссы, чтобы математика работала, вычисление входной двери констант не давало правильного набора значений. Любая дальнейшая корректировка параметров этих систем управления потребует проверки значений и, возможно, настройки одного или нескольких из них, чтобы математика работала.