Z b*_*son 8 c c++ floating-point sse ieee-754
我担心以下情况
min(-0.0,0.0)
max(-0.0,0.0)
minmag(-x,x)
maxmag(-x,x)
Run Code Online (Sandbox Code Playgroud)
据维基百科IEEE 754-2008称,关于min和max
定义了最小和最大操作,但是对于输入值相等但表示不同的情况留有一些余地.特别是:
min(+ 0,-0)或min(-0,+ 0)必须产生值为零的东西,但可能总是返回第一个参数.
我做了一些测试比较fmin
,fmax
,最小值和最大值定义见下文
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
Run Code Online (Sandbox Code Playgroud)
并_mm_min_ps
和_mm_max_ps
其称之为SSE minps
和maxps
指令.
以下是结果(我用来测试的代码发布在下面)
fmin(-0.0,0.0) = -0.0
fmax(-0.0,0.0) = 0.0
min(-0.0,0.0) = 0.0
max(-0.0,0.0) = 0.0
_mm_min_ps(-0.0,0.0) = 0.0
_mm_max_ps(-0.0,0.0) = -0.0
Run Code Online (Sandbox Code Playgroud)
如您所见,每个案例都会返回不同的结果.所以我的主要问题是C和C++标准库说的是什么?是否fmin(-0.0,0.0)
必须相等-0.0
且fmax(-0.0,0.0)
必须相同0.0
或不同的实现允许以不同方式定义它?如果它的实现被定义,这意味着为了确保代码与C标准库的不同实现兼容(例如,来自不同的编译器),必须进行检查以确定它们如何实现min和max?
怎么样minmag(-x,x)
和maxmag(-x,x)
?这些都在IEEE 754-2008中定义.这些实现至少是在IEEE 754-2008中定义的吗?我从Wikepdia的min和max评论中推断出这些是实现定义的.但据我所知,C标准库并未定义这些功能.在OpenCL中,这些函数定义为
maxmag如果|返回x X | > | y |,或y如果| y | > | x |,否则为fmax(x,y).
minmag如果| x |则返回x <| y |,或y如果| y | <| x |,否则为fmin(x,y).
x86指令集没有minmag和maxmag指令,所以我必须实现它们.但在我的情况下,我需要表现并在大小相等的情况下为案例创建分支效率不高.
Itaninum指令集有minmag和maxmag指令(famin
和famax
),在这种情况下,据我所知(从读取),在这种情况下它返回第二个参数.这不是什么minps
,maxps
似乎也在做什么.奇怪的是,_mm_min_ps(-0.0,0.0) = 0.0
和_mm_max_ps(-0.0,0.0) = -0.0
.我希望他们要么在两种情况下都返回第一个参数,要么在第二种情况下返回 为什么以这种方式定义minps
和maxps
指令?
#include <stdio.h>
#include <x86intrin.h>
#include <math.h>
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
int main(void) {
float a[4] = {-0.0, -1.0, -2.0, -3.0};
float b[4] = {0.0, 1.0, 2.0, 3.0};
__m128 a4 = _mm_load_ps(a);
__m128 b4 = _mm_load_ps(b);
__m128 c4 = _mm_min_ps(a4,b4);
__m128 d4 = _mm_max_ps(a4,b4);
{ float c[4]; _mm_store_ps(c,c4); printf("%f %f %f %f\n", c[0], c[1], c[2], c[3]); }
{ float c[4]; _mm_store_ps(c,d4); printf("%f %f %f %f\n", c[0], c[1], c[2], c[3]); }
printf("%f %f %f %f\n", fmin(a[0],b[0]), fmin(a[1],b[1]), fmin(a[2],b[2]), fmin(a[3],b[3]));
printf("%f %f %f %f\n", fmax(a[0],b[0]), fmax(a[1],b[1]), fmax(a[2],b[2]), fmax(a[3],b[3]));
printf("%f %f %f %f\n", min(a[0],b[0]), min(a[1],b[1]), min(a[2],b[2]), min(a[3],b[3]));
printf("%f %f %f %f\n", max(a[0],b[0]), max(a[1],b[1]), max(a[2],b[2]), max(a[3],b[3]));
}
//_mm_min_ps: 0.000000, -1.000000, -2.000000, -3.000000
//_mm_max_ps: -0.000000, 1.000000, 2.000000, 3.000000
//fmin: -0.000000, -1.000000, -2.000000, -3.000000
//fmax: 0.000000, 1.000000, 2.000000, 3.000000
//min: 0.000000, -1.000000, -2.000000, -3.000000
//max: 0.000000, 1.000000, 2.000000, 3.000000
Run Code Online (Sandbox Code Playgroud)
编辑:
在关于C++我测试std::min(-0.0,0.0)
与std::max(-0.0,0.0)
和都返回-0.0
.这表明,这std::min
是不一样的fmin
,并std::max
是不一样的fmax
.
为什么不自己阅读该标准呢?IEEE的维基百科文章包含该标准的链接。
注意:C标准文档不是免费提供的。但最终草案是(这就是我链接的内容,搜索找到 pdf 版本)。然而,我还没有看到这里引用的最终文件,而且据我所知,那里大部分都纠正了一些拼写错误;没有改变。不过,IEEE 是免费提供的。
请注意,编译器不需要遵守标准(例如,某些嵌入式编译器/版本不实现符合 IEEE 的浮点值,但仍然符合 C - 只需阅读标准以了解详细信息)。所以请查看编译器文档来查看兼容性。例如,MS-VC 甚至不兼容 C99(并且永远不会兼容),而 gcc 和 clang/llvm (大部分)在当前版本中与 C11 兼容(gcc 至少从 4.9.2 开始,部分从 4.7 开始)。
一般来说,在使用 MS-VC 时,请检查它是否确实支持所使用的所有标准功能。它实际上并不完全符合当前标准,也不完全符合C99。
归档时间: |
|
查看次数: |
749 次 |
最近记录: |