Minimum and maximum of signed zero
我担心以下情况
1 2 3 4 | min(-0.0,0.0) max(-0.0,0.0) minmag(-x,x) maxmag(-x,x) |
根据维基百科,IEEE 754-2008关于最小和最大
The min and max operations are defined but leave some leeway for the case where the inputs are equal in value but differ in representation. In particular:
min(+0,?0) or min(?0,+0) must produce something with a value of zero but may always return the first argument.
我做了一些测试,比较
1 2 3 4 5 6 7 8 | #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; }) |
和
结果如下(我用来测试此代码的代码发布在下面)
1 2 3 4 5 6 | 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 |
如您所见,每种情况都会返回不同的结果。所以我的主要问题是C和C ++标准库怎么说?
maxmag Returns x if | x| > |y|, or y if |y| > |x|, otherwise fmax(x, y).
minmag Returns x if |x| < |y|, or y if |y| < |x|, otherwise fmin(x, y).
x86指令集没有minmag和maxmag指令,因此我必须实现它们。但就我而言,我需要性能,并且为幅度相等的情况创建分支效率不高。
Itaninum指令集具有minmag和maxmag指令(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #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 ", c[0], c[1], c[2], c[3]); } { float c[4]; _mm_store_ps(c,d4); printf("%f %f %f %f ", c[0], c[1], c[2], c[3]); } printf("%f %f %f %f ", 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 ", 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 ", 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 ", 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 |
编辑:
关于C ++,我测试了
为什么不自己阅读标准? IEEE的Wikipedia文章包含该标准的链接。
注意:C标准文档不是免费提供的。但是最终草案是(这就是我链接的内容,搜索以找到pdf版本)。但是,我还没有看到这里引用的最终文档,并且AFAIK大部分都纠正了一些错别字。没有改变。但是,IEEE是免费提供的。
请注意,编译器不必遵守标准(例如,某些嵌入式编译器/版本未实现符合IEEE的浮点值,但仍符合C语言-只需阅读标准即可了解详细信息)。因此,请参阅编译器文档以了解兼容性。例如,MS-VC甚至与C99不兼容(并且永远都不会变本加厉),而gcc和clang / llvm(在大多数情况下)与当前版本中的C11兼容(至少从4.9.2版开始,gcc从4.7版开始)。
通常,在使用MS-VC时,请检查它是否确实支持所使用的所有标准功能。它实际上不完全符合当前标准,也不完全符合C99。
在这种情况下,基本问题是实际的基础数学,而忽略了表示问题。我认为您的问题中有几个含义是错误的。 -0.0 <0.0为假。 -0.0是负数是假的。 0.0为正数则为假。实际上,虽然存在IEEE 754表示为零且带有符号位的情况,但实际上没有-0.0这样的东西。
此外,最小/最大函数的行为只是合法浮点运算的一小部分,可以产生具有不同符号位的零。由于浮点单位可以自由地为表达式-7--7返回(-)0.0,因此您还必须弄清楚该怎么做。我还要指出的是| 0.0 |实际上-可能会在设置了符号位的情况下返回0.0,因为-0.0是绝对值0.0。简而言之,就数学而言,0.0是-0.0。他们是一样的东西。
可以使用设置的符号位测试0.0的唯一方法是放弃数学表达式,而是检查此类值的二进制表示形式。但是,这有什么意义呢?我只能想到一种合理的情况:从两台不同的机器生成二进制数据,这些机器必须逐位相同。在这种情况下,您还需要担心信令和安静的NaN值,因为这些值还有很多别名(单精度浮点数的10 ^ 22-1 SNaN和10 ^ 22 QNaN的别名,大约10 ^双精度各取51个值)。
在这些情况下,二进制表示很关键(绝对不是数学计算),那么您将必须编写代码以在写入时调节所有浮点数(零,安静的NaN和发出信号的NaN)。
对于任何计算目的,不必担心符号位是置位还是零值清零。