zoukankan      html  css  js  c++  java
  • c# folat, double, decimal分析

    c#中,在小数后面加f表示float,d表示double,m表示decimal,不加默认是double

    var a = 1.0f; //float
    var b = 1.0d; // double
    var c = 1.0m; // decimal

    一直没搞懂为什么需要这么多类型,下面看一下它们能表示的范围以及内部存储,其中float和double属于浮点型,decimal是MS推出的另一种类型

    范围和精度

      字节数 范围 小数点
    float 4 -2128 ~ +2128,也即-3.40E38 ~ +3.40E38 223 = 8388608,也就是7
    double 8 -21024 ~ +21024,也即-1.79E308 ~ +1.79E308 252 = 4503599627370496也就是16
    decimal 16  -(296 - 1) to 296 - 1 28

    内存存储

    • float(32位):
      float的指数部分有8bit(2^8),由于是有符号型,所以得到对应的指数范围-128~128。由于float的指数部分对应的指数范围为-128~128,所以取值范围为: 
      -2128到2128,约等于-3.4E38 — +3.4E38 

      浮点数的计算有一篇文章写的非常好,写出了浮点型的内部存储详细规则以及为什么会有精度损失

      https://blog.csdn.net/u011305680/article/details/80264508

    这里写图片描述

    • double(64位):
      double的指数部分有11bit(2^11),由于是有符号型,所以得到对应的指数范围-1024~1024。 

    这里写图片描述

    • decimal(128位):

    decimal 内部使用 4 个 32-bit 的 System.Int32 来存储,占用 128 bits = 16 bytes。这 128 bits 分配如下:

    96 bits 表示从 0 至 296 - 1 的整数,分布在 3 个 32-bit 的 System.Int32 中。
    剩下的 1 个 32-bit 的 System.Int32 包括符号位和比例因子。
    第 31 bit 是符号位,0 表示正数,1 表示负数。
    第 16 至 23 bit 表示比例因子,必须包含一个 0 至 28 之间的指数,指示 10 的幂,即小数点的位置,也就是小数点右边有几位数字。
    其实表示 0 至 28 之间的指数只需 5 bits 就够了,而上面的第 16 至 23 bit 共 8 bits = 1 byte。也就是说剩下的 3 bits (第 21 至 23 bit) 一定是零。
    其余 bits (0 - 15 bit 和 24 - 30 bit)不被使用,必须为零。

    比较

    由上面2个表可以看出来,浮点型和decimal是完全不同的存储方式

    对于浮点型,

      首先我们要搞清楚下面两个问题:
    
    (1) 十进制整数如何转化为二进制数
    
          算法很简单。举个例子,11表示成二进制数:
    
                    11/2=51
    
                      5/2=21
    
                      2/2=10
    
                      1/2=01
    
                         0结束         
      11二进制表示为(从下往上):1011
    
     (2) 十进制小数如何转化为二进制数
    
          算法是乘以2直到没有了小数为止。举个例子,0.9表示成二进制数
    
                    0.9*2=1.8   取整数部分 1
    
                    0.8(1.8的小数部分)*2=1.6    取整数部分 1
    
                    0.6*2=1.2   取整数部分 1
    
                    0.2*2=0.4   取整数部分 0
    
                    0.4*2=0.8   取整数部分 0
    
                    0.8*2=1.6 取整数部分 1
    
                    0.6*2=1.2   取整数部分 0
    
                    .........   
        0.9二进制表示为(从上往下): 1100100100100......

    上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。这也就解释了为什么浮点型减法出现了”减不尽”的精度丢失问题。

    而对于decimal,整数部分和小数部分都放在后面12个字节内,不存在精度丢失的问题,小数点后面位数保存在另外4个字节的16-23个bit,只要不超出28,就不会有精度损失。下面的代码由字符串转换成decimal,然后获取到了具体的小数位数。

    所以假如在有效位数里面,decimal是不会有精度损失的,财务计算以及位数比较多的科学计算推荐decimal

    相互转换

    这边只考虑精度损失的问题,精度比较大的转换成小的有可能会造成精度损失。

    float -> double, decimal不会造成精度损失

    double-> float可能造成精度损失,double->decimal不会造成精度损失

    decimal->float, double可能会造成精度损失

    decimal和浮点型的相互转换或者加减乘除操作,必须加强制转换

  • 相关阅读:
    背下来就是电脑高手(转)
    split+ Pattern切割字符串
    java中方法中声明三个点“...”作用
    MRUnit测试
    configuration默认设置
    chmod|chown|chgrp和用法和区别
    hadoop 一些文件操作
    关闭SVN服务
    Hadoop如何计算map数和reduce数
    链式mapreduce
  • 原文地址:https://www.cnblogs.com/xiaojidanbai/p/13236023.html
Copyright © 2011-2022 走看看