【问题标题】:Fixed-point casting 16 to 64-bits?定点转换 16 到 64 位?
【发布时间】:2019-11-07 14:36:12
【问题描述】:

16 位数字的定点转换宏,具有最大值和最小值:

#define SCALEFACTOR_16(N) ( 1U << N )
#define Q_MAX16 (  SCALEFACTOR_16(16-1) - 1U )
#define Q_MIN16 ( -SCALEFACTOR_16(16-1)      )

将最小值转换为 64 位:

int64_t x = (int64_t)Q_MIN16;

给:
x == 0x0000 0000 ffff 8000
这是一个正数,而不是我的预期。

解决方法是将1U改为1UL

#define SCALEFACTOR_16(N) ( 1UL << N )

在这种情况下,输出正常:
x == 0xffff ffff ffff 8000

为什么第一个案例没有按预期工作?演员阵容期间会发生什么?

【问题讨论】:

    标签: c fixed-point


    【解决方案1】:

    您的系统有 32 位 (unsigned) int。您正在执行的所有工作都是 32 位值,并且您在完成工作后进行 。当您从unsigned int 转换为int64_t 时,它不会更改值(它不会将unsigned 的高位解释为要扩展的符号位),因此它会被零填充。

    【讨论】:

      【解决方案2】:

      1U 整数常量的类型为 unsigned int。移位操作的结果类型是其(提升的)左操作数,在本例中为 unsigned int

      虽然对无符号类型执行位移是正确的方法,但是在完成移位之后,您需要转换回预期的有符号类型。否则,转换为 int64_t 不会“符号扩展”数字,因为编译器会看到无符号类型。

      请注意-SCALEFACTOR_16 出于同样的原因是可疑的,它实际上并没有做任何事情,因为一元减号的操作数是无符号的。当从无符号类型正确转换为有符号时,编译器会自动处理符号,所以不需要-

      SCALEFACTOR_16也有bug,需要将宏参数括在括号中。

      解决方案:

      #define SCALEFACTOR_16(N) ( 1U << (N) )
      #define Q_MAX16 ( (int16_t)(SCALEFACTOR_16(16-1) - 1U) )
      #define Q_MIN16 ( (int16_t)(SCALEFACTOR_16(16-1)     ) )
      

      您也可以轻松地使这个宏变得非常通用:

      #define SCALEFACTOR(N) ( 1U << (N) )
      #define Q_MAX(N) ( (int##N##_t)( SCALEFACTOR(N-1) - 1U ) )
      #define Q_MIN(N) ( (int##N##_t)( SCALEFACTOR(N-1)      ) )
      

      完整示例:

      #include <stdio.h>
      #include <stdint.h>
      #include <inttypes.h>
      
      #define SCALEFACTOR(N) ( 1U << (N) )
      #define Q_MAX(N) ( (int##N##_t)(  SCALEFACTOR(N-1) - 1U ) )
      #define Q_MIN(N) ( (int##N##_t)( -SCALEFACTOR(N-1)      ) )
      
      int main (void)
      {
        int64_t x;
        x = Q_MIN(16);
        printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
      
        x = Q_MIN(32);
        printf("%.16"PRIx64 " %"PRIi64 "\n", x, x);
      }
      

      【讨论】:

      • “移位操作的结果类型是其(提升的)左操作数,在本例中为 unsigned int”。你的意思是哪个左操作数在这里是 uint?
      • @Danijel 只有一个班次。 1U &lt;&lt; N 的左操作数是1U
      • 好的,对不起,我想你指的是=左边的一些变量。
      【解决方案3】:

      因为您将 32 位无符号值 (0xFFFF 8000) 转换为 64 位有符号值 (0x0000 0000 FFFF 8000)。将无符号值转换为更大的类型只会在前面添加 0。将有符号值转换为更大的类型会将符号位添加到前面,例如:

      (int64_t)(int32_t)Q_MIN16; ==> 0xffff ffff ffff 8000
      

      【讨论】:

        猜你喜欢
        • 2010-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-22
        • 1970-01-01
        • 2018-10-06
        • 2013-03-05
        相关资源
        最近更新 更多