std::fma, std::fmaf, std::fmal
Определено в заголовочном файле <cmath> | ||
|---|---|---|
float fma ( float x, float y, float z ); double fma ( double x, double y, double z ); long double fma ( long double x, long double y, long double z ); | (1) |
(начиная с C++11) (до C++23) |
constexpr /* floating-point-type */
fma ( /* floating-point-type */ x,
/* floating-point-type */ y,
/* floating-point-type */ z );
| (начиная с 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 */
fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
| (A) |
(начиная с C++11) (constexpr начиная с C++23) |
x * y + z так, как если бы вычисление выполнялось с бесконечной точностью и округлялось только один раз для получения результата требуемого типа. Библиотека предоставляет перегрузки std::fma для всех типов с плавающей точкой без cv-квалификаторов в качестве типов параметров x, y и z.(начиная с C++23)
FP_FAST_FMA, FP_FAST_FMAF или FP_FAST_FMAL, функция std::fma выполняется быстрее (и при этом обеспечивает более высокую точность), чем выражение x * y + z для аргументов типа double, float и longdouble соответственно. Если они определены, эти макросы имеют целочисленное значение 1.Параметры
| 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 (fma, fmaf, fmal) дополнительно указывает, что ситуации, для которых предписан возврат FE_INVALID, являются доменными ошибками.
Благодаря бесконечной точности промежуточных вычислений std::fma часто служит основой для других математических операций с корректным округлением, например std::sqrt или даже деления (если оно не поддерживается процессором, например на Itanium).
Как и любые выражения с плавающей точкой, выражение x * y + z может быть скомпилировано как слитное умножение и сложение, если только STDC FP_CONTRACT не выключен в #pragma.
Не требуется, чтобы дополнительные перегрузки были предоставлены в точности в виде (A). Они должны лишь обеспечивать, чтобы для первого аргумента num1, второго аргумента num2 и третьего аргумента num3:
| (до C++23) |
| Если Если такого типа с плавающей точкой с наибольшими рангом и подрангом не существует, то разрешение перегрузки не выбирает пригодного кандидата из предоставленных перегрузок. | (начиная с C++23) |
Пример
#include <cfenv>
#include <cmath>
#include <iomanip>
#include <iostream>
#ifndef __GNUC__
#pragma STDC FENV_ACCESS ON
#endif
int main()
{
// demo the difference between fma and built-in operators
const double in = 0.1;
std::cout << "0.1 double is " << std::setprecision(23) << in
<< " (" << std::hexfloat << in << std::defaultfloat << ")\n"
<< "0.1*10 is 1.0000000000000000555112 (0x8.0000000000002p-3), "
<< "or 1.0 if rounded to 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 subtracted after intermediate rounding\n"
<< "fma(0.1, 10, -1) = " << std::setprecision(6) << fma_result << " ("
<< std::hexfloat << fma_result << std::defaultfloat << ")\n\n";
// fma is used in double-double arithmetic
const double high = 0.1 * 10;
const double low = std::fma(0.1, 10, -high);
std::cout << "in double-double arithmetic, 0.1 * 10 is representable as "
<< high << " + " << low << "\n\n";
// error handling
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 raised\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 |
|
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/numeric/math/fma