我发现了一个实现,其中为了获得值x的四分之一,使用以下代码在arm 32位处理器上运行。

   //global typedef
   typedef unsigned char  uint8;

   //Function definition
   uint8 FindQuarter(void)
   {
     uint8  value, OneQuarter,ThreeQuarter;
     value = 100;
     OneQuarter = (value * 64) / 255;// why not "(value * 1)/4" or "value/4"
     ThreeQuarter = (value *192) /255; //why not "(value * 3)/4"
     return 1;
   }

为什么有人想要使用64/255或192/255而不是1/4或3/4,尽管两者都会给出大致相同的结果。
注:计算精度在这里不是最重要的,允许有一点偏差。

最佳答案

原著作者所说的“四分之一”是什么意思?当计算某些值时,会出现一个模式:

f(0) = 0x00 (0)
f(1) = 0xC0 (192)
f(2) = 0x80 (128)
f(3) = 0x40 (64)
f(4) = 0x00 (0)
f(5) = 0xC0 (192)
...
f(254) = 0x80 (128)
f(255) = 0x40 (64)

这可以解释为给每个输入值分配一个字节域的“四分之一”,其中每个四分之一由该子集中的最低值定义。(这当然不是四除一。)
编辑
上面的答案不准确(最多)或者更可能是不正确的。
根据一条评论,我对f()的实现似乎不正确,计算的/ 255部分被“优化”,并作为-1的有符号除法执行。
typedef unsigned char  uint8;
int main (void)
{
    short ui16Value;
    for(ui16Value = 0; ui16Value < 0x100; ui16Value++)
    {
        uint8 value = (uint8)ui16Value;
        // definition of f():
        uint8 quarter =  (value * 64) / 255;
        printf("f(%d) = 0x%2.2X (%u)\r\n", value, quarter, quarter);
    }
    return 0;
}

拆卸:
!        uint8 quarter =  (value * 64) / 255;
0xF48: MOV.B [W14+2], W5
0xF4A: MOV #0xC0, W4      <-- this looks odd.
0xF4C: MUL.SS W5, W4, W4
0xF4E: MOV.B W4, [W14+3]

上面突出显示的行看起来像是一个运算符精度问题,在方括号中的乘法之前,64被255==0xff==-1除以。
显式地将该值声明为无符号会导致所有值都为零。
!        uint8 quarter =  (value * 64) / (uint8)255;
0xF48: MOV.B [W14+2], W4
0xF4A: ZE W4, W4
0xF4C: SL W4, #6, W5
0xF4E: MOV #0xFF, W4
0xF50: REPEAT #0x11
0xF52: DIV.SW W5, W4
0xF54: MOV W0, W4
0xF56: MOV.B W4, [W14+3]

我可能需要查看正在使用的编译器版本的勘误表,或者尝试编译目标micrcontroller而不是模拟器。不管怎样,这对我来说都是件有趣的事情。

07-24 09:45
查看更多