将 int 转换为 BCD 字节数组

发布于 2024-08-25 00:54:05 字数 264 浏览 5 评论 0原文

我想使用 BCD 将 int 转换为 byte[2] 数组。

所讨论的 int 将来自表示年份的 DateTime,并且必须转换为两个字节。

是否有任何预制函数可以执行此操作,或者您能给我一个简单的方法来执行此操作吗?

示例:

int year = 2010

将输出:

byte[2]{0x20, 0x10};

I want to convert an int to a byte[2] array using BCD.

The int in question will come from DateTime representing the Year and must be converted to two bytes.

Is there any pre-made function that does this or can you give me a simple way of doing this?

example:

int year = 2010

would output:

byte[2]{0x20, 0x10};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

被翻牌 2024-09-01 00:54:05
    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) };
    }

请注意,您要求的是大端结果,这有点不寻常。

    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) };
    }

Beware that you asked for a big-endian result, that's a bit unusual.

以酷 2024-09-01 00:54:05

使用这个方法。

    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 或大于 99999999,则该值将无法容纳在四个字节中。更正式地说,如果该值小于 0 或者为 10^(n*2) 或更大(其中 n 是字节数),则该值将无法容纳在 n 个字节中。
  • 对于每个字节:
    • 将该字节设置为该字节的值除以 10 后的余数。 (这会将最后一个数字放置在当前字节的低半字节 [半字节] 中。)
    • 将该值除以 10。
    • 将值除以 10 后的余数乘以 16 与字节相加。 (这会将现在的最后一个数字放置在当前字节的高半字节中。)
    • 将该值除以 10。

(一种优化是预先将每个字节设置为 0 —— 这是 .NET 在分配新的字节时隐式完成的。数组 - 并在值达到 0 时停止迭代。为了简单起见,上面的代码中没有进行后一种优化。此外,如果可用,一些编译器或汇编器提供了除法/求余例程,允许检索 中的商和余数。一个除法步骤,但通常不需要进行优化。)

Use this method.

    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;
    }

This is essentially how it works.

  • If the value is less than 0 or greater than 99999999, the value won't fit in four bytes. More formally, if the value is less than 0 or is 10^(n*2) or greater, where n is the number of bytes, the value won't fit in n bytes.
  • For each byte:
    • Set that byte to the remainder of the value-divided-by-10 to the byte. (This will place the last digit in the low nibble [half-byte] of the current byte.)
    • Divide the value by 10.
    • Add 16 times the remainder of the value-divided-by-10 to the byte. (This will place the now-last digit in the high nibble of the current byte.)
    • Divide the value by 10.

(One optimization is to set every byte to 0 beforehand -- which is implicitly done by .NET when it allocates a new array -- and to stop iterating when the value reaches 0. This latter optimization is not done in the code above, for simplicity. Also, if available, some compilers or assemblers offer a divide/remainder routine that allows retrieving the quotient and remainder in one division step, an optimization which is not usually necessary though.)

奶气 2024-09-01 00:54:05

这是一个可怕的暴力版本。我确信有比这更好的方法,但无论如何它应该有效。

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 转换(如果您能做到的话)!

Here's a terrible brute-force version. I'm sure there's a better way than this, but it ought to work anyway.

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 };

The sad part about it is that fast binary to BCD conversions are built into the x86 microprocessor architecture, if you could get at them!

定格我的天空 2024-09-01 00:54:05

这是一个稍微干净的版本,然后 Jeffrey 的

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;
}

Here is a slightly cleaner version then 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;
}
盗心人 2024-09-01 00:54:05

也许是一个包含此循环的简单解析函数

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++;
}

maybe a simple parse function containing this loop

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++;
}
动听の歌 2024-09-01 00:54:05

更常见的解决方案

    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;
    }

More common solution

    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;
    }
じ违心 2024-09-01 00:54:05

与 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 方法。

Same version as Peter O. but in 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

The trick here is to be aware that simply using pValue /= 10 will round the value so if for instance the argument is "16", the first part of the byte will be correct, but the result of the division will be 2 (as 1.6 will be rounded up). Therefore I use the Math.Floor method.

椒妓 2024-09-01 00:54:05

我在 IntToByteArray 上发布了一个通用例程,您可以使用它,例如:

varyearInBytes = ConvertBigIntToBcd(2010, 2) ;

I made a generic routine posted at IntToByteArray that you could use like:

var yearInBytes = ConvertBigIntToBcd(2010, 2);

娇妻 2024-09-01 00:54:05
static byte[] IntToBCD(int input) { 
    byte[] bcd = new byte[] { 
        (byte)(input>> 8), 
        (byte)(input& 0x00FF) 
    };
    return bcd;
}
static byte[] IntToBCD(int input) { 
    byte[] bcd = new byte[] { 
        (byte)(input>> 8), 
        (byte)(input& 0x00FF) 
    };
    return bcd;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文