Embedded 嵌入负数除法

Embedded 嵌入负数除法,embedded,division,negative-number,Embedded,Division,Negative Number,在我从事嵌入式编程的所有岁月中,我通常从不需要处理负数。这太疯狂了,但它们在我的工作领域里并不经常出现 我目前正在处理一个传感器读数,可以是正的,也可以是负的,需要按0.006缩放,保留符号。为了避免在运行时进行不必要的浮点计算,我有一个算法可以将其转换为分子和分母(3/500)。正数的情况下,一切正常,但负数的情况如下: Raw data: -103 Multiplied by 3: -309 Divided by 500: 36893488147419102 我找到了

在我从事嵌入式编程的所有岁月中,我通常从不需要处理负数。这太疯狂了,但它们在我的工作领域里并不经常出现

我目前正在处理一个传感器读数,可以是正的,也可以是负的,需要按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)中:

原始
36893488147419102
是SpeedCrunch结果的不可分割部分
0x83126E978D4FDE

我不想每次用负数除法时,都要先把符号保存下来,再进行正数除法,然后再把符号加回去。这是怎么回事

环境是使用c++11的CortexM3 micro、GCC4.9.3。计算是在
int64\u t
上进行的,分子/分母是
uint64\u t

编辑: 下面是回应Michael评论的代码片段:

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

data *= resolutionNumerator;
data /= resolutionDenominator;

具有相同宽度的有符号整数和无符号整数的运算,例如
uint64\u t
int64\u t
,会导致有符号操作数转换为无符号操作数的类型

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

  • (int64_t)-103*(uint64_t)3/(uint64_t)500
  • (uint64-t)-103*(uint64-t)3/(uint64-t)500
如果有符号类型
int64\t
用于分子和分母,结果将保留符号

这是怎么回事

当您将它从无符号类型强制转换为有符号类型时,2的互补表示中的负数保留了前导1位

通过将最终结果强制转换回有符号值,可以恢复预期结果。作为有符号值,前导的1位表示其为负值


我们只能说可能,因为我们没有看到常规。迈克尔在评论中也指出了这一点

C/C++的整数提升规则意味着有符号类型被提升为无符号类型。这就是为什么
-1>1

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

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

您没有执行上述回复中提到的演员阵容;但编译器确实执行了整体升级。对于您所观察到的,这是相同的区别。

我知道您说“计算是在……上完成的”,但为了消除任何猜测,您应该真正显示表达式的实际来源所有这些数字都基于其他地方的表格和原始数据。这是一个非常通用的代码,没有任何“神奇的数字”。但是,我将其压缩并添加了一个片段。使用混合数据类型的表达式通常是一个非常糟糕的主意。您应该始终争取类型一致性,如果这是不可行的(在本例中不是),则应该使用显式强制转换来指示类型不一致是有意的。该语言定义的隐式转换和类型升级可能无法满足您的期望或需要(如本例中所示)。您的传感器提供的数据的分辨率不太可能保证为64位,如果除以0.0006,则在任何情况下都会丢弃超过10位的信息。您确定需要64位还是这是执行缩放的正确位置?通常情况下,您只能以“真实世界”单位缩放数据以进行表示。内部计算最好在传感器数据的完全分辨率下进行。是的,你说得对。这个传感器只有16位。然而,这是一个非常共享的代码,不同的传感器可以提供高达64位的数据。每个传感器读数都有一个配置,允许您通过乘以10或100等来获得更高的分辨率,唯一的目的是避免浮点运算和转换为单个应用程序关心的“真实”单位。0x0083126E978D4FDE(结果)没有前导
1
位。选角没用。这里没有自定义的数学例程。只是乘法和除法。是的,浮点运算和这个问题几乎没有关系。这与浮点无关。顺便说一句,在我的目标上,浮点数学(软件实现)的成本是整数数学的24倍。由于这段代码每秒运行250次,我有动力避免浮点运算。太糟糕了?首先,我实施了“黑客”,在发布之前修复了这个问题。问题是为什么简单的除法不起作用。第二,为什么任何人都必须编写自定义例程来处理分割否定?数学就是数学。我愿意相信。是的,对不起,我的语气。我试图编辑评论,但有5分钟的限制。我不是故意那样说的。那件事肯定令人困惑。感谢您的帮助。aa现在,整个评论线程都引用了您编辑的内容。哦,好吧,你的答案现在更切题了。将分子和分母切换到
uint32\u t
,我所有的单元测试都通过了。谢谢
int64_t data = -103;
uint64_t resolutionNumerator = 3;
uint64_t resolutionDenominator = 500;
int i = -1;
unsigned int j = i;

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