【发布时间】:2010-03-15 15:32:43
【问题描述】:
我想使用 BCD 将 int 转换为 byte[2] 数组。
有问题的 int 将来自表示年份的 DateTime,并且必须转换为两个字节。
是否有任何预制功能可以做到这一点,或者你能给我一个简单的方法吗?
示例:
int year = 2010
会输出:
byte[2]{0x20, 0x10};
【问题讨论】:
标签: c# .net encryption bcd
我想使用 BCD 将 int 转换为 byte[2] 数组。
有问题的 int 将来自表示年份的 DateTime,并且必须转换为两个字节。
是否有任何预制功能可以做到这一点,或者你能给我一个简单的方法吗?
示例:
int year = 2010
会输出:
byte[2]{0x20, 0x10};
【问题讨论】:
标签: c# .net encryption bcd
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) };
}
请注意,您要求的是大端结果,这有点不寻常。
【讨论】:
使用这个方法。
public static byte[] ToBcd(int value){
if(value<0 || value>99999999)
throw new ArgumentOutOfRangeException("value");
byte[] ret=new byte[4];
for(int i=0;i<4;i++){
ret[i]=(byte)(value%10);
value/=10;
ret[i]|=(byte)((value%10)<<4);
value/=10;
}
return ret;
}
这基本上就是它的工作原理。
(一种优化是预先将每个字节设置为 0——这是由 .NET 在分配新数组时隐式完成的——并在值达到 0 时停止迭代。后一种优化未在代码中完成上面,为了简单起见。此外,如果可用,一些编译器或汇编器提供了一个除法/余数例程,允许在一个除法步骤中检索商和余数,但通常不需要进行优化。)
【讨论】:
这是一个可怕的蛮力版本。我确信有比这更好的方法,但无论如何它应该可以工作。
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 };
可悲的是,x86 微处理器架构中内置了快速二进制到 BCD 的转换,如果你能做到的话!
【讨论】:
这是一个比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;
}
【讨论】:
可能是一个包含此循环的简单解析函数
i=0;
while (id>0)
{
twodigits=id%100; //need 2 digits per byte
arr[i]=twodigits%10 + twodigits/10*16; //first digit on first 4 bits second digit shifted with 4 bits
id/=100;
i++;
}
【讨论】:
更常见的解决方案
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;
}
【讨论】:
GetBytes(3.55549322);?
与 Peter O. 相同的版本,但在 VB.NET 中
Public Shared Function ToBcd(ByVal pValue As Integer) As Byte()
If pValue < 0 OrElse pValue > 99999999 Then Throw New ArgumentOutOfRangeException("value")
Dim ret As Byte() = New Byte(3) {} 'All bytes are init with 0's
For i As Integer = 0 To 3
ret(i) = CByte(pValue Mod 10)
pValue = Math.Floor(pValue / 10.0)
ret(i) = ret(i) Or CByte((pValue Mod 10) << 4)
pValue = Math.Floor(pValue / 10.0)
If pValue = 0 Then Exit For
Next
Return ret
End Function
这里的诀窍是要注意,简单地使用 pValue /= 10 将舍入该值,因此如果参数是“16”,则字节的第一部分将是正确的,但除法的结果将是2(因为 1.6 将向上取整)。因此我使用 Math.Floor 方法。
【讨论】:
我在IntToByteArray 发布了一个通用例程,您可以像这样使用它:
var yearInBytes = ConvertBigIntToBcd(2010, 2);
【讨论】:
static byte[] IntToBCD(int input) {
byte[] bcd = new byte[] {
(byte)(input>> 8),
(byte)(input& 0x00FF)
};
return bcd;
}
【讨论】: