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) |
(x * y) + z так, как если бы вычисление выполнялось с бесконечной точностью, а округление производилось только один раз для соответствия типу результата.FP_FAST_FMA, FP_FAST_FMAF или FP_FAST_FMAL, соответствующая функция fma, fmaf или fmal выполняется быстрее (и при этом обеспечивает большую точность), чем выражение x * y + z для аргументов типов double, float и longdouble соответственно. Если эти макросы определены, они принимают целочисленное значение 1.fmal. В противном случае, если хотя бы один аргумент имеет целочисленный тип или тип double, вызывается fma. В противном случае вызывается fmaf.Параметры
| x, y, z | - | значения с плавающей точкой |
Возвращаемое значение
В случае успеха возвращает значение (x * y) + z, вычисленное так, как если бы оно было рассчитано с бесконечной точностью и округлено один раз для соответствия типу результата (или, альтернативно, рассчитано как одна троичная операция с плавающей точкой).
Если возникает ошибка диапазона из-за переполнения, возвращается ±HUGE_VAL, ±HUGE_VALF или ±HUGE_VALL.
Если возникает ошибка диапазона из-за потери значимости, возвращается правильное значение (после округления).
Обработка ошибок
Об ошибках сообщается согласно спецификации в 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).
Примечания
Эта операция обычно реализуется аппаратно в виде инструкции процессора слитного умножения-сложения. Если аппаратная поддержка имеется, ожидается, что будут определены соответствующие макросы FP_FAST_FMA*, однако во многих реализациях инструкция процессора используется, даже если эти макросы не определены.
POSIX устанавливает, что ситуация, когда значение x * y недопустимо, а z является NaN, считается ошибкой области определения.
Благодаря бесконечной точности промежуточных вычислений fma часто используется как строительный блок для других математических операций с корректным округлением, таких как sqrt или даже деление (если оно не поддерживается процессором, например, на Itanium).
Как и любое выражение с плавающей точкой, выражение (x * y) + z может быть скомпилировано как слитное умножение-сложение, если только параметр #pragma STDC FP_CONTRACT не выключен.
Пример
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
// #pragma STDC FENV_ACCESS ON
int main(void)
{
// demo the difference between fma and built-in operators
double in = 0.1;
printf("0.1 double is %.23f (%a)\n", in, in);
printf("0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3),"
" or 1.0 if rounded to double\n");
double expr_result = 0.1 * 10 - 1;
printf("0.1 * 10 - 1 = %g : 1 subtracted after "
"intermediate rounding to 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 use in double-double arithmetic
printf("\nin double-double arithmetic, 0.1 * 10 is representable as ");
double high = 0.1 * 10;
double low = fma(0.1, 10, -high);
printf("%g + %g\n\n", high, low);
// error handling
feclearexcept(FE_ALL_EXCEPT);
printf("fma(+Inf, 10, -Inf) = %f\n", fma(INFINITY, 10, -INFINITY));
if (fetestexcept(FE_INVALID))
puts(" FE_INVALID raised");
}
Возможный вывод:
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 |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/numeric/math/fma