Convertendo um int em uma matriz de bytes BCD
-
20-09-2019 - |
Pergunta
Eu quero converter um int em uma matriz de byte [2] usando o BCD.
O INT em questão virá do DateTime representando o ano e deve ser convertido em dois bytes.
Existe alguma função pré-fabricada que faça isso ou você pode me dar uma maneira simples de fazer isso?
exemplo:
int year = 2010
Sairia:
byte[2]{0x20, 0x10};
Solução
static byte[] Year2Bcd(int year) {
if (year < 0 || year > 9999) throw new ArgumentException();
int bcd = 0;
for (int digit = 0; digit < 4; ++digit) {
int nibble = year % 10;
bcd |= nibble << (digit * 4);
year /= 10;
}
return new byte[] { (byte)((bcd >> 8) & 0xff), (byte)(bcd & 0xff) };
}
Cuidado que você pediu um resultado grande e muito endiano, isso é um pouco incomum.
Outras dicas
Aqui está uma terrível versão da força bruta. Tenho certeza de que há uma maneira melhor do que isso, mas deve funcionar de qualquer maneira.
int digitOne = year / 1000;
int digitTwo = (year - digitOne * 1000) / 100;
int digitThree = (year - digitOne * 1000 - digitTwo * 100) / 10;
int digitFour = year - digitOne * 1000 - digitTwo * 100 - digitThree * 10;
byte[] bcdYear = new byte[] { digitOne << 4 | digitTwo, digitThree << 4 | digitFour };
A parte triste é que as conversões binárias rápidas para o BCD são incorporadas na arquitetura do microprocessador x86, se você puder chegar a elas!
Aqui está uma versão um pouco mais limpa então Jeffrey's
static byte[] IntToBCD(int input)
{
if (input > 9999 || input < 0)
throw new ArgumentOutOfRangeException("input");
int thousands = input / 1000;
int hundreds = (input -= thousands * 1000) / 100;
int tens = (input -= hundreds * 100) / 10;
int ones = (input -= tens * 10);
byte[] bcd = new byte[] {
(byte)(thousands << 4 | hundreds),
(byte)(tens << 4 | ones)
};
return bcd;
}
Solução mais comum
private IEnumerable<Byte> GetBytes(Decimal value)
{
Byte currentByte = 0;
Boolean odd = true;
while (value > 0)
{
if (odd)
currentByte = 0;
Decimal rest = value % 10;
value = (value-rest)/10;
currentByte |= (Byte)(odd ? (Byte)rest : (Byte)((Byte)rest << 4));
if(!odd)
yield return currentByte;
odd = !odd;
}
if(!odd)
yield return currentByte;
}
Eu fiz uma rotina genérica postada em Inttobytearray que você poderia usar como:
var yearenInbytes = convertbigintTobcd (2010, 2);
static byte[] IntToBCD(int input) {
byte[] bcd = new byte[] {
(byte)(input>> 8),
(byte)(input& 0x00FF)
};
return bcd;
}