Каковы правила, регулирующие смешанные вычисления одинарной и двойной точности C ++? - PullRequest
6 голосов
/ 21 ноября 2010

Например, эти переменные:

result (double)
a (double)
b (float)
c (float)
d (double)

Простой расчет:

result = a * (b + c) * d

Как и когда преобразуются типы и как выяснить, с какой точностью выполняются все вычисления?

Ответы [ 7 ]

13 голосов
/ 21 ноября 2010

Все операции выполняются над объектами одного типа (при условии нормальных арифметических операций).

Если вы напишите программу, использующую разные типы, компилятор автоматически обновит Параметр ONE , чтобы они оба были одинаковыми.

В этом случае значения с плавающей запятой будут увеличены до двойных:

result      = a * (b + c) * d

float  tmp1 = b + c;            // Plus operation done on floats.
                                // So the result is a float

double tmp2 = a * (double)tmp1; // Multiplication done on double (as `a` is double)
                                // so tmp1 will be up converted to a double.

double tmp3 = tmp2 * d;         // Multiplication done on doubles.
                                // So result is a double

result      = tmp3;             // No conversion as tmp3 is same type as result.
3 голосов
/ 21 ноября 2010

Если у вас есть:

float f;
double d;

... тогда арифметическое выражение типа f * d переведет оба операнда в больший тип, который в данном случае равен double.

* 1007.* Таким образом, выражение a * (b + c) * d оценивается как double, а затем сохраняется в result, что также является double.Это продвижение типа делается для того, чтобы избежать случайной потери точности.

Для получения дополнительной информации прочитайте эту статью об обычных арифметических преобразованиях .

1 голос
/ 22 ноября 2010

Вы должны различать преобразование типов и преобразование значений.Стандарт C ++ (в том числе и C) позволяет выполнять вычисления с плавающей точкой с повышенной точностью.

"Значения плавающих операндов и результаты плавающих выражений могут быть представлены с большей точностью и в диапазоне, чем требуетсяпо типу; типы не меняются. "

Как типы, b + c является сложением двух чисел с плавающей точкой.Результатом является поплавок.Затем результат получает тип, удваивающийся до двойного, и два умножения выполняются как двойные с результатом двойного.

Однако реализации разрешено выполнять все вычисления, включая b + c, с использованием двойных чисел (иливысокая точность).Действительно, я попробовал это с помощью Visual C ++, и он выполнил все вычисления с использованием 80-битного стека с плавающей точкой, доступного на x86.

1 голос
/ 21 ноября 2010

Следуя порядку операций, каждое подвыражение преобразуется в тип его (не уверен, что здесь термин, возможно, доминантный?).double доминирует над float, поэтому:

(b + c) // this is evaluated as a float, since both b and c are floats
a * (b + c) // this is evaluated as a double, since a is a double
a * (b + c) * d // this is evaluated as a double, since both "a * (b + c)" and d are doubles
1 голос
/ 21 ноября 2010

У вас есть скобка, ограничивающая число с плавающей точкой.Так что было бы сделать b + c как float + float.Преобразуйте это значение в удвоенное для сохранения максимальной точности, затем умножьте двойные значения.

Однако в том случае, если вы хотите контролировать преобразования, а не угадывать: используйте static_cast<>();

0 голосов
/ 21 ноября 2010

В вашем примере все типы float повышаются до double, когда вычисляется формула справа.

Что касается того, как они конвертируются: то, что я читал об операциях с плавающей запятой, состоит в том, что большинство современных аппаратных средств выполняют операции FP с использованием удвоенных длин (80 бит) в специальных аппаратных регистрах (по крайней мере, об этом я помню современные процессоры Intel x86 / x87). Насколько я понимаю, float и double продвигаются по типу В ОБОРУДОВАНИИ через специальные инструкции FP (кто-то исправит меня, если я ошибаюсь).

0 голосов
/ 21 ноября 2010

Поплавки будут преобразованы в двойные.Явно приведите значения.

то есть, если вы хотите удвоить результат, вы должны написать:

result = a * double( b + c ) * d;

ВСЕГДА стоит быть явным.Он встречает недоразумения, подобные этому, и это МГНОВЕННО очевидно для любого, кто пытается использовать ваш код именно то, что вы имеете в виду.

...