C# general binary conversion to float and double methods

In the previous article, we converted 32-bit binary [or 4 bytes] into float [Real] decimals. This time we use a general method for binary conversion.

Convert 32-bit binary to float [Real] decimal type in C# - Programmer Sought

Binary conversion float (double) method:

            //Single-precision floating-point number corresponds to 32 bits
            //Sign bit (Sign): 0 means positive, 1 means negative [1 bit]
            //Exponent bit (Exponent): used to store exponent data in scientific notation, and Use shift storage [occupy 8 bits]
            // mantissa part (Mantissa): mantissa part [occupy 23 bits]
            // single precision float: N has 32 bits in total, among which S occupies 1 bit, E occupies 8 bits, and M occupies 23 bits . Therefore, after the decimal point, the accuracy is up to 23/4=6 digits 
            //Double precision double: N has a total of 64 digits, of which S occupies 1 digit, E occupies 11 digits, and M occupies 52 digits. Therefore, after the decimal point, it is accurate up to 52/4=13 digits 

           //IEEE rules: Binary 32-bit to float [Real] rule
            //The first digit is 1 to represent a negative number, the first digit is 0 to represent a positive number or 0
            //The second to ninth digits represent the exponent, the corresponding value Subtracting 127 is the number of shifts [shiftCount]
            //[Start at the tenth digit] add a 1 in front of the 23 digits of the mantissa to make up 24 digits. The first [shiftCount+1] of the 24 digits mantissa is the integer part, and the rest is the fractional part

            //Integer binary is converted to decimal: from low to high are 2 to the power of 0, power of 1, power of 2... Multiply and add respectively, and the sum obtained is the decimal result.
            //The binary conversion of the fractional part is in decimal: similar to the integer part, starting from the decimal point is the -1 power, -2 power, -3 power of 2..., multiplying and adding respectively, the obtained The sum is the decimal result, for example, 001 (binary) corresponds to 0.125 (decimal)

target data type source binary digits conversion logic
float(Real、Single) 32 bit

The first digit is 1 for a negative number, the first digit is 0 for a positive number or 0, and the
second to ninth digits represent the exponent, and the corresponding value minus 127 is the shift number [shiftCount]

Start at the tenth digit] Add a 1 in front of the 23 digits of the mantissa to make up 24 digits. The first [shiftCount+1] number of the 24 digits of the mantissa is the integer part, and the rest is the decimal part

double(LReal、Double) 64 bit

The first digit is 1 for a negative number, the first digit is 0 for a positive number or 0, and the
second to twelfth digits represent the exponent, and the corresponding value minus 1023 is the shift number [shiftCount]

Start at the thirteenth digit] Add a 1 in front of the 52 digits of the mantissa to make up 53 digits. The first [shiftCount+1] number of the 53 digits of the mantissa is the integer part, and the rest is the decimal part

 The C# source program is as follows:

Related method: static T BinaryBitToFractional<T>(byte[] binaryArraySource) where T : struct 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BinaryToFloatDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.SetWindowSize(160, 50);
            //单精度浮点数对应32位
            //符号位(Sign) : 0代表正,1代表为负【占1位】
            //指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储【占8位】
            //尾数部分(Mantissa):尾数部分【占23位】
            //单精度float:N共32位,其中S占1位,E占8位,M占23位。因此小数点后最多精确到23/4=6位 
            //双精度double:N共64位,其中S占1位,E占11位,M占52位。因此小数点后最多精确到52/4=13位 

            //IEEE规则:二进制32位转float【Real】规则
            //第一位为1代表负数,第一位为0代表正数或者0
            //第二位到第九位代表 指数位,对应的值减去127就是移位数【shiftCount】
            //【第十位开始】尾数23位前面加一个1,凑够24位,这个24位尾数的前【shiftCount+1】个数就是整数部分,剩下的就是小数部分

            //整数二进制转为10进制:从低位到高位分别是2的0次幂、1次幂、2次幂……,分别相乘再相加,得到的和即为10进制结果。
            //小数部分的二进制转换位10进制:与整数部分类似,从小数点开始分别是2的-1次幂、-2次幂、-3次幂……,分别相乘再相加,得到的和即为10进制结果,比如001(2进制)对应0.125(10进制)
            byte[] binary32ArraySource = new byte[4] { 80, 32, 241, 71 };
            byte[] binary64ArraySource = new byte[8] { 215, 252, 96, 26, 153, 190, 60, 194 };
            try
            {
                float fNumber = Binary32BitToFloat(binary32ArraySource);
                Console.WriteLine(fNumber);

                double dNumber = Binary64BitToDouble(binary64ArraySource);
                Console.WriteLine(dNumber);

                Console.WriteLine($"-------------下面整体测试通用方法【{nameof(BinaryBitToFractional)}】-------------");
                fNumber = BinaryBitToFractional<float>(binary32ArraySource);
                Console.WriteLine(fNumber);
                dNumber = BinaryBitToFractional<double>(binary64ArraySource);
                Console.WriteLine(dNumber);
            }
            catch (Exception ex) 
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine(); 
        }

        /// <summary>
        /// 32位二进制转化为对应的浮点数float【Real】
        /// </summary>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        private static float Binary32BitToFloat(byte[] binaryArraySource) 
        {
            if (binaryArraySource == null || binaryArraySource.Length != 4) 
            {
                throw new ArgumentException($"源数组不能为空并且有且只有4个元素", nameof(binaryArraySource));
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转,反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为32位二进制,为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用1位,为【{signString}】");
            string exponent = binaryString.Substring(1, 8);
            int shiftCount = Convert.ToInt32(exponent, 2) - 127;
            Console.WriteLine($"指数位为8位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】,共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(9);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为23位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分:从低位到高位 依次是2的0次方,2个1次方,2的2次方,然后累加
            long numberInteger = 0;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分:从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert,整数也为【{Convert.ToInt32(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            Console.WriteLine($"32位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToSingle(binaryArraySource, 0)}】");
            return float.Parse(destNumber);
        }

        /// <summary>
        /// 64位二进制转化为对应的双精度浮点数double【Double】
        /// </summary>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        private static double Binary64BitToDouble(byte[] binaryArraySource)
        {
            if (binaryArraySource == null || binaryArraySource.Length != 8)
            {
                throw new ArgumentException($"源数组不能为空并且有且只有8个元素", nameof(binaryArraySource));
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转,反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为64位二进制,为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用1位,为【{signString}】");
            string exponent = binaryString.Substring(1, 11);
            int shiftCount = Convert.ToInt32(exponent, 2) - 1023;
            Console.WriteLine($"指数位为8位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】,共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(12);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为52位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分:从低位到高位 依次是2的0次方,2个1次方,2的2次方,然后累加
            long numberInteger = 0L;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分:从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert,整数也为【{Convert.ToInt64(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            Console.WriteLine($"64位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToDouble(binaryArraySource, 0)}】");
            return double.Parse(destNumber);
        }

        /// <summary>
        /// 通用的二进制32位或64位 转浮点小数
        /// </summary>
        /// <typeparam name="T">仅支持float和double</typeparam>
        /// <param name="binaryArraySource"></param>
        /// <returns></returns>
        private static T BinaryBitToFractional<T>(byte[] binaryArraySource) where T : struct 
        {
            if (typeof(T) != typeof(float) && typeof(T) != typeof(double)) 
            {
                throw new Exception($"类型错误,必须是浮点数类型【float或double】");
            }
            if (binaryArraySource == null) 
            {
                throw new ArgumentException($"源数组不能为空", nameof(binaryArraySource));
            }
            if (typeof(T) == typeof(float) && binaryArraySource.Length != 4)
            {
                throw new ArgumentException($"转化为float时,源数组必须有且只有4个元素", nameof(binaryArraySource));
            }
            if (typeof(T) == typeof(double) && binaryArraySource.Length != 8)
            {
                throw new ArgumentException($"转化为double时,源数组必须有且只有8个元素", nameof(binaryArraySource));
            }

            //单精度float:N共32位,其中S占1位,E占8位,M占23位。因此小数点后最多精确到23/4=6位 
            int signBitCount = 1;//符号位数,代表正数还是负数
            int exponentBitCount = 8;//指数位数
            int mantissaBitCount = 23;//尾数位数
            int totalBitCount = 32;//二进制总位数
            if (typeof(T) == typeof(double))
            {
                //双精度double:N共64位,其中S占1位,E占11位,M占52位。因此小数点后最多精确到52/4=13位 
                exponentBitCount = 11;//指数位数
                mantissaBitCount = 52;//尾数位数
                totalBitCount = 64;//二进制总位数
            }
            byte[] binaryArray = binaryArraySource.Reverse().ToArray();
            Console.WriteLine($"将数组顺序反转,反转后为【{string.Join(",", binaryArray)}】");
            IEnumerable<string> binaryCollection = binaryArray.Select(element => Convert.ToString(element, 2).PadLeft(8, '0'));
            string binaryString = string.Join("", binaryCollection);
            Console.WriteLine($"转化为【{totalBitCount}】位二进制,为【{string.Join("\x20", binaryCollection)}】");
            string signString = (binaryString[0] == '1' ? "-" : "+");
            Console.WriteLine($"符号位占用【{signBitCount}】位,为【{signString}】");
            string exponent = binaryString.Substring(1, exponentBitCount);
            int shiftCount = Convert.ToInt32(exponent, 2) - (1 << (exponentBitCount - 1)) + 1;
            Console.WriteLine($"指数位为【{exponentBitCount}】位【{exponent}】,对应数字【{Convert.ToInt32(exponent, 2)}】,共移动【{shiftCount}】位");
            string mantissa = binaryString.Substring(signBitCount + exponentBitCount);
            string dotString = $"1.{mantissa}";
            Console.WriteLine($"尾数位为【{mantissaBitCount}】位【{mantissa}】,尾数位前面添加一个1并插入移位小数点,字符串为【{dotString}乘以2的{shiftCount}次方】");
            dotString = dotString.Replace(".", "").Insert(shiftCount + 1, ".");
            Console.WriteLine($"即【{dotString}】");
            string integerPart = dotString.Substring(0, shiftCount + 1);//整数部分
            string fractionalPart = dotString.Substring(shiftCount + 2);//小数部分

            //整数部分:从低位到高位 依次是2的0次方,2个1次方,2的2次方,然后累加
            long numberInteger = 0L;
            for (int i = 0; i < integerPart.Length; i++)
            {
                if (integerPart[i] == '1')
                {
                    numberInteger += (1L << (integerPart.Length - 1 - i));
                }
            }
            //小数部分:从小数点开始分别是2的-1次幂、-2次幂、-3次幂……
            decimal numberFractional = 0M;
            for (int i = 0; i < fractionalPart.Length; i++)
            {
                if (fractionalPart[i] == '1')
                {
                    numberFractional += (decimal)Math.Pow(2, -1 - i);
                }
            }
            Console.WriteLine($"整数部分【{integerPart}】,对应整数为【{numberInteger}】.或者使用Convert,整数也为【{Convert.ToInt64(integerPart, 2)}】");
            Console.WriteLine($"小数部分【{fractionalPart}】,对应小数【{numberFractional}】");
            string destNumber = $"{signString}{numberInteger + numberFractional}";
            if (typeof(T) == typeof(float))
            {
                Console.WriteLine($"【{totalBitCount}】位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToSingle(binaryArraySource, 0)}】");
                return (T)(object)float.Parse(destNumber);
            }
            else 
            {
                Console.WriteLine($"【{totalBitCount}】位二进制对应的浮点数为【{destNumber}】,使用BitConverter转换为浮点数的结果为【{BitConverter.ToDouble(binaryArraySource, 0)}】");
                return (T)(object)double.Parse(destNumber);
            }
        }
    }
}

The program runs as shown in the figure:

 

Guess you like

Origin blog.csdn.net/ylq1045/article/details/130807358