floating-point - 如何在 C 中将浮点数转换为 16 位有符号整数小数?
问题描述
我正在使用 NXP 为其 Arm M4F 提供的库中的宏将浮点类型变量转换为名为 frac16_t 的库数据类型,当浮点值小于 -1 时它不起作用。frac16_t 被 typedef 为有符号短。
宏代码为:
#define FRAC16(x) ((frac16_t)((x) < 0.999969482421875 ? ((x) >= -1 ? (x)*0x8000 : 0x8000) : 0x7fff))
该宏的预期行为是将 -1 和 +1 之间的任何浮点值转换为 16 位有符号整数,表示从 -1 到 (1 - 1/2^15) 的范围,其中 0x8000 作为 -1 值,0x7fff 和近1个值。如果浮点值大于(几乎)1,则结果在 0x7fff 处饱和,当浮点值小于 -1 时,结果应为 0x8000。
实际发生的是,对于任何小于 -1 的输入,结果都是 0x7fff(即接近 1),对于任何其他值,它都像宣传的那样工作。
我确实发现将 0x8000 常量转换为 frac16_t 类型可以使宏正常工作,但我不明白为什么原始库宏不起作用。将常量更改为 -32768 也有效,这两个修复程序都会导致常量被编码为 32 位长,这需要从加载指令附近的闪存中的某处间接加载该值,而不是作为 16 位文字加载,这是操作说明。
解决方案
这两个修复都导致常量被编码为 32 位长,这需要从闪存中的某处间接加载该值
不完全的。十六进制常量被转换double
为signed short
.
首先与test ? some_type_A : some_type_B
,结果是一个常见的类型。在这种情况下,double
。
(x)*0x8000
是a double
(or float
),然后: 0x8000
又: 0x7fff
变成同样的浮点类型。
0x8000
变成 32768.0。将超出范围分配double
给signed short
UB。
常见的 UB 是超出范围的值采用最小/最大限制。
在 OP 的情况下double
,32768.0 变为signed short
32767。
#define FRAC16(x) \\
((frac16_t)((x) < 0.999969482421875 ? ((x) >= -1 ? (x)*0x8000 : 0x8000) : 0x7fff))
// ^^^^^^
// 32768.0
与其将 32768.0 分配给 asigned short
并调用undefined behavior,不如将 -32768.0 分配给已定义的行为。
#define FRAC16(x)
((frac16_t)((x) < 0.999969482421875 ? ((x) >= -1 ? (x)*0x8000 : -32768 : 0x7fff))
// ^^^^^^^
// -32768.0
如果想用 编码SHRT_MIN
,不要使用0x8000
,使用SHRT_MIN
or (-0x7fff - 1)
。
推荐阅读
- ubuntu - 如何在 Ubuntu 18.04 的 PhpStorm 中设置 Super+comma 快捷方式?
- javascript - 使用 Material UI 和 React 的动态头像
- javascript - 如何配置“webpack”?JavaScript
- javascript - 如何在运行时使用 jquery 创建 json 对象数组?
- c++ - STL 算法和 back_inserter 可以预先分配空间吗?
- python - 如何将附加列表存储到python中的.txt文件中
- python-2.7 - 杀死一个从 tkinter 开始的 shell 命令
- java - Dropwizard:无法提供静态 HTML
- windows - Jenkins ec2 插件 - windows 代理很慢
- reactjs - 使用别名而不是相对路径创建的打字稿声明文件