Unsigned Integer to BCD conversion?

前端 未结 10 1058
囚心锁ツ
囚心锁ツ 2020-12-11 05:01

I know you can use this table to convert decimal to BCD:

0 0000

1 0001

2 0010

3 0011

4 0100

5 0101

6 01

10条回答
  •  时光说笑
    2020-12-11 05:30

    This code encodes and decodes. Benchmarks are as follows.

    • 45 clocks for the round-trip
    • 11 clocks for unpacking BCD to uint32_t
    • 34 clocks for packing uint32_t into BCD

    I used an uint64_t to store the BCD here. Very convenient and fixed width, but not very space efficient for large tables. Pack the BCD digits, 2 to char[] for that.

    // -------------------------------------------------------------------------------------
    uint64_t uint32_to_bcd(uint32_t usi)    {
    
        uint64_t shift = 16;  
        uint64_t result = (usi % 10);
    
        while (usi = (usi/10))  {
            result += (usi % 10) * shift;
            shift *= 16; // weirdly, it's not possible to left shift more than 32 bits
        }
        return result;
    }
    // ---------------------------------------------------------------------------------------
    uint32_t bcd_to_ui32(uint64_t bcd)  {
    
        uint64_t mask = 0x000f;
        uint64_t pwr = 1;
    
        uint64_t i = (bcd & mask);
        while (bcd = (bcd >> 4))    {
            pwr *= 10;
            i += (bcd & mask) * pwr;
        }
        return (uint32_t)i;
    }
    // --------------------------------------------------------------------------------------
    const unsigned long LOOP_KNT = 3400000000; // set to clock frequencey of your CPU
    // --------------------------------------------------------------------------------------
    int main(void)  {
        time_t start = clock();
        uint32_t foo, usi = 1234; //456;
        uint64_t result;
        unsigned long i;
    
        printf("\nRunning benchmarks for %u loops.", LOOP_KNT);
    
        start = clock();
        for (uint32_t i = 0; i < LOOP_KNT; i++) {
            foo = bcd_to_ui32(uint32_to_bcd(i >> 10));
        }
        printf("\nET for bcd_to_ui32(uint_16_to_bcd(t)) was %f milliseconds. foo %u", (double)clock() - start, foo);
    
    
        printf("\n\nRunning benchmarks for %u loops.", LOOP_KNT);
    
        start = clock();
        for (uint32_t i = 0; i < LOOP_KNT; i++) {
            foo = bcd_to_ui32(i >> 10);
        }
        printf("\nET for bcd_to_ui32(uint_16_to_bcd(t)) was %f milliseconds. foo %u", (double)clock() - start, foo);
    
        getchar();
        return 0;
    }
    

    NOTE: It appears that it's impossible, even with 64-bit ints, to shift left more than 32 bits, but fortunately, it's entirely possible to multiply by some factor of 16 - which happily has the desired effect. It's also much faster. Go figure.

提交回复
热议问题