C#中32位浮点数Float(Real)一步步按位Bit进行分析

目录
  • C#代码示例如下
  • 程序运行结果
  • 关于32位浮点数的一些理解
    • 1、定点的缺点
    • 2、对于定点123.625
    • 3、翻译一下
    • 4、定点转浮点实例:123.625用32位浮点表示
    • 5、验证
    • 6、浮点转定点实例

我们都知道单精度浮点数(Single,float,Real)由32位0或1组成,它具体是如何来的。

浮点数的32位N=1符号位(Sign)+8指数位(Exponent)+23尾数部分(Mantissa)

  • 符号位(Sign) : 0代表正,1代表为负【占1位】
  • 指数位(Exponent)::用于存储科学计数法中的指数数据,并且采用移位存储【占8位】
  • 尾数部分(Mantissa):尾数部分【占23位】
  • 单精度float:N共32位,其中S占1位,E占8位,M占23位。因此小数点后最多精确到23/4=6位 。

C#代码示例如下

using System;
using System.Collections.Generic;
using System.Linq;
namespace ConverterAndPrecisionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //参考博客:https://blog.csdn.net/zhengyanan815/article/details/78550073
            //小数点后面:4个位占用一个数字【十进制9就是1001】
            //符号位(Sign) : 0代表正,1代表为负【占1位】
            //指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储【占8位】
            //尾数部分(Mantissa):尾数部分【占23位】
            //单精度float:N共32位,其中S占1位,E占8位,M占23位。因此小数点后最多精确到23/4=6位 
            //双精度double:N共32位,其中S占1位,E占11位,M占52位。因此小数点后最多精确到52/4=13位 
            //十进制小数的二进制表示:【法则--整数部分:除基取余,逆序拼接。小数部分:乘基取整,顺序拼接】
            //整数部分:除以2,取出余数,商继续除以2,直到得到0为止,将取出的余数逆序。可以使用栈Stack
            //小数部分:乘以2,然后取出整数部分,将剩下的小数部分继续乘以2,然后再取整数部分,一直取到小数部分为零为止。如果永远不为零,则按要求保留足够位数的小数,最后一位做0舍1入。将取出的整数顺序排列。可以使用队列Queue
            float f = 123456.8125F;
            byte[] buffer = BitConverter.GetBytes(f);
            Console.WriteLine("打印浮点数对应的4个字节:");
            Console.WriteLine(string.Join(",", buffer));
            Console.WriteLine($"【使用函数】{123456}对应的二进制:{ Convert.ToString(123456, 2)}");
            int num = 123456;
            Stack<int> stack = new Stack<int>();
            while (num != 0)
            {
                int cur = num % 2;
                stack.Push(cur);
                num = num / 2;
            }
            Console.WriteLine($"【使用堆栈】{123456}对应的二进制:{ string.Join("", stack)}");
            int scale = 10;
            int index = 0;
            double d = 0.8125;
            Queue<int> queue = new Queue<int>();
            while (index < scale)
            {
                int cur = (int)(d * 2);
                queue.Enqueue(cur);
                d = d * 2 - cur;
                if (d == 0)
                {
                    break;
                }
                index++;
            }
            Console.WriteLine($"{0.8125}对应的二进制:{ string.Join("", queue)}");
            string binaryDisplay = string.Join("", stack) + "." + string.Join("", queue);
            Console.WriteLine($"{123456.8125}对应的二进制为{binaryDisplay}");
            int dotIndex = binaryDisplay.IndexOf('.');
            //移除小数点后将小数点插入索引1的位置【即:小数点移动到索引1的位置】
            string scienceDisplay = binaryDisplay.Remove(dotIndex, 1).Insert(1, ".");
            Console.WriteLine($"小数{123456.8125}对应的二进制科学计数为{scienceDisplay}×(2的{dotIndex - 1}次方)");
            string sign = (f > 0 ? "0" : "1");//符号位占用1位
            Console.WriteLine($"符号位S:正数为0,负数为1。符号位是:{sign}");
            string exponent = Convert.ToString(127 + (dotIndex - 1), 2).PadLeft(8, '0');//指数位占用8位
            Console.WriteLine($"指数位E:123456最高位为2的{dotIndex - 1}次方,指数为{dotIndex - 1},因此指数位E的十进制值为【127+{dotIndex - 1}={127 + dotIndex - 1}】");
            //尾数部分:去除scienceDisplay开始的"1.",也就是字符串从索引2开始。并凑够23位
            string mantissa = scienceDisplay.Substring(2).PadRight(23, '0');//尾数位占用23位
            Console.WriteLine($"尾数位M:尾数部分M需要凑够23位。为【{mantissa}】");
            string joinBits = sign + exponent + mantissa;//符号位占用1位+指数位占用8位+尾数位占用23位=32位
            byte[] bufferJoin = new byte[4];
            for (int i = 0; i < 4; i++)
            {
                bufferJoin[i] = Convert.ToByte(joinBits.Substring(8 * i, 8), 2);
            }
            Console.WriteLine("重新拼接形成的32位浮点数,对应的4个字节为:");
            Console.WriteLine(string.Join(",", bufferJoin));
            byte[] reverseBuffer = bufferJoin.Reverse().ToArray();
            Console.WriteLine("反转数组bufferJoin的顺序:重新打印我们会发现与浮点数原始的字节完全一致。注意:C#是低字节在前");
            Console.WriteLine(string.Join(",", reverseBuffer));
            Console.ReadLine();
        }
    }
}

程序运行结果

关于32位浮点数的一些理解

1、定点的缺点

对于一个系统可能出现一些特别大的数和特别小的数,如果用定点表示就会很僵硬,位数一定就不能同时表达特别大的数和特别小的数。

2、对于定点123.625

用科学计数法的方式可以写成1.23625*10^2,也可以写成12.625*10^1或1.111011101*2^6。。。。。为了规范,IEEE就规定了32位浮点的格式如下

3、翻译一下

(1)最高位是符号位,“0”代表正,“1”代表负。

(2)接下来的8位是指数位,8位可表示整数的范围是0-255,考虑指数可以是负的,IEEE规定在上面的范围减去127,并将-127(全0)和128(全1)用做特殊值处理,所以指数的位的范围是(-127,128)。

(3)最低的23位是小数位(尾数位),正常是可以表示23位的范围,但是IEEE规定小数点左侧必须为1,右侧位数不够补0。这样可以就可以省略1,可以用23位来表示24位。

eg. 1.111011101*2^6中,小数位是111011101+补14个0

4、定点转浮点实例:123.625用32位浮点表示

科学计数法=1.111011101*26(整数部分:123=01111011b,小数部分:0.625=0.101b,整数部分除2取余,倒序排列,高位补零;小数部分乘2取整,顺序排列)

符号位:0

指数位:6+127=10000101

小数位:11101110100000000000000

即:01000010111101110100000000000000=0x42F74000

5、验证

6、浮点转定点实例

42F74000=01000010111101110100000000000000,拆分为符号位、指数位、小数位。

(1)符号位:0

(2)指数位:10000101=133,实际指数=133-127=6

(3)小数位:11101110100000000000000去掉后面的0、前面补1为1. 111011101

即科学计数法表示为1. 111011101*26=(2^0+2^-1+2^-2+2^-3+2^-5+2^-6+2^-7+2^-9)*2^6=123.625。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C#中float的取值范围和精度分析

    本文实例分析了C#中float的取值范围和精度.分享给大家供大家参考.具体分析如下: float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double. 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中不使用后缀,则会因为您尝试将一个 double值存储到 float 变量中而发生编译错误. float的取值范围 float占用4个字节,和int是一样,也就是32bit. 1bit(符号位) 8bits(指数位)

  • C#浮点数的表示和基本运算

    1 浮点数的表示 通常,我们可以用下面的格式来表示浮点数 S P M 其中S是符号位,P是阶码,M是尾数 对于IBM-PC而言,单精度浮点数是32位(即4字节)的,双精度浮点数是64位(即8字节)的.两者的S,P,M所占的位数以及表示方法由下表可知 S P M 表示公式 偏移量 1 8 23 (-1)S*2(P-127)*1.M 127 1 11 52 (-1)S*2(P-1023)*1.M 1023 以单精度浮点数为例,可以得到其二进制的表示格式如下 S(第31位) P(30位到23位) M(

  • 浮点数在计算机中存储方式是怎样的

    C语言和C#语言中,对于浮点类型的数据采用单精度类型(float)和双精度类型(double)来存储,float数据占用32bit,double数据占用64bit,我们在声明一个变量float f= 2.25f的时候,是如何分配内存的呢?如果胡乱分配,那世界岂不是乱套了么,其实不论是float还是double在存储方式上都是遵从IEEE的规范的,float遵从的是IEEE R32.24 ,而double 遵从的是R64.53. 无论是单精度还是双精度在存储中都分为三个部分: 1.符号位(Sign

  • C#中32位浮点数Float(Real)一步步按位Bit进行分析

    目录 C#代码示例如下 程序运行结果 关于32位浮点数的一些理解 1.定点的缺点 2.对于定点123.625 3.翻译一下 4.定点转浮点实例:123.625用32位浮点表示 5.验证 6.浮点转定点实例 我们都知道单精度浮点数(Single,float,Real)由32位0或1组成,它具体是如何来的. 浮点数的32位N=1符号位(Sign)+8指数位(Exponent)+23尾数部分(Mantissa) 符号位(Sign) : 0代表正,1代表为负[占1位] 指数位(Exponent)::用于

  • 基于C++浮点数(float、double)类型数据比较与转换的详解

    浮点数在内存中的存储机制和整型数不同,其有舍入误差,在计算机中用近似表示任意某个实数.具体的说,这个实数由一个整数或定点数(即尾数)乘以某个基数(计算机中通常是2)的整数次幂得到,这种表示方法类似于基数为10的科学记数法.所以浮点数在运算过程中通常伴随着因为无法精确表示而进行的近似或舍入.但是这种设计的好处是可以在固定的长度上存储更大范围的数.1.将字符串转换为float.double过程存在精度损失,只是float.double各自损失的精度不相同而已std::string str="8.2&

  • MySQL中Decimal类型和Float Double的区别(详解)

    MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,double等非标准类型,在DB中保存的是近似值,而Decimal则以字符串的形式保存数值. float,double类型是可以存浮点数(即小数类型),但是float有个坏处,当你给定的数据是整数的时候,那么它就以整数给你处理.这样我们在存取货币值的时候自然遇到问题,我的default值为:0.00而实际存储是0,同样我存取货币为12.00,实际存储是12. 幸好mysql提供

  • JavaScript 获取任一float型小数点后两位的小数

    用Javascript取float型小数点后两位,例22.127456取成22.13,如何做? 1.这种方法最不推荐: function get(){ var s = 22.127456 + ""; var str = s.substring(0,s.indexOf(".") + 3); alert(str); } 2. 使用正则表达式获取: function get(){ var a = "23.456322"; var aNew; var r

  • ASP中格式化时间短日期补0变两位长日期的方法

    因为短日期不足2位,所以在网页排版的时候,影响美观,下面两个函数可以解决这个问题. 2020-2-7短日期 变 2020-02-07长日期 Function FStime(times) Dim years,months,days if len(times)=0 then exit function years=year(times) months=right("0"&month(times),2) days=right("0"&day(times),

  • Python如何保留float类型小数点后3位

    目录 保留float类型小数点后3位 float 一.round() 二.'%.3f'%x 三.decimal 小数点后的位数 第一种方法 第二种方法 第三种方法 保留float类型小数点后3位 float 查询持仓数据,数字货币交易所一般给出的是float类型,且小数点十几位,为了展示便捷,只保留小数点后3位. float数据类型,保留小数点的方式有三种 一.round() >> x = 3.897654326 >> round(x, 3) 3.898 >> x =

  • Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而Ima

  • js正则表达式 限1-2位整数,或者至多含有两位小数的写法

    测试代码 <script type="text/javascript"> //1.只能输入数字或者小数点 仅整数,整数加小数 var reg1=/(^[0-9]{1,2}$)|(^[0-9]{1,2}[\.]{1}[0-9]{1,2}$)/; console.log(reg1.test("")+" 空串 false"); console.log(reg1.test("1")+" 1 true")

  • 脚本中出现 window.open() access is denied - 拒绝访问 情况一则及分析

    也许这个状况有的朋友已经知道了,但我还是把自己的分析思路写下来给其他的朋友参考. 昨天把blog页面另存在,在本地调试和改blog皮肤. 简介: 我想在onload页面加载完时用脚本控制,把Run HTML code, CopyCode, SaveCode这三个按扭动态的添加到css类名为code_textarea的多行文本框里. 状况描述: 在非服务器端(即没有在本地服务器下调试)按扭已经全部出现在多行文本框下,但在调试脚本时(点击Run HTML code),出现拒绝访问...服务器下调试正

  • 在Yii2中使用Pjax导致Yii2内联脚本载入失败的原因分析

    当我用defunkt/jquery-pjax载入Yii2的ActiveForm时发生一个错误,正常情况下是 ActiveForm的两个js应该先载入,而实际情况是 typeError:JQuery(...).yiiActiveForm is not a function. 在github的issues对这个问题已经讨论并得到了解决. Pjax首先通过html()执行内联的<script>,然后才通过executeScriptTags()执行带着src的<script>,所以导致找不

随机推荐