带负数的嵌入式除法

时间:2015-12-11 19:42:01

标签: embedded division negative-number

在我多年的嵌入式编程中,我一般都不需要使用负数。这很疯狂,但他们在我的工作中经常不会出现。

我目前处理的传感器读数可以是正数或负数,需要按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

编辑: 以下是迈克尔评论中的代码段:

int64_t data = -103;
uint64_t resolutionNumerator = 3;
uint64_t resolutionDenominator = 500;

data *= resolutionNumerator;
data /= resolutionDenominator;

2 个答案:

答案 0 :(得分:3)

具有相同宽度的有符号和无符号整数的运算(例如uint64_tint64_t)会导致已签名的操作数转换为无符号操作数的类型。

因此这两个表达式是等价的:

  • (int64_t) -103 * (uint64_t) 3 / (uint64_t) 500
  • (uint64_t) -103 * (uint64_t) 3 / (uint64_t) 500

如果签名类型int64_t用于分子和分母,结果将保留符号。

答案 1 :(得分:1)

  

这里发生了什么?

当你将它从无符号类型转换为有符号类型时,前导的1位仍为2的恭维表示中的负数。

可能能够通过将最终结果转换回签名值来恢复预期结果。作为有符号值,前导1位将表示其为负值。

我们只能说可能,因为我们还没有看到例程。迈克尔在评论中指出了相同的内容。

int64_t data = -103;
uint64_t resolutionNumerator = 3;
uint64_t resolutionDenominator = 500;

C / C ++的整数提升规则意味着签名类型被提升为无符号类型。其原因-1 > 1

int i = -1;
unsigned int j = i;

if ( i > j )
    printf("-1 is greater than 1\n");

您没有执行上述回复中提到的演员表;但编译器 执行整数提升。对于你所观察到的,它有相同的区别。