Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have 3 questions. All of them are concerned with binary coded decimal (BCD) conversion. My coding snippets are listed as follows. But I don't like my algorithm because its takes too long when dealing with tons of data. Any suggestions to improve the performance? Would you please show me an efficient and fast way to do that? Thank you very much!

  1. The value is expressed with 4-bits binary coded decimals (BCD), which was originally stored in a character buffer (for example, pointed by a pointer const unsigned char *).

    BCD*2; 1001 0111 0110 0101=9765 "9" "7" "6" "5"

    unsigned int BCDn( unsigned int n, const unsigned char * data )
    {
        unsigned int uResult = 0;
        unsigned char ucTmp;
        int iTmp1,iTmp2;
    
        for (unsigned int i=0;i<n;i++)
        {
            ucTmp = data[i];
            iTmp1 = (ucTmp & 0xf0) >> 4;
            iTmp2 = ucTmp & 0x0f;
            uResult += (iTmp1*10+iTmp2) * static_cast<unsigned int>(pow(100.0,static_cast<int>(n-1-i)));
        }
    
        return uResult; 
    }
    
  2. The value is expressed by n binary integer (n* 8-bits). The first bit (MSB) defines the sign of binary integer; "0" signifies that it's a positive integer, and "1" for negative one. In the case of negative number, the other bits show the complement number that is added 1.

         MSB          LSB
    I*2; 00101101 1001100=19999
    I*2; 10101101 10011100=(-1)*(0101101 10011100 
                          =(-1)*(1010010 01100100) (after complement)
                          =-21092
    
    int SINTn(unsigned int n, const unsigned char *data)
    {   
        int nResult;
        bool bNegative = false;
    
        if ((data[0] & 0x80)!= 0)
            isNegative = true;
    
        nResult = data[0] & 0x7f;
    
        for (unsigned int i=1;i<n;i++)
            nResult = nResult * 0x100 + data[i];
    
        if (bNegative) 
            nResult = nResult - static_cast<int>(pow(2.0,static_cast<int>(n*8-1)));
    
        return nResult
    }
    
    unsigned int UINTn(unsigned int n, const unsigned char *data)
    {   
        unsigned int uResult = 0;
    
        for (unsigned int i=0;i<n;i++)
            uResult = uResult * 0x100 + data[i];
    
        return uResult;
    }
    
  3. R*n.m The value is expressed by n-bytes (n*8 bits) binary number, the first bit (MSB) defines the sign of it; "0" means positive and "1" means negative. The number m means that the binary number should be multiplied by 10-m to get the value.

           MSB                        LSB
    R*4.0: 00000000 00000000 00000111 10110101=1973
    R*4.2: 00000000 00000000 00000111 10110101=1973*10-2=19.73
    R*4.5: 10000000 00000000 00000111 10110101=-1973*10-5= -0.01973
    R*2.0: 10101101 10011100 =-11676
    
    double REALnm(unsigned int n, unsigned int m, const unsigned char * data)
    {   
        double dResult;
        bool bNegative = false;
    
        if ((data[0] & 0x80)!= 0)
            isNegative = true;
    
        dResult = data[0] & 0x7f;
    
        for (unsigned int i=1;i<n;i++)
            dResult = dResult * 0x100 + data[i];
    
        if (bNegative) dResult *= -1.0;
    
        dResult *= pow(10.0, (-1.0) * m);
    
        return dResult;
    }
    

Thank you for simple and concise implementation to BCDn. I took your BCDn as an example, and revised the other two functions as following:

int SINTn(unsigned int n, const unsigned char *data) 
{        
    int nResult;     
    bool bNegative = false;

    if ((*data & 0x80)!= 0)
       bNegative = true;      

    nResult = *data & 0x7f;      

    while n--) 
    {  
       nResult = nResult * 0x100 + *data;      
       ++data;     
    }

    if (bNegative) 
       nResult = nResult - 2 << (n * 8 - 2);

    return nResult 
}  

double REALnm(unsigned int n, unsigned int m, const unsigned char * data) 
{   
    double dResult;
    bool bNegative = false;

    if ((data[0] & 0x80)!= 0)         
       isNegative = true;      

    dResult = data[0] & 0x7f;

    for (unsigned int i=1;i<n;i++)         
        dResult = dResult * 0x100 + data[i];      

    if (bNegative) dResult *= -1.0;      

    dResult *= pow(10.0, (-1.0) * m);      
    return dResult; 
}

Further suggestions and improvement will be highly appreciated.

share|improve this question

2 Answers

it can be a lot simpler...

#include "seatest.h"

unsigned int BCDn( unsigned int n, const unsigned char * data )
{
    unsigned int uResult = 0;
    unsigned int i;

    for (i=0;i<n;i++) 
    {
        uResult = (uResult * 100) + ((data[i] >> 4) * 10 ) + ( data[i] & 0x0F);     
    }

    return uResult; 
}
void test_max_bcd_convert()
{   
    unsigned char bcd_data[]= { 0x97, 0x65 };

    assert_int_equal(9765, BCDn(2, bcd_data));

}

void test_fixture_bcd( void )
{
    test_fixture_start();      
    run_test(test_max_bcd_convert);   
    test_fixture_end();       
}

void all_tests( void )
{
    test_fixture_bcd();   
}

int main( int argc, char** argv )
{
    run_tests(all_tests);   
    return 0;
}
share|improve this answer

You can avoid pow by doing something like this:

unsigned int BCDn( unsigned int n, const unsigned char * data )
{
    unsigned int uResult = 0;
    unsigned char ucTmp;
    int iTmp1,iTmp2;

    unsigned int factor = 1;
    for (unsigned int i=n-1;i>=0;i--)
    {
        ucTmp = data[i];
        iTmp1 = (ucTmp & 0xf0) >> 4;
        iTmp2 = ucTmp & 0x0f;
        uResult += (iTmp1*10+iTmp2) * factor;
        factor *= 100;
    }

    return uResult; 
}

Basically count backwards, and then you only need to multiply the factor each time. Similar tricks should work for the other methods.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.