[英]Embedded C Cortex-M4: Properly handle division by big numbers?
I'm writing embedded code for spectroscopy. 我正在编写光谱的嵌入式代码。 In order to build my spectrum, I need to map linearly samples from an interval (dynamic range is given by the physics/specs of the problem) to another.
为了建立光谱,我需要将一个区间(动态范围由问题的物理/规格给定)中的线性样本映射到另一个区间。 Basically after data is processed I have a series of samples (peaks) and every one of them will contribute to the spectrum (ie will increment the counter of a specific bin in a histogram).
基本上,在处理完数据后,我会有一系列样本(峰值),并且每个样本都会对频谱有所贡献(即将增加直方图中特定bin的计数器)。 Here's a sketch:
这是一个草图:
So in C, I need to map each peak value into the [0:4095] and I'm doing this in real-time on a MCU (LPC4370) so I need to go fast.
因此,在C语言中,我需要将每个峰值映射到[0:4095],并且正在MCU(LPC4370)上实时进行此操作,因此我需要快速进行操作。 The problem is that my dumb implementation is squeezing everything to 0. here's what i did:
问题是我愚蠢的实现将所有内容都压缩为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;
};
Where every quantity is int32 if lower cas, #define is upper case. 如果小写cas中每个数量都是int32,则#define是大写字母。 The problem is that is believe this one
问题是相信这一个
(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN)
Goes very often near zero. 经常接近零。 So I end-up having just the first one or two bins filled.
所以我最后只装了一个或两个垃圾箱。
Here's a screenshot of first values of mca after few thousand iterations: 这是几千次迭代后的mca第一个值的屏幕截图:
Here's the disassbly view of the code under study, along with register status at breakpoint. 这是正在研究的代码的绝妙视图,以及断点处的寄存器状态。
What is the best/fastest way to handle this kind of problem? 解决此类问题的最佳/最快方法是什么?
The intermediate result (MCA_SIZE*(peak_val-PEAKMIN))
is too large for a 32-bit integer datatype. 对于32位整数数据类型,中间结果
(MCA_SIZE*(peak_val-PEAKMIN))
太大。 I would use uint64_t for these calculations, and I would define all of your constants as const uint64_t
rather than using a #define
, adding a suffix of ULL
to their literal values. 我将使用uint64_t进行这些计算,并且将所有常量定义为
const uint64_t
而不是使用#define
,在其字面值中添加ULL
后缀。
Please note that your code is likely to produce signed integer overflow, which is undefined in the standard. 请注意,您的代码可能会产生带符号的整数溢出,这在标准中是未定义的。
From the C99 standard (§3.4.3/1) 根据C99标准(§3.4.3/ 1)
An example of undefined behavior is the behavior on integer overflow
未定义行为的一个示例是整数溢出时的行为
So I would start there, either move to unsigned, use a wider type or change the boundaries. 因此,我将从此处开始,或者移动到无符号的,使用更广泛的类型或更改边界。
Also, as user6556709
mentioned in it's comment, the expression: 另外,正如
user6556709
在其注释中所述,表达式:
(MCA_SIZE*(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN))
Is guaranteed to be executed as if it was written as follows, due to left-to-right associativity for those group of operators (note the parentheses): 由于这些运算符组从左到右的关联性(请注意括号),保证可以按如下方式执行:
((MCA_SIZE*(peak_val-PEAK_MIN))/(PEAK_MAX-PEAK_MIN))
So the always-zero-evaluated expression (peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN)
is not performed, the expression (MCA_SIZE*(peak_val-PEAK_MIN))
is done prior, so that is not the main problem. 因此,不会执行始终为零的表达式
(peak_val-PEAK_MIN)/(PEAK_MAX-PEAK_MIN)
,该表达式(MCA_SIZE*(peak_val-PEAK_MIN))
执行,因此这不是主要问题。
I would recommend providing some examples for peak_val
in which bins are not filled. 我建议为不填充垃圾箱的
peak_val
提供一些示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.