Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 通过十进制数字快速循环打印(嵌入式)_Algorithm_Embedded_Decimal_Real Time - Fatal编程技术网

Algorithm 通过十进制数字快速循环打印(嵌入式)

Algorithm 通过十进制数字快速循环打印(嵌入式),algorithm,embedded,decimal,real-time,Algorithm,Embedded,Decimal,Real Time,在我的实时嵌入式处理器FW中,我需要十进制数的格式化打印。标准printf/sprintf在toolchain中不可用,所以我需要自己实现它 我使用了简单的方法,即除以十,然后取余数。但我的目标处理器不支持本机划分,软件实现需要很长时间(超过200个)来计算。 我想知道是否有不除法从数字中提取十进制数字的快速方法 char* os_prn_decimal(char* outBuf, const char* end, uint32 v) { uint32 dgtIdx = 10000000

在我的实时嵌入式处理器FW中,我需要十进制数的格式化打印。标准printf/sprintf在toolchain中不可用,所以我需要自己实现它

我使用了简单的方法,即除以十,然后取余数。但我的目标处理器不支持本机划分,软件实现需要很长时间(超过200个)来计算。 我想知道是否有不除法从数字中提取十进制数字的快速方法

char* os_prn_decimal(char* outBuf, const char* end, uint32 v)
{
    uint32 dgtIdx = 1000000000;

    do
    {
        uint8 dgt = (uint8)(v / dgtIdx);

        *outBuf = dgt + '0';
        ++outBuf;

       v = v % dgtIdx;
        dgtIdx /= 10;
    } while (outBuf < end && dgtIdx > 0);
    return outBuf;
}
char*os\u prn\u十进制(char*extuf,const char*end,uint32 v)
{
uint32 dgtIdx=100000000;
做
{
uint8 dgt=(uint8)(v/dgtIdx);
*exputf=dgt+'0';
++爆发;
v=v%dgtix;
dgtix/=10;
}而(exputf0);
返回爆发;
}

您的解决方案直接以正确的顺序生成数字,但代价是可变除法(
v/dgtix
)、可变模(与除法的代价相同或更大)和除以10。这是三项昂贵的行动

首先从最低有效位生成数字,然后再反转后的数字,成本可能会更低。这将只需要除以10和模10运算。在处使用解决方案并对其进行修改,以在与商相同的操作中获得余数:

uint32_t div10_rem( uint32_t dividend, int* remainder )
{
    uint32_t quotient = (uint32_t)((0x1999999Aull * dividend) >> 32) ;
    *remainder = dividend - (quotient * 10) ;

    return quotient ;
}
然后,转换为可显示的十进制字符串可能是:

char* int2dec( uint32_t val, char* buffer )
{
    char reverse_digits[10] = {0} ;
    uint32_t u = val ;
    size_t digit_count = 0 ;

    while( u > 0 )
    {
        int d = 0 ;
        u = div10_rem( u, &d ) ;
        reverse_digits[digit_count] = d + '0' ;
        digit_count++ ;
    }

    buffer[digit_count] = '\0' ;
    size_t i = 0 ;
    for( size_t i = 0; i < digit_count; i++ )
    {
        buffer[i] = reverse_digits[digit_count - i - 1] ;
    }

    return buffer ;
}
如果静态缓冲区合适,可以避免数字反转:

#define MAX_DIGITS 10
const char* int2dec( uint32_t val )
{
    static char digits[MAX_DIGITS + 1] = {0} ;
    uint32_t u = val ;
    size_t digit_index = MAX_DIGITS - 1 ;

    while( u > 0 )
    {
        int d = 0 ;
        u = div10_rem( u, &d ) ;
        digits[digit_index] = d + '0' ;
        digit_index-- ;
    }

    return &digits[digit_index + 1] ;
}
然后,例如:

    printf( "%s", int2dec( val ) ) ;

daShier的一个提示帮助我修正了我的谷歌搜索,我发现这篇文章描述了一种有趣的10除方法,它提供了商和模。 最好的部分是完全没有乘法、除法和循环

UPD:模拟测量表明,与替代解决方案相比,此解决方案的性能提高了约2倍,与我的原始实现相比,性能提高了约6倍

void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
{
 // q = in * 0.8;
 uint32_t q = (in >> 1) + (in >> 2);
 q = q + (q >> 4);
 q = q + (q >> 8);
 q = q + (q >> 16);  // not needed for 16 bit version

 // q = q / 8;  ==> q =  in *0.1;
 q = q >> 3;

 // determine error
 uint32_t  r = in - ((q << 3) + (q << 1));   // r = in - q*10;
 div = q + (r > 9);
 if (r > 9) mod = r - 10;
 else mod = r;
}
void divmod10(uint32_t in,uint32_t&div,uint32_t&mod)
{
//q=in*0.8;
uint32_t q=(in>>1)+(in>>2);
q=q+(q>>4);
q=q+(q>>8);
q=q+(q>>16);//16位版本不需要
//q=q/8;==>q=in*0.1;
q=q>>3;
//判定误差
uint32_t r=in-((q 9)mod=r-10;
else-mod=r;
}

简短的回答是否定的。您正在从一个基转换到另一个基,因此需要整数除法和模运算。但您可能还可以进行其他优化。例如,看看您是否可以在不使用
(uint8)的情况下解决此问题
casting。您还可以对数字的基数-10大小进行初始检查,查看其是否超过缓冲区大小,而不是在每个循环中检查
end
。除了获得(稍微)更好的速度(对于
v
的大值),这将解决缓冲区太小时输出不完整数据的问题。不完整数据是我最不关心的问题(tbh:)200us相当于4K操作。10次检查
,没什么大不了的。但对于基转换本身,也许有一些数学技巧可以用来除以十。不管怎样,都值得在StackOverflow上与聪明人核实一下。谢谢你的回复这可能会有帮助:哦,看起来不错。谢谢也许如果你提到你的实际目标是什么,你会得到很好的答案。在大多数情况下,没有特定目标的手动优化没有多大意义。是的,这与daShier在评论中提到的类似。这一切都很好,但它有64位乘法,这对于我的特定环境来说有点问题-处理器不支持这种操作。无论如何,谢谢你的回答。@Noname:这不是64位乘法,而是一个32x32位的64位乘法结果。它不必由处理器支持,只需由编译器支持。编译器提供的软件32x32位乘法将比任何平台上的软件除法都快,并且将受到任何可用硬件乘法的支持。@Noname:这正是daSher所指的,但他只是建议它可能会有所帮助-这离答案还有很长的路要走。如果你的处理器和工具链应用了这样的约束,那么如果你指定它们是什么(处理器和工具链,而不是约束),这会有所帮助。无需争论语义。用你的话来说,我的意思是说我的处理器只支持16x16乘法。@Noname:是的,但你没有领会我的意思;许多处理器都是如此——编译器仍然可以对大于硬件支持的字大小合成整数运算,这仍然比除法更快。您的移位解决方案可能更快,但没有给出问题的完整解决方案-您没有问如何用商和余数除以10-这是解决方案的一种方法,而不是解决方案。我现在不清楚是用10除以200 us还是整个算法?这不是生成十进制字符串的解决方案,只是除以10,这只是原始算法中的一个操作。您是如何使用它来生成字符串的?现在的性能是什么(出于兴趣)?初步估计(基于拆解)每次打印约14us。需要运行模拟以查看实际性能。至于“这不是解决方案”,我的问题是“如何不除法提取十进制数字”。对我来说,答案差不多是:)好的,但你的问题是从“我需要十进制数字的格式化打印”开始的,然后给出了一个当前的实现,它不仅仅是获取“一个没有除法的十进制数字”。不过进步不错。一个很好的答案——即使是对一个稍微不同的问题;-)因为StackOverflow需要为这个问题提供一些背景知识。我只是想表现得友好一些,并遵循一些指导原则:d编译器应该能够进行这些优化
void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
{
 // q = in * 0.8;
 uint32_t q = (in >> 1) + (in >> 2);
 q = q + (q >> 4);
 q = q + (q >> 8);
 q = q + (q >> 16);  // not needed for 16 bit version

 // q = q / 8;  ==> q =  in *0.1;
 q = q >> 3;

 // determine error
 uint32_t  r = in - ((q << 3) + (q << 1));   // r = in - q*10;
 div = q + (r > 9);
 if (r > 9) mod = r - 10;
 else mod = r;
}