简体   繁体   English

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM