c – 阈值是绝对值
我有以下功能:
char f1( int a,unsigned b ) { return abs(a) <= b; } 对于执行速度,我想重写如下: char f2( int a,unsigned b ) { return (unsigned)(a+b) <= 2*b; } // redundant cast 或者使用此签名,即使对于非负b,也可能具有微妙的含义: char f3( int a,int b ) { return (unsigned)(a+b) <= 2*b; } 这两种替代方案都可以在一个平台上进行简单的测试,但我需要便携式.假设非负b并且没有溢出风险,这是典型硬件和C编译器的有效优化吗?它对C也有效吗? 注意:作为带有-O3的gcc 4.8 x86_64上的C,f1()使用6个机器指令而f2()使用4. f3()的指令与f2()的指令相同.同样有趣的是:如果b作为文字给出,则两个函数都编译为3条指令,这些指令直接映射到f2()中指定的操作. 解决方法
从带有签名的原始代码开始
char f2( int a,unsigned b ); 这包含表达式 a + b 由于其中一个操作数具有signed,另一个(对应的)无符号整数类型(因此它们具有相同的“整数转换等级”),因此 – 遵循“常用算术转换”(第6.3.1.8节) – 操作数有符号整数类型转换为另一个操作数的无符号类型. 即使有问题的值无法用新类型表示,也可以很好地定义转换为无符号整数类型:
脚注60只是说所描述的算术与数学值一起工作,而不是键入的算术. 现在,使用更新的代码 char f2_updated( int a,int b ); // called f3 in the question 事情会有所不同.但由于b被假定为非负数,并且假设INT_MAX <= UINT_MAX,您可以将b转换为无符号,而不必担心它之后具有不同的数学值.因此你可以写 char f2_updated( int a,int b ) { return f2(a,(unsigned)b); // cast unnecessary but to make it clear } 再看f2,表达式2 * b进一步限制了b的允许范围不大于UINT_MAX / 2(否则数学结果将是错误的). 注意:无符号类型不会溢出,它们会根据模运算“换行”. N1570的报价(C11工作草案) 最后一句话: IMO是编写此函数的唯一合理选择 #include <stdbool.h> #include <assert.h> bool abs_bounded(int value,unsigned bound) { assert(bound <= (UINT_MAX / 2)); /* NOTE: Casting to unsigned makes the implicit conversion that otherwise would happen explicit. */ return ((unsigned)value + bound) <= (2 * bound); } 对绑定使用带符号的类型没有多大意义,因为值的绝对值不能小于负数. abs_bounded(value,something_negative)总是假的.如果有可能出现负面界限,那么我会在这个函数之外捕获它(否则它会“太多”),如: int some_bound; // ... if ((some_bound >= 0) && abs_bounded(my_value,some_bound)) { // yeeeha } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |