简单接触BCD码,以及使用C#简单实现BCD转换

BCD码(Binary-Coded Decimal‎),使用4位二进制数来表示1位十进制中的0~9这10个数码,

BCD码常用于会计系统的设计里,因为会计制度经常需要对很长的数字串作准确的计算。相对于一般的浮点式记数法,采用BCD码,既可保存数值的精确度,又可免却使电脑作浮点运算时所耗费的时间。

BCD码有很多形式,本次只讨论8421码,

如果一个字节的二进制是 0101 0101,则十进制为85,那么BCD就是55(BCD用4个bit表示一个0-9的数值,0101是5,8个bit就是2位,即5*10+5=55),

如果用一串字节数组来描述BCD码,那么字节数组中每个字节前4位和后4位的范围为000-1001,这和十六进制很像,十六进制的低4位表示0-F,范围0000-1111,

个人感觉BCD码(8421码)和没有ABCDEF的十六进制完全一样,如果确认BCD码为8421码,是不是就能将字节数组转成十六进制字符串来表示BCD码呢?

不过8421码本身就很简单,也可以自己实现一个,

        public static void Start() {
            var rd = new Random();
            for (int i = 0; i < 20; i++) {
                var num = rd.NextInt64(10000000000000, 99999999999999);
                string bcdString = num.ToString(); //模拟BCD码
                var bcdCode = new BCDCode(bcdString);
                var bytes = bcdCode.ToBytes(); //其字节数组
                var other = new BCDCode(bytes, 0, bytes.Length); //测试通过字节数组转BCD吗
                var hex = BitConverter.ToString(bytes).Replace("-", "");
                Console.WriteLine($"{i},{bcdString},{bcdString == other.Value},{other.Value},{hex},{hex == bcdString}");
            }
        }

  

        /// <summary>
        /// 一个用于描述BCD码的结构体
        /// </summary>
        public readonly struct BCDCode {
            public readonly string Value { get; }
            static string Validate(string value) {
                if (string.IsNullOrEmpty(value))
                    throw new ArgumentNullException(nameof(value), "BCD 值不能为空");
                if (value.Length % 2 != 0)
                    throw new ArgumentException("BCD 值必须是偶数长度", nameof(value));
                if (!value.All(c => char.IsDigit(c)))
                    throw new ArgumentException("BCD 值只能包含数字字符", nameof(value));
                return value;
            }
            /// <summary>
            /// 从字符串创建 BCD 码
            /// </summary>
            public BCDCode(string value) => Value = Validate(value);
            /// <summary>
            /// 从字节数组创建 BCD 码
            /// </summary>
            public BCDCode(byte[] bytes, int startIndex, int length) {
                char[] result = new char[length * 2];
                int idx = 0;
                for (int i = 0; i < length; i++) {
                    var b = bytes[startIndex + i]; //每个字节分两份,分别将前4位和后4位转成数字字符
                    result[idx++] = (char)((b >> 4) + '0'); //加上字符0正好能对应上ASCII的数字
                    result[idx++] = (char)((b & 0x0F) + '0');
                }
                Value = new string(result);
                Validate(Value);
            }
            /// <summary>
            /// 转换为字节数组
            /// </summary>
            public byte[] ToBytes() {
                byte[] bytes = new byte[Value.Length / 2];
                for (int i = 0; i < bytes.Length; i++) {
                    var b1 = (byte)(Value[i * 2] - '0'); //减去字符0将ASCII字符还原为4bit表示的数值
                    var b2 = (byte)(Value[i * 2 + 1] - '0');
                    bytes[i] = (byte)((b1 << 4) | b2); //将2个数值合并为一个字节
                }
                return bytes;
            }
        }

 

posted @ 2025-06-03 16:30  WmW  阅读(251)  评论(0)    收藏  举报