【发布时间】:2015-12-11 19:42:01
【问题描述】:
在我从事嵌入式编程的所有岁月中,我通常从不需要使用负数。这很疯狂,但他们只是在我的工作中不经常出现。
我目前正在处理一个传感器读数,它可以是正数或负数,需要按 0.006 缩放,保留符号。为了避免在运行时进行不必要的浮点计算,我有一个算法可以将其转换为分子和分母 (3/500)。正数情况下一切正常,但负数情况如下:
Raw data: -103
Multiplied by 3: -309
Divided by 500: 36893488147419102
我知道这个数字是从哪里来的,我有一个解决方法,但我宁愿相信数学就是数学。
这是相同的十六进制计算:
Raw data: 0xFFFFFFFFFFFFFF99
Multiplied by 3: 0xFFFFFFFFFFFFFECB
Divided by 500: 0x0083126E978D4FDE
在计算器中 (SpeedCrunch):
0xFFFFFFFFFFFFFECB/500 = 0x83126E978D4FDE.9D2F1A9FBE76C8B44
原来的 36893488147419102 是 SpeedCrunch 结果的组成部分 0x83126E978D4FDE。
我不想保存符号,做一个正除法,然后在每次用负数除法时重新添加符号。这是怎么回事?
环境是CortexM3 micro,GCC4.9.3,使用c++11。计算是在int64_t 上完成的,分子/分母是uint64_t。
编辑: 下面是响应 Michael 评论的代码 sn-p:
int64_t data = -103;
uint64_t resolutionNumerator = 3;
uint64_t resolutionDenominator = 500;
data *= resolutionNumerator;
data /= resolutionDenominator;
【问题讨论】:
-
我知道你说“计算是在……上完成的”,但为了消除任何猜测,你应该真正显示计算中涉及的表达式的实际来源以及类型对于涉及的任何变量。
-
所有这些数字都基于来自其他地方的表格和原始数据。这是非常通用的代码,在任何地方都没有“幻数”。但是,我将其浓缩并添加了一个sn-p。
-
具有混合数据类型的表达式通常是一个非常糟糕的主意。您应该始终争取类型一致,如果这是不切实际的(在这种情况下不是),您应该使用显式转换来表明类型不一致是故意的。该语言定义了可能无法满足您期望或需要的隐式转换和类型提升(如本例所示)。
-
您的传感器似乎不太可能以保证 64 位的分辨率提供数据,并且在任何情况下除以 0.0006 都会丢弃超过 10 位的信息。您确定需要 64 位还是这是执行缩放的正确位置?您通常只会缩放数据以以“真实世界”单位表示。内部计算最好在传感器数据的全分辨率下执行。
-
是的,你是对的。这个传感器只有 16 位。但是,这是非常共享的代码,不同的传感器可以提供高达 64 位的数据。每个传感器读数都有一个配置,可以通过乘以 10 或 100 等来获得更高的分辨率,其唯一目的是避免浮点数学和转换为各个应用程序关心的“真实世界”单位。
标签: embedded division negative-number