2016-09-11 2 views
4

У меня есть функция, которая принимает float, я делаю некоторые вычисления с ними, и я хотел бы сохранить как можно больше точности в возвращаемом результате. Я читал, что когда вы умножаете два поплавка, вы удваиваете количество значимых цифр.Умножение поплавков и сохранение/получение точности с двойной точностью

Итак, когда два поплавка умножаются, например float e, f;, и я делаю double g = e * f, когда бит заканчивается?

В моем примере функция ниже, мне нужно кастинг, и если да, то где? Это находится в плотном внутреннем цикле, если я помещаю static_cast<double>(x) вокруг каждой переменной a b c d, где он используется, я получаю 5-10% замедления. Но я подозреваю, что мне не нужно бросать каждую переменную отдельно, и только в некоторых местах, если вообще? Или возвращение двойника здесь не дает мне никакой выгоды, и я могу просто вернуть поплавок?

double func(float a, float b, float c, float d) { 
    return (a - b) * c + (a - c) * b; 
} 
+1

Вам нужен только один актер, так как другие операнды будут преобразованы для вас _ "если один из операндов двойной, другой операнд преобразуется в двойной" _ источник: http://en.cppreference.com/w/cpp/ language/operator_arithmetiC# Conversions Однако это все равно даст вам такое же замедление. Второй вопрос о возврате двойника зависит от того, что вы делаете с возвращенным результатом. –

+0

Да, но в моем случае оба (все) операнда (кроме возвращаемого типа) - это поплавки? – Ela782

+1

Вы можете получить лучшую производительность (и, тем не менее, лучшую точность), если вы используете 'double' всюду. Это экономит накладные расходы на конвертацию. – 5gon12eder

ответ

5

Когда вы умножаете два поплавка без литья, результат рассчитывается с точностью поплавка (т. Е. Усечен), а затем преобразуется в double.

Чтобы вычислить результат в двойном, вам необходимо выполнить по крайней мере один операнд, чтобы удвоить первый. Тогда весь расчет будет выполнен в double (и все значения float будут преобразованы). Однако это приведет к такому же замедлению. Замедление, скорее всего, связано с тем, что преобразование числа из float в double не является полностью тривиальным (разный размер бит и диапазон показателей и мантиса).

Если бы я это делал и имел контроль над определением функции, я бы передал все аргументы как двойные (я обычно использую double везде, на современных компьютерах разница в скорости между вычислением в float vs double незначительна, только проблемами могут быть производительность памяти и производительность кэша при работе на больших массивах значений).

КПП. дело важно для точности на самом деле не умножение, а сложение/вычитание - вот где точность может иметь большое значение. Рассмотрим добавление/вычитание 1e + 6 и 1e-3.

+0

Спасибо, ваши первые три предложения отлично отвечают на мои вопрос! И другая информация весьма полезна. – Ela782

4

Значение более чем 5-10% -ное снижение. То, что я хотел бы сделать:

double func_impl(double a, double b, double c, double d) { 
    return (a - b) * c + (a - c) * b; 
} 

double func(float a, float b, float c, float d) { 
    return func_impl(a, b, c, d); 
} 

Я выбрал бы это, даже если это немного медленнее, потому что он выражает идею, что вы хотите двойной точности в вычислениях хорошо и просто нужно поплавки на интерфейсе; в то время как он удерживает тело вашей функции отдельно от литья (последнее делается за один шаг).

Смежные вопросы