Причина своеобразного порядка деления и умножения в C ++
Вопрос
Я нахожусь в процессе переноса некоторого кода c ++ на java, и я продолжаю натыкаться на случаи, когда тот, кто его написал, продолжал делать следующее:
double c = (1.0/(a+1.0)*pow(b, a+1.0));
double d = (1./(integral(gamma, dmax)-integral(gamma, dmin)))*(integral(gamma+1, dmax)-integral(gamma+1, dmin));
Вместо того, чтобы:
double c = pow(b, a+1.0)/(a+1.0);
double d = (integral(gamma+1, dmax)-integral(gamma+1, dmin))/(integral(gamma, dmax)-integral(gamma, dmin));
Второй вариант кажется намного понятнее, и если я не ошибаюсь относительно порядка операций в C ++, они должны делать то же самое.Есть ли какая-то причина делать первое, а не второе?Единственное, о чем я мог бы подумать, это о каком-нибудь странном случае с точностью.
Решение
Да, это одно и то же.Единственная причина, о которой я могу думать, - это математическая ясность:иногда, когда вы нормализуете величину, вы часто пишете:
answer = (1/total) * (some of it)
Например, интегральная теорема Коши часто пишется
f(a) = (1/(2*pi*i)) * integral(f(z)/(z-a), dz)
Другие советы
Если a
остается прежним и b
меняется (скажем, если ваш код находится в цикле и ясно, что a
не изменяется между двумя итерациями, например, потому, что это const
переменная), тогда исходная версия может выполняться быстрее, потому что умножение дешевле деления (при условии, что компилятор перемещает вычисление 1/...
вне цикла).
Это кажется ошибочной попыткой оптимизации, если причина в этом, но это не значит, что это не так.
О, и что касается точности, оригинальная версия на самом деле немного менее точна, чем ваша, если уж на то пошло, потому что есть дополнительная ошибка округления для 1/...
.Именно эта ошибка округления не позволяет компилятору преобразовать вашу версию в исходную по собственной воле:они вычисляют не совсем одно и то же (но очень близкие вещи).
Да, они должны делать то же самое.Первоначальный автор, возможно, копировал уравнения, найденные в другом месте