嵌入式 C Cortex-M4:正确处理大数除法?

Embedded C Cortex-M4: Properly handle division by big numbers?

我正在为光谱学编写嵌入式代码。 为了构建我的频谱,我需要将样本从一个区间(动态范围由问题的 physics/specs 给出)线性映射到另一个区间。基本上在处理数据后,我有一系列样本(峰值),它们中的每一个都会对频谱产生影响(即,将增加直方图中特定 bin 的计数器)。 这是一个草图: 因此,在 C 语言中,我需要将每个峰值映射到 [0:4095],并且我在 MCU (LPC4370) 上实时执行此操作,因此我需要快速进行。 问题是我的愚蠢实现将所有内容压缩为 0。 这是我所做的:

 #define MCA_SIZE     4096
 #define PEAK_MAX     1244672762
 #define PEAK_MIN     6000000

 int32_t mca[MCA_SIZE];
 int32_t peak_val;
 int32_t bin_val;

[...]

 if(peak_val > PEAK_MIN)
      {
       bin_val = (int)(MCA_SIZE*(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN));

       /*Increment corrispondent multi channel bin*/
       mca[bin_val]+=1;
      };

如果小写,每个数量都是 int32,#define 是大写。问题是相信这个

(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN)

经常接近于零。 所以我最终只填满了第一个或两个垃圾箱。

这是几千次迭代后 mca 的第一个值的屏幕截图:

这是正在研究的代码的无序视图,以及断点处的寄存器状态。

处理这种问题的best/fastest方法是什么?

请注意,您的代码可能会产生有符号整数溢出,这在标准中是未定义的。

来自 C99 标准 (§3.4.3/1)

An example of undefined behavior is the behavior on integer overflow

所以我会从那里开始,要么转向无符号,使用更宽的类型,要么改变边界。

此外,正如 user6556709 在评论中提到的,表达式:

(MCA_SIZE*(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN))

由于这些运算符组(注意括号)的从左到右的结合性,保证像下面这样写一样执行:

((MCA_SIZE*(peak_val-PEAK_MIN))/(PEAK_MAX-PEAK_MIN))

所以始终为零计算的表达式 (peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN) 没有执行,表达式 (MCA_SIZE*(peak_val-PEAK_MIN)) 是先完成的,所以这不是主要问题。

我建议为 peak_val 提供一些垃圾箱未被填满的示例。

中间结果 (MCA_SIZE*(peak_val-PEAKMIN)) 对于 32 位整数数据类型来说太大了。我会使用 uint64_t 进行这些计算,我会将所有常量定义为 const uint64_t 而不是使用 #define,并在其字面值中添加后缀 ULL