Chr*_*pka 1 c++ floating-point performance
在C++中(假定至少是C++ 11),给定浮点值a,我需要找到满足以下约束的浮点值b:
换句话说,我需要将a的幅度"截断"到最接近的2的幂,同时保持符号不变.
[*在我的情况下,"较少或相等"的约束是松散的,而"较少"也会起作用.]
给定一些IEEE 754二进制表示,实现此目的的一种方法是通过比特抨击简单地清除所有尾数位,同时保持符号和指数位不变.
一种更便携的方法是:
logb,ilogb甚至更便携,log2或frexp.pow(2.0,n),exp2(n),或ldexp(1.0,n).copysign.这允许许多可能的组合来解决任务,当考虑单精度替代方案时更是如此.有没有人对现代硬件和使用现代编译器的性能有这些方法的经验?
使用frexp()1,ldexp()2来呈现a,形成了答案.
这两个功能几乎完全是所需要的.
这些
frexp函数将浮点数分解为归一化分数和2的整数幂....frexp函数返回值x,使其x具有区间[1/2,1]或0的大小.这些
ldexp函数将浮点数乘以2的整数幂.
#include <math.h>
#include <stdio.h>
double round_pow2(double a) {
int exp;
double frac = frexp(a, &exp);
if (frac > 0.0) frac = 0.5;
else if (frac < 0.0) frac = -0.5;
double b = ldexp(frac, exp);
printf("% 20g % 25a % 25a", a, a, b);
printf(" %d", !!signbit(a) == !!signbit(b)); // b must have the same sign as a.
printf(" %d\n", !(fabs(b) > fabs(a))); // magnitude `b` must be <= magnitude `a`.
return b;
}
Run Code Online (Sandbox Code Playgroud)
测试代码
void round_pow2_test(double x) {
round_pow2(nextafter(-x, -INFINITY));
round_pow2(-x);
round_pow2(nextafter(-x, INFINITY));
round_pow2(nextafter(x, -INFINITY));
round_pow2(x);
round_pow2(nextafter(x, INFINITY));
}
int main(void) {
round_pow2_test(0);
round_pow2_test(DBL_MIN);
round_pow2_test(1.0);
round_pow2_test(42.0);
round_pow2_test(DBL_MAX);
round_pow2(NAN);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
产量
-4.94066e-324 -0x1p-1074 -0x1p-1074 1 1
-0 -0x0p+0 -0x0p+0 1 1
4.94066e-324 0x1p-1074 0x1p-1074 1 1
-4.94066e-324 -0x1p-1074 -0x1p-1074 1 1
0 0x0p+0 0x0p+0 1 1
4.94066e-324 0x1p-1074 0x1p-1074 1 1
-2.22507e-308 -0x1.0000000000001p-1022 -0x1p-1022 1 1
-2.22507e-308 -0x1p-1022 -0x1p-1022 1 1
-2.22507e-308 -0x1.ffffffffffffep-1023 -0x1p-1023 1 1
2.22507e-308 0x1.ffffffffffffep-1023 0x1p-1023 1 1
2.22507e-308 0x1p-1022 0x1p-1022 1 1
2.22507e-308 0x1.0000000000001p-1022 0x1p-1022 1 1
-1 -0x1.0000000000001p+0 -0x1p+0 1 1
-1 -0x1p+0 -0x1p+0 1 1
-1 -0x1.fffffffffffffp-1 -0x1p-1 1 1
1 0x1.fffffffffffffp-1 0x1p-1 1 1
1 0x1p+0 0x1p+0 1 1
1 0x1.0000000000001p+0 0x1p+0 1 1
-42 -0x1.5000000000001p+5 -0x1p+5 1 1
-42 -0x1.5p+5 -0x1p+5 1 1
-42 -0x1.4ffffffffffffp+5 -0x1p+5 1 1
42 0x1.4ffffffffffffp+5 0x1p+5 1 1
42 0x1.5p+5 0x1p+5 1 1
42 0x1.5000000000001p+5 0x1p+5 1 1
-inf -inf -0x1p-1 1 1
-1.79769e+308 -0x1.fffffffffffffp+1023 -0x1p+1023 1 1
-1.79769e+308 -0x1.ffffffffffffep+1023 -0x1p+1023 1 1
1.79769e+308 0x1.ffffffffffffep+1023 0x1p+1023 1 1
1.79769e+308 0x1.fffffffffffffp+1023 0x1p+1023 1 1
inf inf 0x1p-1 1 1
nan nan nan 1 1
Run Code Online (Sandbox Code Playgroud)
1来自OP的"获得幅度的基数2对数,向下舍入,使用例如...... frexp".
2从OP的"使用例如...... ldexp(1.0,n)将2提升到n次幂".
| 归档时间: |
|
| 查看次数: |
221 次 |
| 最近记录: |