嵌入式 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
。
我正在为光谱学编写嵌入式代码。
为了构建我的频谱,我需要将样本从一个区间(动态范围由问题的 physics/specs 给出)线性映射到另一个区间。基本上在处理数据后,我有一系列样本(峰值),它们中的每一个都会对频谱产生影响(即,将增加直方图中特定 bin 的计数器)。
这是一个草图:
#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
。