Namespaces
Variants

fma, fmaf, fmal

From cppreference.net
< c ‎ | numeric ‎ | math
Common mathematical functions
Functions
Basic operations
(C99)
fma
(C99)
(C99)
(C99) (C99) (C99) (C23)
Maximum/minimum operations
Exponential functions
Power functions
Trigonometric and hyperbolic functions
Nearest integer floating-point
(C99) (C99) (C99)
(C23) (C23) (C23) (C23)
Floating-point manipulation
Narrowing operations
(C23)
(C23)
(C23)
(C23)
(C23)
(C23)
Quantum and quantum exponent
Decimal re-encoding functions
Total order and payload functions
Classification
Error and gamma functions
(C99)
(C99)
(C99)
(C99)
Types
Macro constants
Special floating-point values
Arguments and return values
Error handling
Fast operation indicators
Определено в заголовке <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)
1-3) Вычисляет ( x * y ) + z как если бы с бесконечной точностью, с однократным округлением для приведения к типу результата.
4-6) Если определены макроконстанты FP_FAST_FMA , FP_FAST_FMAF или FP_FAST_FMAL , соответствующая функция fma , fmaf или fmal вычисляется быстрее (в дополнение к большей точности), чем выражение x * y + z для аргументов типа double , float и long double соответственно. Если определены, эти макросы вычисляются в целочисленное значение 1 .
7) Макрос общего типа: Если любой аргумент имеет тип long double , 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)
вычисляет знаковый остаток, а также три последних бита операции деления
(функция)