std::fma, std::fmaf, std::fmal
Определено в заголовочном файле <cmath> |
||
|---|---|---|
| (1) | ||
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 ); |
(с 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 для float, double, и long double аргументов соответственно. Если определены, эти макросы возвращают целое число 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. - если
zNaN, то возвращается NaN и может быть сгенерированFE_INVALID.
- если
- Если
x * yточная бесконечность, аzбесконечность с противоположным знаком, возвращается NaN и генерируетсяFE_INVALID. - Если
xилиyNaN, возвращается NaN. - Если
zNaN, иx * yне 0 * Бесконечность или Бесконечность * 0, то возвращается NaN (безFE_INVALID).
Примечания
Эта операция обычно реализуется в аппаратном обеспечении как инструкция ЦП умножения-сложения. Если поддерживается аппаратным обеспечением, ожидается определение соответствующих FP_FAST_FMA? макросов, но многие реализации используют инструкцию ЦП даже когда макросы не определены.
POSIX (fma, fmaf, fmal) дополнительно указывает, что ситуации, указанные для возврата FE_INVALID, являются ошибками области.
Благодаря своей бесконечной промежуточной точности, std::fma является общим строительным блоком других математических операций с правильным округлением, таких как std::sqrt или даже деление (если не предоставлено ЦП, например, Itanium).
Как и для всех выражений с плавающей точкой, выражение x * y + z может быть скомпилировано как умножение-сложение, если #pragma STDC FP_CONTRACT не выключен.
Дополнительные перегрузки не обязаны быть предоставлены точно как (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/w/cpp/numeric/math/fma