定点转换 16 位到 64 位?
Fixed-point casting 16 to 64-bits?
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
为什么第一个案例没有按预期工作?施法期间会发生什么?
您的系统是 32 位 (unsigned
) int
。您正在执行的所有工作都是使用 32 位值,并且您在 after 完成工作后进行转换。当您从 unsigned int
转换为 int64_t
时,它不会更改值(它不会将 unsigned
的高位解释为要扩展的符号位),因此它填零。
因为您正在将 32 位无符号值 (0xFFFF 8000) 转换为 64 位有符号值 (0x0000 0000 FFFF 8000)。将无符号值转换为更大的类型只会在前面添加 0。将有符号值转换为更大的类型会将符号位添加到前面,例如:
(int64_t)(int32_t)Q_MIN16; ==> 0xffff ffff ffff 8000
1U
整数常量的类型为 unsigned int
。移位操作的结果类型是其(提升的)左操作数的类型,在本例中为 unsigned int
.
尽管对无符号类型执行位移位是正确的方法,但完成移位后,您需要转换回预期的有符号类型。否则转换为 int64_t
不会 "sign extend" 编译器看到无符号类型的数字。
请注意 -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);
}
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
为什么第一个案例没有按预期工作?施法期间会发生什么?
您的系统是 32 位 (unsigned
) int
。您正在执行的所有工作都是使用 32 位值,并且您在 after 完成工作后进行转换。当您从 unsigned int
转换为 int64_t
时,它不会更改值(它不会将 unsigned
的高位解释为要扩展的符号位),因此它填零。
因为您正在将 32 位无符号值 (0xFFFF 8000) 转换为 64 位有符号值 (0x0000 0000 FFFF 8000)。将无符号值转换为更大的类型只会在前面添加 0。将有符号值转换为更大的类型会将符号位添加到前面,例如:
(int64_t)(int32_t)Q_MIN16; ==> 0xffff ffff ffff 8000
1U
整数常量的类型为 unsigned int
。移位操作的结果类型是其(提升的)左操作数的类型,在本例中为 unsigned int
.
尽管对无符号类型执行位移位是正确的方法,但完成移位后,您需要转换回预期的有符号类型。否则转换为 int64_t
不会 "sign extend" 编译器看到无符号类型的数字。
请注意 -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);
}