tags:

views:

4329

answers:

4

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 0110

7 0111

8 1000

9 1001

Is there a equation for this conversion or you have to just use the table? Im trying to write some code for this conversion but Im not sure how to do the math for it. Suggestions?

+2  A: 

You know the Binary numeral system, don't you?

Especially have a look at this chapter.

EDIT: Also note KFro's comment that the lower nibble (= 4 bits) of the binary ASCII representation of numerals is in BCD. This makes conversions BCD <-> ASCII very easy as you just have to add/remove the leading 4 bits:

Number    ASCII Code
0         0011 0000
1         0011 0001
 ...
8         0011 1000
9         0011 1001
schnaader
It should also be noted that ASCII representations for the numerals are also in BCD (on purpose)...well at least the lower nybble.
KFro
Er...KFro. That is not terribly clear. Do you mean that the lower nibble of the ASCII representation for the digits coresponds to the BCD representation of the digit?
dmckee
@dmckee: That's the case, so I assume that's what KFro meant: `"0"` is `0x30`, `"1"` is `0x31` etc.
LukeH
A: 

Would something like this work for your conversion?

#include <string>
#include <bitset>

using namespace std;

string dec_to_bin(unsigned long n)
{
    return bitset<numeric_limits<unsigned long>::digits>(n).to_string<char, char_traits<char>, allocator<char> >();
}
CTT
+1  A: 

Usually when someone says they want to convert from decimal to BCD, they're talking about more than one decimal digit.

BCD is often packed into two decimal digits per byte (because 0..9 fit in 4 bits, as you've shown), but I think it's more natural to use an array of bytes, one per decimal digit.

An n-bit unsigned binary number will fit into ceil(n*log_2(10)) = ceil(n/log10(2)) decimal digits. It will also fit in ceil(n/3) = floor((n+2)/3)) decimal digits, since 2^3=8 is less than 10.

With that in mind, here's how I'd get the decimal digits of an unsigned int:

#include <algorithm>
#include <vector>

template <class Uint>
std::vector<unsigned char> bcd(Uint x) {  
  std::vector<unsigned char> ret;
  if (x==0) ret.push_back(0); 
  // skip the above line if you don't mind an empty vector for "0"
  while(x>0) {
    Uint d=x/10;
    ret.push_back(x-(d*10)); // may be faster than x%10
    x=d;
  }
  std::reverse(ret.begin(),ret.end());
  // skip the above line if you don't mind that ret[0] is the least significant digit
  return ret;
}

Of course, if you know the width of your int type, you may prefer fixed length arrays. There's also no reason to reverse at all if you can remember the fact that the 0th digit is the least significant and reverse only on input/output. Keeping the least significant digit as the first simplifies digit-wise arithmetic ops in the case that you don't use a fixed number of digits.

If you want to represent "0" as the single "0" decimal digit rather than the empty digit-string (either is valid), then you'd check specifically for x==0.

wrang-wrang
A: 

If you want two decimal digits per byte, and "unsigned" is half the size of "unsigned long" (use uint32 and uint64 typedefs if you want):

unsigned long bcd(unsigned x) {
  unsigned long ret=0;
  while(x>0) {
    unsigned d=x/10;
    ret=(ret<<4)|(x-d*10);
    x=d;
  }
  return ret;
}

This leaves you with the least significant (unit) decimal digit in the least significant half-byte. You can also execute the loop a fixed number (10 for uint32) of times, not stopping early when only 0 bits are left, which would allow the optimizer to unroll it, but that's slower if your numbers are often slow.

wrang-wrang