是否有一种方法可以获得比float
小的浮点类型1
表示的最大值。
我有见以下定义
static const double DoubleOneMinusEpsilon = 0x1.fffffffffffffp-1;
static const float FloatOneMinusEpsilon = 0x1.fffffep-1;
但这就是我们应该如何定义这些价值观吗?
根据标准,std::numeric_limits<T>::epsilon
是机器epsilon,也就是说,1.0和下一个值之间的差异可以由浮点类型的T
表示。但这并不一定意味着定义T(1) - std::numeric_limits<T>::epsilon
会更好。
发布于 2022-03-07 07:44:30
您可以使用函数,不管它的名称如何,它可以通过使用适当的to
参数来检索下一个可表示的值,该值在给定的起始点之前是算术的。(通常是-Infinity
、0
或+Infinity
)。
无论您的nextafter
实现使用什么浮点格式,通过C++的定义,这是可以移植的。(二进制对十进制,或尾数的宽度,也就是意义,或其他任何东西。)
示例:检索double
类型的最近值小于1(在Windows上,使用Visual 2019年中的clang编译器),答案与1 - ε
计算结果不同(如注释中所讨论的,IEEE754数字不正确;在任何2的幂以下,可表示数字是其上面的两倍):
#include <iostream>
#include <iomanip>
#include <cmath>
#include <limits>
int main()
{
double naft = std::nextafter(1.0, 0.0);
std::cout << std::fixed << std::setprecision(20);
std::cout << naft << '\n';
double neps = 1.0 - std::numeric_limits<double>::epsilon();
std::cout << neps << '\n';
return 0;
}
输出:
0.99999999999999988898
0.99999999999999977796
使用不同的输出格式,这可以打印为0x1.fffffffffffffp-1
和0x1.ffffffffffffep-1
(1 - ε
)。
注意,当使用类似技术来确定大于1
的最近值时,nextafter(1.0, 10000.)
调用提供与1 + ε
计算(1.00000000000000022204)相同的值,这与ε定义中的预期值相同。
性能
C++23要求std::nextafter
必须是constexpr
,但目前只有一些编译器支持这一点。GCC确实通过它做了恒定的传播,但是clang不能(哥德波特).如果您希望这与0x1.fffffffffffffp-1;
这样的文字常量一样快(在启用优化的情况下),对于double
是IEEE754 binary64的系统,那么在某些编译器上,您将不得不等待C++23支持的这一部分。(很可能一旦编译器能够做到这一点,比如GCC,即使不实际使用-std=c++23
,他们也会进行优化。)
全局作用域的const double DoubleBelowOne = std::nextafter(1.0, 0.);
在最坏的情况下将在启动时运行该函数一次,从而击败了使用它的常量传播,但如果与其他运行时变量一起使用,则执行与FP文字常量大致相同的操作。
发布于 2022-03-07 08:37:04
这可以在不调用函数的情况下通过使用C标准中指定的浮点表示的特性来计算。由于epsilon
提供了略高于1的可表示数之间的距离,而radix
提供了用来表示数字的基,所以在1以下的可表示数之间的距离是epsilon
除以该基:
#include <iostream>
#include <limits>
int main(void)
{
typedef float Float;
std::cout << std::hexfloat <<
1 - std::numeric_limits<Float>::epsilon() / std::numeric_limits<Float>::radix
<< '\n';
}
发布于 2022-03-07 14:56:26
0.9999940395355224609375是小于1的最大32位浮点数。下面的代码演示如下:
Mac_3.2.57$cat float2uintTest4.c
#include <stdio.h>
int main(void){
union{
float f;
unsigned int i;
} u;
//u.f=0.9999;
//printf("as hex: %x\n", u.i); // 0x3f7fffff
u.i=0x3f800000; // 1.0
printf("as float: %200.200f\n", u.f);
u.i=0x3f7fffff; // 1.0-e
//00111111 01111111 11111111 11111111
//seeeeeee emmmmmmm mmmmmmmm mmmmmmmm
printf("as float: %200.200f\n", u.f);
return(0);
}
Mac_3.2.57$cc float2uintTest4.c
Mac_3.2.57$./a.out
as float: 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
as float: 0.99999994039535522460937500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
https://stackoverflow.com/questions/71383519
复制相似问题