Converting to ASCII in C

前端 未结 9 1819
温柔的废话
温柔的废话 2021-01-05 07:26

Using a microcontroller (PIC18F4580), I need to collect data and send it to an SD card for later analysis. The data it collects will have values between 0 and 1023, or 0x0 a

9条回答
  •  轮回少年
    2021-01-05 08:05

    If the values are correctly in range (0..1023), then your last conversion is unnecessarily wasteful on the divisions; the last line could be replaced with:

    temp[3] = 1023 / 1000;
    

    or even:

    temp[3] = 1023 >= 1000;
    

    Since division is repeated subtraction, but you have a very special case (not a general case) division to deal with, I'd be tempted to compare the timings for the following code with the division version. I note that you put the digits into the string in 'reverse order' - the least significant digit goes in temp[0] and the most in temp[4]. Also, there is no chance of null-terminating the string given the storage. This code uses a table of 8 bytes of static data - considerably less than many of the other solutions.

    void convert_to_ascii(int value, char *temp)
    {
        static const short subtractors[] = { 1000, 100, 10, 1 };
        int i;
        for (i = 0; i < 4; i++)
        {
            int n = 0;
            while (value >= subtractors[i])
            {
                n++;
                value -= subtractors[i];
            }
            temp[3-i] = n + '0';
        }
    }
    

    Performance testing - Intel x86_64 Core 2 Duo 3.06 GHz (MacOS X 10.6.4)

    This platform is probably not representative of your microcontroller, but the test shows that on this platform, the subtraction is considerably slower than the division.

    void convert_by_division(int value, char *temp)
    {
        temp[0] = (value %    10)        + '0';
        temp[1] = (value %   100) /   10 + '0';
        temp[2] = (value %  1000) /  100 + '0';
        temp[3] = (value % 10000) / 1000 + '0';
    }
    
    void convert_by_subtraction(int value, char *temp)
    {
        static const short subtractors[] = { 1000, 100, 10, 1 };
        int i;
        for (i = 0; i < 4; i++)
        {
            int n = 0;
            while (value >= subtractors[i])
            {
                n++;
                value -= subtractors[i];
            }
            temp[3-i] = n + '0';
        }
    }
    
    #include 
    #include 
    #include 
    
    static void time_convertor(const char *tag, void (*function)(void))
    {
        int r;
        Clock ck;
        char buffer[32];
    
        clk_init(&ck);
        clk_start(&ck);
        for (r = 0; r < 10000; r++)
            (*function)();
        clk_stop(&ck);
        printf("%s: %12s\n", tag, clk_elapsed_us(&ck, buffer, sizeof(buffer)));
    }
    
    static void using_subtraction(void)
    {
        int i;
        for (i = 0; i < 1024; i++)
        {
            char temp1[4];
            convert_by_subtraction(i, temp1);
        }
    }
    
    static void using_division(void)
    {
        int i;
        for (i = 0; i < 1024; i++)
        {
            char temp1[4];
            convert_by_division(i, temp1);
        }
    }
    
    int main()
    {
        int i;
    
        for (i = 0; i < 1024; i++)
        {
            char temp1[4];
            char temp2[4];
            convert_by_subtraction(i, temp1);
            convert_by_division(i, temp2);
            if (memcmp(temp1, temp2, 4) != 0)
                printf("!!DIFFERENCE!! ");
            printf("%4d: %.4s %.4s\n", i, temp1, temp2);
        }
    
        time_convertor("Using division   ", using_division);
        time_convertor("Using subtraction", using_subtraction);
    
        time_convertor("Using division   ", using_division);
        time_convertor("Using subtraction", using_subtraction);
    
        time_convertor("Using division   ", using_division);
        time_convertor("Using subtraction", using_subtraction);
    
        time_convertor("Using division   ", using_division);
        time_convertor("Using subtraction", using_subtraction);
    
        return 0;
    }
    

    Compiling with GCC 4.5.1, and working in 32-bit, the average timings were (optimization '-O'):

    • 0.13 seconds using division
    • 0.65 seconds using subtraction

    Compiling and working in 64-bit, the average timings were:

    • 0.13 seconds using division
    • 0.48 seconds using subtraction

    Clearly, on this machine, using subtraction is not a winning proposition. You would have to measure on your machine to make a decision. And removing the modulo 10000 operation will only skew results in favour of the division (it knocks about 0.02 seconds off the time with division when replaced with the comparison; that's a 15% saving and worth having).

提交回复
热议问题