Search code examples
algorithmembeddeddecimalreal-time

Fast cycling through decimal digits for printing (embedded)


In my FW for real-time embedded processor I need formatted print of decimal number. Standard printf/sprintf are not available in toolchain, so I need implement it myself.

I used naive approach of dividing by tens and taking remainder. But my target processor doesn't support division natively and software implementation take very long time (more than 200us) to compute. I wonder if there is quick way to fetch decimal digits from a number without division?

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;
}

Solution

  • A hint from daShier helped me to rectify my googling and I found this article https://forum.arduino.cc/index.php?topic=167414.0 that describes interesting approach to division by 10, which provides both quotient and modulo. Best part of it is complete lack of multiplications, divisions and cycles.

    UPD: simulation measurement showed ~2X better performance of this solution compared to alternative solution and ~6X better performance over my original implementation.

    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;
    }