浮点数
什么是浮点数?为什么不叫做小数(数学之中的概念)?
因为计算机资源的限制,无法准确地表示小数,所以科学家发明了浮点数的概念,来近似地 表示小数。
浮点数是指用符号、尾数、基数和指数这四部分来表示的小数。
单精度浮点数 双精度浮点数
单精度为什么叫单,单和双针对的是什么?
根据IEEE754的规范,要表达的数字占32位是个基准,称为“单”,32位的整数倍即为“几倍精度”。所以还有“半精度”、“双精度”、“四倍精度”、“任意精度”等
单精度浮点数 双精度浮点数的差别
单精度 占据 4个字节
双精度 占据 8个字节
单精度 用 1位表示符号位 8位表示指数 23位表示尾数
双精度 用 1位表示符号位 11位表示指数 52位表示尾数
为什么要区分单精度浮点数与双精度浮点数,直接使用一个概念浮点数不行嘛?
自己比较浅显的理解:
还是受限于计算机的资源限制,区分出不同的浮点数(占据的字节书不同),利于节约资源。
精度
浮点数之中的精度 是什么意思?
自己目前的理解为:
浮点数所能够表示的最大有效位数。浮点数所能表示的最大有效位数是由尾数来决定的。
单精度浮点数的尾数 = 23 + 1 = 24位,可以表示(5-7)位的有效位数。(自己的理解,计算机可以准确地表示类似1.000005 这样的小数,如果再加一位,单精度浮点数就无法表示了)
双精度浮点数的尾数 = 52 + 1 = 53位,可以表示(15-17)位的有效位数(转换为十进制)
备注:
有效位数 就是 从左数到右的数字数目。
二进制表示浮点数
使用科学计数法的规则来表示浮点数,只是指数设置为2。 例子:
1.01 * 2^2
单精度 占据 4个字节
双精度 占据 8个字节
单精度 用 1位表示符号位 8位表示指数 23位表示尾数
双精度 用 1位表示符号位 11位表示指数 52位表示尾数
计算机 表示 浮点数 的局限性
什么是浮点数精度丢失问题
第一步是十进制的小数 转 二进制。这一步的转换可能会存在精度丢失,例如 0.1转换为二进制,转换后的二进制重新转换为十进制,两者会存在细微的偏差。
浮点数精度丢失问题产生的原因
因为 有些 小数 在使用转换规则 转换为二进制的时候,会出现无限循环的问题,而计算机的资源是有限的,只能使用有限的位来表示小数, 故而计算机在存储此小数的时候,会舍弃超出范围的位数,导致二进制转换为十进制的时候,数值会小于原来的值。
为什么计算机可以输出0.3的值
var c float64 = 0.3
fmt.Println(c) // 输出的值 = 0.3 ,而不是0.3000004
以下是我搜索到的链接,解答上述的问题: stackoverflow.com/questions/3…
自己大致的理解是与语言的打印规则有关。
以下的代码输出,则不会输出 0.3
var c float64 = 0.3
fmt.Printf("%.17f", c)
了解浮点数,对于程序员的意义是什么?换个问法,如何正确地使用浮点数?
-
浮点数的运算 (加 减 乘 除 等操作)
由于浮点数的精度丢失,会导致最终的数据和预期的不一致,这个是需要在脑海之中建立认知的。 -
浮点数之间比较大小。
因为浮点数的精度丢失问题,尽量不要用 if floatA == floatB 这样的语法来进行判断,可能会出现意想不到的问题。
既然浮点数的精度丢失问题存在,如何来规避这个问题造成的影响,来保持程序的正确性呢?
对于golang 而言,如果要使用浮点数 进行算术运算,以及比较大小,可以使用 github.com/shopspring/decimal 包 来解决问题。
对于不同的语言,那么程序员在需要进行浮点数运算的时候,就要注意思考,所使用的这门语言,针对浮点数的精度丢失问题,所提供的解决方案是什么,针对性地进行搜索,然后进行编程。
记录一下浮点数的应用场景(商品单价)
钱的计算是不能差的,不能出现多或者少。商品的单价一般都会带小数类型的后缀的。虽然不同的语言针对浮点数的精度丢失问题,都会给出对应的解决方案,但是对于浮点数精度丢失的问题,最好的解决方法还是不使浮点数产生。
自己的理解,应该针对业务场景而采取不同的解决方案。所以在业务上面,就可以限制商品单价的设置最多到小数点后的几位,同时数据库之中,按整数来存储商品的单价。例如,商品的单价最小单位是分,那么数据库之中的字段以分为最小单位,采用长整型来存储。在业务上规定具体的逻辑,同时采用合适的方式来规避问题。
看到钱的计算的时候,还是提醒一下自己,浮点数的精度丢失问题,别到时候坑了自己。