【问题标题】:Converting a int to a BCD byte array将 int 转换为 BCD 字节数组
【发布时间】:2010-03-15 15:32:43
【问题描述】:

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

有问题的 int 将来自表示年份的 DateTime,并且必须转换为两个字节。

是否有任何预制功能可以做到这一点,或者你能给我一个简单的方法吗?

示例:

int year = 2010

会输出:

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

【问题讨论】:

    标签: c# .net encryption bcd


    【解决方案1】:
        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) };
        }
    

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

    【讨论】:

    • 如果他使用嵌入式硬件,Big-endian 可能并不罕见。
    • 非常感谢!在这种情况下,我认为 Endian 无关紧要,我对此很小心,但在这种情况下没关系。
    【解决方案2】:

    使用这个方法。

        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 时停止迭代。后一种优化未在代码中完成上面,为了简单起见。此外,如果可用,一些编译器或汇编器提供了一个除法/余数例程,允许在一个除法步骤中检索商和余数,但通常不需要进行优化。)

    【讨论】:

    • 你能一步一步告诉我这里发生了什么吗?谢谢。
    • @Anonymous:我已经添加了解释。
    • 很棒的功能 - 我已经使用了很长时间 - 我通过将数组增加到 5 个字节来更改我的以覆盖所有 int 值。还为其他数据类型制作了一个并将它们制成扩展方法。感谢您让我继续前进。
    【解决方案3】:

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

    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 的转换,如果你能做到的话!

    【讨论】:

      【解决方案4】:

      这是一个比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;
      }
      

      【讨论】:

      • 你可能会想出一些使用布尔逻辑和移位的疯狂方法......但这会更好维护。
      【解决方案5】:

      可能是一个包含此循环的简单解析函数

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

      【讨论】:

        【解决方案6】:

        更常见的解决方案

            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);
        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          我在IntToByteArray 发布了一个通用例程,您可以像这样使用它:

          var yearInBytes = ConvertBigIntToBcd(2010, 2);

          【讨论】:

            【解决方案9】:
            static byte[] IntToBCD(int input) { 
                byte[] bcd = new byte[] { 
                    (byte)(input>> 8), 
                    (byte)(input& 0x00FF) 
                };
                return bcd;
            }
            

            【讨论】:

            • 这不是BCD。您只是将 int 转换为两字节数组,
            猜你喜欢
            • 1970-01-01
            • 2011-09-04
            • 1970-01-01
            • 2010-10-22
            • 2023-03-03
            • 2022-06-20
            • 1970-01-01
            相关资源
            最近更新 更多