Arduino 上数学运算的计时速度 - 异常
Timing speed of math operations on Arduino - anomaly
我在Arduino Uno上对整数除法进行了一些研究,并试图确定解决除法的最快方法。
在阅读中,我遇到了这篇文章。
我抓住并修改了Nick Gammon在回复#4中发布的草图,最终目的是编制我需要执行的计算列表及其时间。
这是我修改后的草图:
#define DATATYPE byte
#define OPERATION i / j
volatile DATATYPE x=0;
volatile DATATYPE y=0;
//volatile DATATYPE j=7;
unsigned long time;
unsigned long loop_time;
void setup ()
{
Serial.begin(115200);
Serial.println ();
time = micros();
for (DATATYPE i = 1; i < 101; i++) {
//for (DATATYPE j = 1; j < 101; j++) {
for (DATATYPE j = 56; j < 57; j++) {
y++;
} // end of for j
} // end of for i
loop_time = micros() - time;
Serial.print("Loop baseline Completion time: ");
Serial.print(loop_time);
Serial.print(" ");
time = micros();
for (DATATYPE i = 1; i < 101; i++) {
//for (DATATYPE j = 1; j < 101; j++) {
for (DATATYPE j = 56; j < 57; j++) {
y++;
x = OPERATION;
} // end of for j
} // end of for i
time = micros() - time;
Serial.print("Completion time: ");
Serial.print(time);
Serial.print(" Operation time: ");
time = time - loop_time;
Serial.println(time);
} // end of setup
void loop() {}
其输出为:
Loop baseline Completion time: 52 Completion time: 644 Operation time: 592
这基本上为使用字节的每个除法运算提供了 5usec 的时间。
但是,将两个循环从:
for (DATATYPE j = 56; j < 57; j++) {
自
for (DATATYPE j = 57; j < 58; j++) {
给出以下输出:
Loop baseline Completion time: 52 Completion time: 108 Operation time: 56
我已经为内部循环(7、56、58、3(等尝试了几种不同的值
3 给出了类似的结果,但 7、11 和 13 没有
谁能告诉我为什么执行手术所需的时间会有这么大的差异?
如果编译器知道除法中的分母是什么,它也许能够用乘法(乘以分母的倒数(和移位来计算除法。由于除法非常慢,即使在具有除法指令的CPU上,这种技术(通常称为倒数乘法(也可以是一个巨大的胜利。
不幸的是,有些分母比其他分母更容易优化,特别是当乘法限制为 16 位时。因此,您可能会看到具有不同常数除数的不同行为。
我发现编译器没有看到该循环可用的更好优化,即将临时设置为 0 并将其用作除法的结果。当i
达到 56(或视情况而定为 57(时,临时值将递增。我认为这将从根本上减少执行时间。
编译测试
好奇心让我受益匪浅,所以我安装了当前的 Ubuntu avr-gcc 软件包,即 v5.4.0,并尝试了一些编译。我的程序比原来的程序简单得多:
uint8_t dodiv(uint8_t d) {
return d / DIVISOR;
}
然后我用如下命令编译它:
avr-gcc -S -Wall -O3 -o - -mmcu=atmega32 -DDIVISOR=57 avrdiv.c
据我所知,-mmcu=atmega32
对于Arduino Uno是正确的。
以下是一些结果,仅限于dodiv
函数的主体。我不认为它真的解释了 OP 测试中 56 和 57 之间的差异结果,但我可能错过了一些东西。它当然说明了为什么 3 和 7 可能有非常不同的时间。
/* DIVISOR 3 */ /* DIVISOR 7 */ /* DIVISOR 56 */ /* DIVISOR 57 */
dodiv: dodiv: dodiv: dodiv:
ldi r25,lo8(-85) ldi r25,lo8(37) lsr r24 ldi r25,lo8(9)
mul r24,r25 mul r24,r25 lsr r24 mul r24,r25
mov r24,r1 mov r25,r1 lsr r24 mov r24,r1
clr __zero_reg__ clr __zero_reg__ ldi r25,lo8(37) clr __zero_reg__
lsr r24 sub r24,r25 mul r24,r25 lsr r24
ret lsr r24 mov r24,r1 ret
add r24,r25 clr __zero_reg__
lsr r24 ret
lsr r24
ret
- 处理多个异常集合的C++方法
- 我在c++代码中生成了一个运行时#3异常
- 孤立代码块在结构中引发异常
- C++中的赋值发生,尽管右侧出现异常
- 为什么在读取文件大小时文件IO速度会发生变化
- 从构造函数抛出异常时如何克服内存泄漏
- 异常属于C++中的线程还是进程
- 当类定义不可见时捕获异常
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 为什么异常不退出程序?
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- 文件系统:复制功能的速度秘诀是什么
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- 如何修复链表类实现的未处理异常0xDDDDDDDD
- 关于:C++中异常对象的范围:为什么我没有得到副本?
- 是什么导致了Unity 3D中的"错误线程异常"?
- 如何将strftime中的格式错误作为异常捕获
- 创建具有 new in 函数和"this is nullptr"异常的对象
- Arduino 上数学运算的计时速度 - 异常
- select()中的c++makefile项目在stdin中的返回速度异常快