跳到主要内容

Fma

定义于头文件 <cmath> 中。

描述

计算 x * y + z,就像以无限精度计算并仅舍入一次以适应结果类型。该库为所有 cv-unqualified 浮点类型提供了 std::fma 的重载,作为参数 xyz 的类型。

如果定义了宏常量 FP_FAST_FMAFP_FAST_FMAFFP_FAST_FMAL,则函数 std::fma 的评估速度(除了更精确)比 floatdoublelong double 参数的表达式 x * y + z 分别更快。如果定义了这些宏,它们的值为整数 1

声明

// 1)
constexpr /* floating-point-type */
fma ( /* floating-point-type */ x,
/* floating-point-type */ y,
/* floating-point-type */ z );
// 2)
constexpr float fmaf( float x, float y, float z );
// 3)
constexpr long double fmal( long double x, long double y, long double z );
附加重载
// 4)
template< class Arithmetic1, class Arithmetic2, class Arithmetic3 >
constexpr /* common-floating-point-type */
fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
宏常量定义
#define FP_FAST_FMA  /* implementation-defined */
#define FP_FAST_FMAF /* implementation-defined */
#define FP_FAST_FMAL /* implementation-defined */

参数

x, y, z - 浮点或整数值

返回值

如果成功,返回 x * y + z 的值,就像以无限精度计算并一次舍入以适应结果类型(或者,作为单个三元浮点运算计算)

如果由于溢出而发生范围错误,则返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL

如果因下溢导致范围错误,则返回正确的值(四舍五入后)。

错误处理

如果实现支持 IEEE 浮点运算(IEC 60559

如果 x 为零且 y 为无穷大,或者 x 为无穷大且 y 为零,并且
如果 z 不是 NaN,则返回 NaN 并引发 FE_INVALID
如果 z 是 NaN,则返回 NaN 并可能引发 FE_INVALID
如果 x * y 是精确的无穷大且 z 是相反符号的无穷大,则返回 NaN 并引发 FE_INVALID
如果 xy 是 NaN,则返回 NaN
如果 z 是 NaN,并且 x * y 不是 0*InfInf*0,则返回 NaN(不引发 FE_INVALID)

备注

此操作通常在硬件中作为融合乘加 CPU 指令实现。如果硬件支持,预计会定义适当的 FP_FAST_FMA? 宏,但即使未定义这些宏,许多实现也会使用 CPU 指令。

POSIX (fma, fmaf, fmal) 另外指定,指定返回 FE_INVALID 的情况是域错误。

由于其无限的中间精度,std::fma 是其他正确舍入的数学操作的常见构建块,例如 std::sqrt 甚至除法(如果 CPU 未提供,例如 Itanium)。

与所有浮点表达式一样,表达式 x * y + z 可以编译为融合乘加,除非 #pragma STDC FP_CONTRACT 关闭。

不需要完全按照“附加重载”提供附加重载。它们只需要足以确保对于它们的第一个参数 num1、第二个参数 num2 和第三个参数 num3

如果 num1num2num3 的类型是 long double,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<long double>(num1), static_cast<long double>(num2), static_cast<long double>(num3))

否则,如果 num1num2 和/或 num3 的类型是 double 或整数类型,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<double>(num1), static_cast<double>(num2), static_cast<double>(num3))

否则,如果 num1num2num3 的类型是 float,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<float>(num1), static_cast<float>(num2), static_cast<float>(num3))

如果 num1num2num3 具有算术类型,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast</* common-floating-point-type */>(num1), static_cast</* common-floating-point-type */>(num2), static_cast</* common-floating-point-type */>(num3))

其中 /* common-floating-point-type */ 是在 num1num2num3 的类型中具有最高浮点转换等级和最高浮点转换子等级的浮点类型,整数类型的参数被认为与 double 具有相同的浮点转换等级。

如果不存在具有最高等级和子等级的浮点类型,则重载决议不会从提供的重载中产生可用的候选。

示例

#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

Fma

定义于头文件 <cmath> 中。

描述

计算 x * y + z,就像以无限精度计算并仅舍入一次以适应结果类型。该库为所有 cv-unqualified 浮点类型提供了 std::fma 的重载,作为参数 xyz 的类型。

如果定义了宏常量 FP_FAST_FMAFP_FAST_FMAFFP_FAST_FMAL,则函数 std::fma 的评估速度(除了更精确)比 floatdoublelong double 参数的表达式 x * y + z 分别更快。如果定义了这些宏,它们的值为整数 1

声明

// 1)
constexpr /* floating-point-type */
fma ( /* floating-point-type */ x,
/* floating-point-type */ y,
/* floating-point-type */ z );
// 2)
constexpr float fmaf( float x, float y, float z );
// 3)
constexpr long double fmal( long double x, long double y, long double z );
附加重载
// 4)
template< class Arithmetic1, class Arithmetic2, class Arithmetic3 >
constexpr /* common-floating-point-type */
fma( Arithmetic1 x, Arithmetic2 y, Arithmetic3 z );
宏常量定义
#define FP_FAST_FMA  /* implementation-defined */
#define FP_FAST_FMAF /* implementation-defined */
#define FP_FAST_FMAL /* implementation-defined */

参数

x, y, z - 浮点或整数值

返回值

如果成功,返回 x * y + z 的值,就像以无限精度计算并一次舍入以适应结果类型(或者,作为单个三元浮点运算计算)

如果由于溢出而发生范围错误,则返回 ±HUGE_VAL±HUGE_VALF±HUGE_VALL

如果因下溢导致范围错误,则返回正确的值(四舍五入后)。

错误处理

如果实现支持 IEEE 浮点运算(IEC 60559

如果 x 为零且 y 为无穷大,或者 x 为无穷大且 y 为零,并且
如果 z 不是 NaN,则返回 NaN 并引发 FE_INVALID
如果 z 是 NaN,则返回 NaN 并可能引发 FE_INVALID
如果 x * y 是精确的无穷大且 z 是相反符号的无穷大,则返回 NaN 并引发 FE_INVALID
如果 xy 是 NaN,则返回 NaN
如果 z 是 NaN,并且 x * y 不是 0*InfInf*0,则返回 NaN(不引发 FE_INVALID)

备注

此操作通常在硬件中作为融合乘加 CPU 指令实现。如果硬件支持,预计会定义适当的 FP_FAST_FMA? 宏,但即使未定义这些宏,许多实现也会使用 CPU 指令。

POSIX (fma, fmaf, fmal) 另外指定,指定返回 FE_INVALID 的情况是域错误。

由于其无限的中间精度,std::fma 是其他正确舍入的数学操作的常见构建块,例如 std::sqrt 甚至除法(如果 CPU 未提供,例如 Itanium)。

与所有浮点表达式一样,表达式 x * y + z 可以编译为融合乘加,除非 #pragma STDC FP_CONTRACT 关闭。

不需要完全按照“附加重载”提供附加重载。它们只需要足以确保对于它们的第一个参数 num1、第二个参数 num2 和第三个参数 num3

如果 num1num2num3 的类型是 long double,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<long double>(num1), static_cast<long double>(num2), static_cast<long double>(num3))

否则,如果 num1num2 和/或 num3 的类型是 double 或整数类型,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<double>(num1), static_cast<double>(num2), static_cast<double>(num3))

否则,如果 num1num2num3 的类型是 float,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast<float>(num1), static_cast<float>(num2), static_cast<float>(num3))

如果 num1num2num3 具有算术类型,则
std::fma(num1, num2, num3) 具有与以下相同的效果:
std::fma(static_cast</* common-floating-point-type */>(num1), static_cast</* common-floating-point-type */>(num2), static_cast</* common-floating-point-type */>(num3))

其中 /* common-floating-point-type */ 是在 num1num2num3 的类型中具有最高浮点转换等级和最高浮点转换子等级的浮点类型,整数类型的参数被认为与 double 具有相同的浮点转换等级。

如果不存在具有最高等级和子等级的浮点类型,则重载决议不会从提供的重载中产生可用的候选。

示例

#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