std:: fma, std:: fmaf, std:: fmal
|
Определено в заголовочном файле
<cmath>
|
||
| (1) | ||
|
float
fma
(
float
x,
float
y,
float
z
)
;
double
fma
(
double
x,
double
y,
double
z
)
;
|
(начиная с C++11)
(до C++23) |
|
|
constexpr
/* floating-point-type */
fma
(
/* floating-point-type */
x,
|
(начиная с C++23) | |
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(2) |
(начиная с C++11)
(constexpr начиная с C++23) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) |
(начиная с C++11)
(constexpr начиная с C++23) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (начиная с C++11) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (начиная с C++11) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (начиная с C++11) |
|
Определено в заголовочном файле
<cmath>
|
||
|
template
<
class
Arithmetic1,
class
Arithmetic2,
class
Arithmetic3
>
/* common-floating-point-type */
|
(A) |
(начиная с C++11)
(constexpr начиная с C++23) |
std::fma
для всех неквалифицированных cv типов с плавающей точкой в качестве типа параметров
x
,
y
и
z
.
(начиная с C++23)
std::fma
выполняется быстрее (в дополнение к большей точности), чем выражение
x
*
y
+
z
для аргументов типа
double
,
float
и
long
double
соответственно. Если определены, эти макросы вычисляются в целочисленное значение
1
.
Содержание |
Параметры
| x, y, z | - | значения с плавающей точкой или целочисленные значения |
Возвращаемое значение
В случае успеха возвращает значение x * y + z так, как если бы оно было вычислено с бесконечной точностью и однократно округлено для соответствия типу результата (или, альтернативно, вычислено как одна тернарная операция с плавающей точкой).
Если происходит ошибка диапазона из-за переполнения,
±HUGE_VAL
,
±HUGE_VALF
, или
±HUGE_VALL
возвращается.
Если возникает ошибка диапазона из-за потери значимости (underflow), возвращается корректное значение (после округления).
Обработка ошибок
Ошибки сообщаются, как указано в math_errhandling .
Если реализация поддерживает арифметику с плавающей запятой IEEE (IEC 60559),
-
Если
x
равен нулю и
y
бесконечен, или если
x
бесконечен и
y
равен нулю, и
- если z не является NaN, то возвращается NaN и возбуждается FE_INVALID ,
- если z является NaN, то возвращается NaN и может быть возбуждено FE_INVALID .
- Если x * y является точной бесконечностью и z является бесконечностью с противоположным знаком, возвращается NaN и возбуждается FE_INVALID .
- Если x или y являются NaN, возвращается NaN.
- Если z является NaN, и x * y не является 0 * Inf или Inf * 0 , то возвращается NaN (без FE_INVALID ).
Примечания
Эта операция обычно реализуется в аппаратном обеспечении как fused multiply-add инструкция процессора. Если она поддерживается аппаратно, ожидается, что соответствующие FP_FAST_FMA ? макросы будут определены, но многие реализации используют инструкцию процессора даже когда макросы не определены.
POSIX
(
fma
,
fmaf
,
fmal
)
дополнительно указывает, что ситуации, в которых требуется возврат
FE_INVALID
, являются ошибками домена.
Благодаря своей бесконечной промежуточной точности,
std::fma
является распространённым строительным блоком для других корректно округлённых математических операций, таких как
std::sqrt
или даже деление (когда оно не предоставляется процессором, например, на
Itanium
).
Как и все выражения с плавающей точкой, выражение x * y + z может быть скомпилировано как fused multiply-add, если только #pragma STDC FP_CONTRACT не отключена.
Дополнительные перегрузки не обязаны быть предоставлены в точности как (A) . Они должны быть лишь достаточными для обеспечения того, чтобы для их первого аргумента num1 , второго аргумента num2 и третьего аргумента num3 :
|
(до C++23) |
|
Если
num1
,
num2
и
num3
имеют арифметические типы, то
std
::
fma
(
num1, num2, num3
)
имеет тот же эффект, что и
std
::
fma
(
static_cast
<
/*common-floating-point-type*/
>
(
num1
)
,
Если такого типа с плавающей запятой с наибольшим рангом и подрангом не существует, то разрешение перегрузки не приводит к пригодному кандидату из предоставленных перегрузок. |
(начиная с C++23) |
Пример
#include <cfenv> #include <cmath> #include <iomanip> #include <iostream> #ifndef __GNUC__ #pragma STDC FENV_ACCESS ON #endif int main() { // демонстрация разницы между fma и встроенными операторами const double in = 0.1; std::cout << "0.1 в double равно " << std::setprecision(23) << in << " (" << std::hexfloat << in << std::defaultfloat << ")\n" << "0.1*10 равно 1.0000000000000000555112 (0x8.0000000000002p-3), " << "или 1.0 при округлении до double\n"; const double expr_result = 0.1 * 10 - 1; const double fma_result = std::fma(0.1, 10, -1); std::cout << "0.1 * 10 - 1 = " << expr_result << " : 1 вычитается после промежуточного округления\n" << "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " (" << std::hexfloat << fma_result << std::defaultfloat << ")\n\n"; // fma используется в double-double арифметике const double high = 0.1 * 10; const double low = std::fma(0.1, 10, -high); std::cout << "в double-double арифметике 0.1 * 10 представляется как " << high << " + " << low << "\n\n"; // обработка ошибок std::feclearexcept(FE_ALL_EXCEPT); std::cout << "fma(+Inf, 10, -Inf) = " << std::fma(INFINITY, 10, -INFINITY) << '\n'; if (std::fetestexcept(FE_INVALID)) std::cout << " FE_INVALID поднят\n"; }
Возможный вывод:
0.1 double is 0.10000000000000000555112 (0x1.999999999999ap-4)
0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), or 1.0 if rounded to double
0.1 * 10 - 1 = 0 : 1 subtracted after intermediate rounding
fma(0.1, 10, -1) = 5.55112e-17 (0x1p-54)
in double-double arithmetic, 0.1 * 10 is representable as 1 + 5.55112e-17
fma(+Inf, 10, -Inf) = -nan
FE_INVALID raised
Смотрите также
|
(C++11)
(C++11)
(C++11)
|
знаковый остаток от операции деления
(функция) |
|
(C++11)
(C++11)
(C++11)
|
знаковый остаток, а также три последних бита операции деления
(функция) |
|
Документация C
для
fma
|
|