c++ - типов - Можно ли оптимизировать static_cast<float> из double, назначенного для double?




конструктор приведения типов c++ (3)

Независимо от того, разрешено ли такое преобразование, оно происходит, и изменчивое назначение останавливает его.

Например, компиляция MSVC для 32-битной (то есть с использованием x87) с /Ox /fp:fast :

_x$ = 8                                       ; size = 8
float uselessCast(double) PROC                         ; uselessCast
        fld     QWORD PTR _x$[esp-4]
        ret     0
float uselessCast(double) ENDP                         ; uselessCast

_y$ = 8                                       ; size = 4
_x$ = 8                                       ; size = 8
float coerceToFloat(double) PROC                   ; coerceToFloat
        fld     QWORD PTR _x$[esp-4]
        fstp    DWORD PTR _y$[esp-4]
        fld     DWORD PTR _y$[esp-4]
        ret     0
float coerceToFloat(double) ENDP 

Где uselessCast ниже, а coerceToFloat как в вопросе.

float uselessCast(double x)
{
    return static_cast<float>(x);
}

Аналогично, GCC и Clang с -O3 -ffast-math -m32 -mfpmath=387

uselessCast(double):
    fld     QWORD PTR [esp+4]
    ret
coerceToFloat(double):
    sub     esp, 20
    fld     QWORD PTR [esp+24]
    fstp    DWORD PTR [esp+12]
    fld     DWORD PTR [esp+12]
    add     esp, 20
    ret

Godbolt ссылка для всего вышеперечисленного

Конечно, вы можете утверждать, что с /fp:fast или -ffast-math вы ничего не должны ожидать от арифметики с плавающей запятой, но вам это может понадобиться, но вы все равно сможете отбросить лишнюю точность.

Я наткнулся на функцию, которая я считаю ненужной, и вообще меня пугает:

float coerceToFloat(double x) {
    volatile float y = static_cast<float>(x);
    return y;
}

Который затем используется так:

// double x
double y = coerceToFloat(x);

Отличается ли это когда-нибудь от простого?

double y = static_cast<float>(x);

Намерение, кажется, состоит в том, чтобы просто лишить двойного до единой точности Пахнет чем-то написанным из-за крайней паранойи.


Некоторые компиляторы имеют такую ​​концепцию «расширенной точности», когда двойники несут с собой более 64 бит данных. Это приводит к вычислениям с плавающей запятой, которые не соответствуют стандарту IEEE.

Приведенный выше код может быть попыткой не допустить, чтобы флаги расширенной точности на компиляторе убрали потерю точности. Такие флаги явно нарушают допущения точности значений типа double и значений с плавающей запятой. Кажется правдоподобным, что они не будут делать это с volatile переменной.


static_cast<float>(x) требуется для удаления любой избыточной точности, создавая float . Хотя стандарт C ++, как правило, позволяет реализациям сохранять избыточную точность с плавающей точкой в ​​выражениях, эта точность должна быть удалена операторами приведения и присваивания.

Лицензия на использование большей точности содержится в проекте C ++ N4659, пункт 8, пункт 13:

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

Сноска 64 гласит:

Операторы приведения и присваивания все еще должны выполнять свои конкретные преобразования, как описано в 8.4, 8.2.9 и 8.18.





floating-point