gpt4 book ai didi

c++ - 迭代与将整数打印到字符LCD/OLED显示器的递归

转载 作者:太空狗 更新时间:2023-10-29 21:09:39 25 4
gpt4 key购买 nike

问题

我正在寻找有关如何优化将整数数字(例如uint32_t num = 1234567890;)打印到具有Arduino UNO的字符显示器的输入。 要考虑的主要指标是内存使用情况和编译大小。 显示太慢了,以至于速度的提高没有意义,最小的代码长度虽然不错,但这不是必需的。

目前,我正在使用num%10提取最低有效位,然后通过num/10删除此位,依此类推,直到提取了num的所有位。使用递归,我可以反转打印顺序,因此只需很少的操作(作为显式代码行)即可按正确的顺序打印数字。使用for循环,我需要找到用于写入数字的字符数,然后存储它们,然后才能以正确的顺序打印它们,这需要一个数组和3个for循环。

根据Arduino IDE,当打印各种有符号和无符号整数时,递归使用 2010/33 字节的存储/内存,而迭代使用 2200/33 字节与 2474/52 字节(使用Adafruit_CharacterOLED库)扩展了类Print

是否有比我使用下面的递归和迭代编写的函数更好的实现方法?如果没有,您想要哪个,为什么? 我觉得可能有一种更好的方法来用更少的资源来执行此操作-但也许我是Don Quixote与风车作战,并且代码已经足够好了。

背景

我正在使用NHD-0420DZW字符OLED显示器,并已使用Newhaven数据表和LiquidCrystal库作为编写我自己的库的指南,并且该显示器运行良好。但是,为了最大程度地减少代码膨胀,我选择不让显示库成为Print的子类,它是Arduino核心库的一部分。这样,已经实现了存储空间(〜400字节)和内存(〜19字节)的显着节省(ATmega328P具有32k的存储空间和2k的RAM,因此资源稀缺)。

递归

如果我使用递归,则打印方法相当优雅。该数字除以10,直到达到零的基本情况。然后,打印最小编号的最低有效数字(数字的MSD),以及下一个最小编号的LSD(数字的第二MSD),依此类推,导致最终的打印顺序颠倒。这可以使用%10/10操作纠正数字提取的相反顺序。

// print integer type literals to display (base-10 representation) 
void NewhavenDZW::print(int8_t num) {print(static_cast<int32_t>(num));}
void NewhavenDZW::print(uint8_t num) {print(static_cast<uint32_t>(num));}
void NewhavenDZW::print(int16_t num) {print(static_cast<int32_t>(num));}
void NewhavenDZW::print(uint16_t num) {print(static_cast<uint32_t>(num));}
void NewhavenDZW::print(int32_t num) {
if(num < 0) { // print negative sign if present
send('-', HIGH); // and make num positive
print(static_cast<uint32_t>(-num));
} else
print(static_cast<uint32_t>(num));
}
void NewhavenDZW::print(uint32_t num) {
if(num < 10) { // print single digit numbers directly
send(num + '0', HIGH);
return;
} else // use recursion to print nums with more
recursivePrint(num); // than two digits in the correct order
}
// recursive method for printing a number "backwards"
// used to correct the reversed order of digit extraction
void NewhavenDZW::recursivePrint(uint32_t num) {
if(num) { // true if num>0, false if num==0
recursivePrint(num/10); // maximum of 11 recursive steps
send(num%10 + '0', HIGH); // for a 10 digit number
}
}

迭代

由于数字提取方法是从LSD(而不是MSD)开始的,因此除非直接移动光标并告诉显示器从右到左打印,否则无法直接打印提取的数字。因此,在提取数字之前,必须先存储它们,然后才能以正确的顺序将它们写入显示器。

void NewhavenDZW::print(uint32_t num) {
if(num < 10) {
send(num + '0', HIGH);
return;
}
uint8_t length = 0;
for(uint32_t i=num; i>0; i/=10) // determine number of characters
++length; // needed to represent number
char text[length];
for(uint8_t i=length; num>0; num/=10, --i)
text[i-1] = num%10 + '0'; // map each numerical digit to
for(uint8_t i=0; i<length; i++) // its char value and fix ordering
send(text[i], HIGH); // before printing result
}

更新资料

最终,递归占用的存储空间最少,但可能使用的内存最多。

在回顾了Igor G和darune提供的代码之后,并查看了Godbolt上列出的指令数(如darune和old_timer讨论的) ,我相信Igor G的解决方案是最好的整体。在测试期间,它将编译为dart函数的 2076 字节与 2096 字节(使用 if语句停止前导零并能够打印 0)。当必要的 if语句被加上时,与darune(273)相比,它还需要更少的指令(88)。

使用指针变量

void NewhavenDZW::print(uint32_t num) {
char buffer[10];
char* p = buffer;
do {
*p++ = num%10 + '0';
num /= 10;
} while (num);
while (p != buffer)
send(*--p, HIGH);
}

使用索引变量

这是我最初的 for循环试图做的,但是很幼稚。正如Igor G指出的那样,试图最小化缓冲区数组的大小确实没有任何意义。

void NewhavenDZW::print(uint32_t num) {
char text[10]; // signed/unsigned 32-bit ints are <= 10 digits
uint8_t i = sizeof(text) - 1; // set index to end of char array
do {
text[i--] = num%10 + '0'; // store each numerical digit as
num /= 10; // its associated char value
} while (num);
while (i < sizeof(text))
send(text[i++], HIGH); // print num in the correct order
}

替代

这是darune的函数,其中添加了if语句,适用于不想筛选注释的用户。条件 pow10 == 100pow10 == 1相同,但是保留了两次循环迭代以在编译大小相同的情况下打印零。

void NewhavenDZW::print(uint32_t num) {
for (uint32_t pow10 = 1000000000; pow10 != 0; pow10 /= 10)
if (num >= pow10 || (num == 0 && pow10 == 100))
send((num/pow10)%10 + '0', HIGH);
}

最佳答案

试试这个。我的avr-gcc-5.4.0 + readelf告诉函数主体只有138个字节。

void Send(uint8_t);

void OptimizedPrintf(uint32_t val)
{
uint8_t buffer[sizeof(val) * CHAR_BIT / 3 + 1];
uint8_t* p = buffer;
do
{
*p++ = (val % 10) + '0';
val /= 10;
} while (val);
while (p != buffer)
Send(*--p);
}

关于c++ - 迭代与将整数打印到字符LCD/OLED显示器的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57798199/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com