嵌入式C Cortex-M4:正确处理大数字划分?

问题描述 投票:2回答:2

我正在为光谱学编写嵌入式代码。为了构建我的光谱,我需要将一个间隔(动态范围由问题的物理/规格给出)的线性样本映射到另一个。基本上在处理数据之后,我有一系列样本(峰值),并且它们中的每一个都将对频谱有贡献(即,将增加直方图中特定二进制位的计数器)。这是一个草图:Peaks to Hist mapping所以在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;
      };

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

(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN)

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

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

这是对正在研究的代码的不可思议的看法,以及断点处的寄存器状态。

Disassembly view

处理这类问题的最佳/最快方法是什么?

c embedded fixed-point integer-division
2个回答
3
投票

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


1
投票

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

来自C99标准(§3.4.3/ 1)

未定义行为的一个示例是整数流上的行为

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

另外,正如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提供一些不填充垃圾箱的例子。

© www.soinside.com 2019 - 2024. All rights reserved.