我正在为光谱学编写嵌入式代码。为了构建我的光谱,我需要将一个间隔(动态范围由问题的物理/规格给出)的线性样本映射到另一个。基本上在处理数据之后,我有一系列样本(峰值),并且它们中的每一个都将对频谱有贡献(即,将增加直方图中特定二进制位的计数器)。这是一个草图:所以在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)
经常接近于零。所以我最终只填充了第一个或两个箱子。
这是对正在研究的代码的不可思议的看法,以及断点处的寄存器状态。
处理这类问题的最佳/最快方法是什么?
对于32位整数数据类型,中间结果(MCA_SIZE*(peak_val-PEAKMIN))
太大。我会使用uint64_t进行这些计算,我会将所有常量定义为const uint64_t
,而不是使用#define
,将ULL
的后缀添加到它们的文字值。
请注意,您的代码可能会产生有符号整数溢出,这在标准中是未定义的。
来自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
提供一些不填充垃圾箱的例子。