fma, fmaf, fmal
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Определено в заголовке
<math.h>
|
||
|
float
fmaf
(
float
x,
float
y,
float
z
)
;
|
(1) | (начиная с C99) |
|
double
fma
(
double
x,
double
y,
double
z
)
;
|
(2) | (начиная с C99) |
|
long
double
fmal
(
long
double
x,
long
double
y,
long
double
z
)
;
|
(3) | (начиная с C99) |
|
#define FP_FAST_FMA /* implementation-defined */
|
(4) | (начиная с C99) |
|
#define FP_FAST_FMAF /* implementation-defined */
|
(5) | (начиная с C99) |
|
#define FP_FAST_FMAL /* implementation-defined */
|
(6) | (начиная с C99) |
|
Определено в заголовке
<tgmath.h>
|
||
|
#define fma( x, y, z )
|
(7) | (начиная с C99) |
FP_FAST_FMA
,
FP_FAST_FMAF
или
FP_FAST_FMAL
, соответствующая функция
fma
,
fmaf
или
fmal
вычисляется быстрее (в дополнение к большей точности), чем выражение
x
*
y
+
z
для аргументов типа
double
,
float
и
long
double
соответственно. Если определены, эти макросы вычисляются в целочисленное значение
1
.
fmal
вызывается. В противном случае, если любой аргумент имеет целочисленный тип или тип
double
,
fma
вызывается. В противном случае
fmaf
вызывается.
Содержание |
Параметры
| 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 определяет что ситуация, когда значение x * y является недопустимым и z является NaN, представляет собой ошибку домена.
Благодаря своей бесконечной промежуточной точности,
fma
является распространённым базовым элементом для других корректно округлённых математических операций, таких как
sqrt
или даже деление (когда оно не предоставляется процессором, например, на
Itanium
).
Как и все выражения с плавающей точкой, выражение ( x * y ) + z может быть скомпилировано как fused multiply-add, если только #pragma STDC FP_CONTRACT не отключена.
Пример
#include <fenv.h> #include <float.h> #include <math.h> #include <stdio.h> // #pragma STDC FENV_ACCESS ON int main(void) { // демонстрация разницы между fma и встроенными операторами double in = 0.1; printf("0.1 в double это %.23f (%a)\n", in, in); printf("0.1*10 это 1.0000000000000000555112 (0x8.0000000000002p-3)," " или 1.0 при округлении до double\n"); double expr_result = 0.1 * 10 - 1; printf("0.1 * 10 - 1 = %g : 1 вычитается после " "промежуточного округления до 1.0\n", expr_result); double fma_result = fma(0.1, 10, -1); printf("fma(0.1, 10, -1) = %g (%a)\n", fma_result, fma_result); // использование fma в double-double арифметике printf("\nв double-double арифметике 0.1 * 10 представляется как "); double high = 0.1 * 10; double low = fma(0.1, 10, -high); printf("%g + %g\n\n", high, low); // обработка ошибок feclearexcept(FE_ALL_EXCEPT); printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY)); if (fetestexcept(FE_INVALID)) puts(" FE_INVALID поднят"); }
Возможный вывод:
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 to 1.0
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
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
-
- 7.12.13.1 Функции fma (стр.: TBD)
-
- 7.25 Обобщённая математика <tgmath.h> (стр.: TBD)
-
- F.10.10.1 Функции fma (стр.: TBD)
- Стандарт C17 (ISO/IEC 9899:2018):
-
- 7.12.13.1 Функции fma (стр. 188-189)
-
- 7.25 Обобщенная математика <tgmath.h> (стр. 272-273)
-
- F.10.10.1 Функции fma (стр. 386)
- Стандарт C11 (ISO/IEC 9899:2011):
-
- 7.12.13.1 Функции fma (стр. 258)
-
- 7.25 Обобщённая математика <tgmath.h> (стр. 373-375)
-
- F.10.10.1 Функции fma (стр. 530)
- Стандарт C99 (ISO/IEC 9899:1999):
-
- 7.12.13.1 Функции fma (стр. 239)
-
- 7.22 Обобщённая математика <tgmath.h> (стр. 335-337)
-
- F.9.10.1 Функции fma (стр. 466)
Смотрите также
|
(C99)
(C99)
(C99)
|
вычисляет знаковый остаток от операции деления чисел с плавающей запятой
(функция) |
|
(C99)
(C99)
(C99)
|
вычисляет знаковый остаток, а также три последних бита операции деления
(функция) |
|
Документация C++
для
fma
|
|