Понимание операций двойной точности в C

Я хотел бы понять, почему этот код:

double r,d,rc;
scanf("%lf %lf", &r, &d);
rc = (r * r) - (d/2) * (d/2);
printf("%.2f\n", M_PI * rc);

возвращает более точный результат, чем этот (без назначения переменной rc):

double r,d,rc;
scanf("%lf %lf", &r, &d);
printf("%.2f\n", M_PI * (r * r) - (d/2) * (d/2));

Другой связанный вопрос: почему n * n лучше, чем pow(n,2)?

Ответ 1

Первый пример кода вычисляет:

M_PI * ((r * r) - (d/2) * (d/2));

Второе вычисляет:

(M_PI * (r * r)) - (d/2) * (d/2);

Для большинства компиляторов вызов pow(n, 2) совпадает с n * n. Будет произведена та же самая сборка. Это связано с оптимизацией, называемой "сокращение силы". Большинство реализаций pow() будут проверять, является ли показатель степени равным 2, и уменьшают этот случай до одного умножения. Неоптимизированная версия немного дороже, так как требует вызова функции и некоторого разветвления.

Обратите внимание, что M_PI не является частью стандарта C, поэтому вы можете использовать эквивалент, который компилируется в тот же самый код:

double M_PI = 4.0 * atan(1.0);

Ответ 2

Чтобы ответить на второй вопрос; pow предназначен для выполнения произвольных полномочий, но не удивительно, что существует более быстрый способ вычисления ответа при постоянной мощности. Однократное умножение выполняется быстро (всего одна инструкция процессора), тогда как для вызова pow требуется служебная информация вызова функции (без учета оптимизации на данный момент) и итеративный алгоритм, который многократно умножается, пока не получит ответ. Когда вы можете увидеть математический ярлык, чтобы избежать таких вещей, вы его используете.