有符号零的最小值和最大值

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 minpsmaxps指令.

以下是结果(我用来测试的代码发布在下面)

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.0fmax(-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指令(faminfamax),在这种情况下,据我所知(从读取),在这种情况下它返回第二个参数.这不是什么minps,maxps似乎也在做什么.奇怪的是,_mm_min_ps(-0.0,0.0) = 0.0_mm_max_ps(-0.0,0.0) = -0.0.我希望他们要么在两种情况下都返回第一个参数,要么在第二种情况下返回 为什么以这种方式定义minpsmaxps指令?

#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.

too*_*ite 1

为什么不自己阅读该标准呢?IEEE的维基百科文章包含该标准的链接。

注意:C标准文档不是免费提供的。但最终草案是(这就是我链接的内容,搜索找到 pdf 版本)。然而,我还没有看到这里引用的最终文件,而且据我所知,那里大部分都纠正了一些拼写错误;没有改变。不过,IEEE 是免费提供的。

请注意,编译器不需要遵守标准(例如,某些嵌入式编译器/版本不实现符合 IEEE 的浮点值,但仍然符合 C - 只需阅读标准以了解详细信息)。所以请查看编译器文档来查看兼容性。例如,MS-VC 甚至不兼容 C99(并且永远不会兼容),而 gcc 和 clang/llvm (大部分)在当前版本中与 C11 兼容(gcc 至少从 4.9.2 开始,部分从 4.7 开始)。

一般来说,在使用 MS-VC 时,请检查它是否确实支持所使用的所有标准功能。它实际上并不完全符合当前标准,也不完全符合C99。