为什么是一种近似值的演出办法?
由于打算机是二进制表示,通过2^-n ,表示小数点的数字,这种办法有些数字不能表示出来
如 0.1 ~= 0.100000001490116119384765625,通过打算机CPU的精度进行减少偏差

打算机是若何表示的
浮点分,单精度与双精度,在64位系统里面差异在于单精度利用32位,双精度利用64位
我们来看看它的构造
S singificand 表示符号位,0表示正数,1表示负数
Exp exponent 表示阶码(E),表示科学计数法的 n,打算机利用二进制 因此利用 2^E, 阶码的意思是指,二进制数的小数点向左移动多少位才剩下 1. 或 0. 为首位的
Frac, 表示用二进制表示小数点后的数, M表示十进制,解释能存储多少位小数,有些无限循环的二进制当位数不足会采取偶数舍入办法进位
单精度,s=1bit, exp = 8bit, frac = 23bit
双精度,s=1bit, exp = 11bit, frac = 52bit
其IEEE 浮点标准表示办法,V=(-1)^s x M x 2^E
以是10.5 是若何存储的
我们须要把上面的数拆解为 V=(-1)^s x M x 2^E
10.5 转 二进制,分两部分 10的二进制 = 1010, 0.5 的二进制 0.1 (详细参考十进制转二进制的辗转相乘除法)
因此 10.5的二进制位 1010.01,标准表示办法 1.01001 2^3
关于阶码 E 的解析
e 表示 exp 的二进制,Bias 表示偏移量 = 2^(k-1) - 1, k为exp的位数单精度为8,E= e - Bias 即是阶码
k 表示exp的位数,这里表示8,k=8
e 表示exp的二进制,10000010
Bias 表示偏移量,2^(k-1) - 1,这里k=8 Bias即是 127
E 表示阶码科学计数法的幂,E=e-Bias (e须要转10进制打算),
e - Bias = 3 , Bias = 127 求 e = (3 + 127)二进制 = 10000010
遍及知识
非规格化,exp全为0,指0为头的表示办法,如0.10101. 0.0
规范化,exp 介于0~全1之间
分外化,exp全为1,表示无穷大,nan
为什么须要偏移量 Bias
由于要表示阶码的负数,表示更多的范围,如果没有这个Bias ,exp的取值范围[0,255] ,没有负数,想扩展多0.00000的机会都没有,因此须要bias [-128,127] 为什么是这个值,由于是利用补码
浮点舍入向偶数舍入,将数字向上或向下舍入,使得结果最低有效数字是偶数,如1.4,不到一半,1.4 = 1,-1.5 也变成-2,如果2.5,则变为2,由于偶数舍入是找最近的偶数进行舍入
向零舍入,把整数向下舍入,把负数想上舍入,如 1.4 = 1,1.6 = 1,-1.5 = -1
向下舍入,把整数和负数都向下舍入,1.4 = 1, 1.6 = 1,-1.5 = 2
向上舍入,把正数和负数想上舍入,1.4 = 2,1.6 = 2 , -1.5 = -1
为什么默认采取偶数舍入?
避免了统计偏移,舍入方法把一组数值,打算这些值的均匀数中引入统计偏差,采取欧舍舍入得到一组数的均匀值比这些数本身的均匀值略高,相反向下舍入,比均匀值略低
偶数舍入,在50%时向上舍入,50%,向下舍入
如1.234999 舍入 1.23,1.235舍入1.24
由于在1.23和1.24正中间,有 1.235 和 1.245,两者都舍入到。124,由于4是偶数
有限的精度不是紧张问题,打算相对偏差才是?
如何理解?
例如 0.1 在二进制里面是无限循环,0.0 0011 0011[0011] 括号是无限重复
程序可利用24位存储,在我们的系统中,是利用23位
X = 0.00011001100110011001100
当 0.1 - x 的二进制表示,为 0.000000000000000000000001100[1100],23位都是0,后续1100[1100] 是0.1二进制的剩余
0.1 - x 的十进制值是多少呢?
0.1 = 0.000000000000000000000001100[1100]
x = 0.00011001100110011001100
两者相减为
0.000000000000000000000001100[1100]…不断重复[1100]
终极转化为 0.1 x 2^-20 大约为 9.54 x 10^-8
ps:2^-20 此办法若何来的,0.1 是若何来的
按照上面的 0.000000000000000000000001100[1100]…不断重复[1100],我们抽取 20个零,为 2^-20
然后剩下 0.0001100[1100] 这个便是0.1 因此即是 0.1 x 2^-20
产生了这些偏差,如果在一个运动系统里面进行,相乘100小时,9.54 x 10^-8 x 100 x 60 x 60 x 10 ~= 0.343秒偏差
在乘速率 0.343 v 如 v = 300m/s = 102.9m
这种在航天,导弹,自动驾驶都是至关主要的
假设采取偶数舍入
0.1 ~= 0.00011001100110011001100 采取欧舍办法23位表示,x` = 0.00011001100110011001101
末了的0变为1的缘故原由 0.1 ~=0.00011001100110011001100(11) ,末了两位是11 因此进位
X` - 0.1 表示
0.00011001100110011001101 - 0.0001100110011000110011001100 = 0.000000000000000000001[1100]
个中1100是无限循环
约即是 2^-22 x 0.1,大约即是2.38x10^-8
比较0.1 - x , X` - 0.1 所产生的偏差, 2.38x10^-8 x 100 x 60 x 60 x 10 ~= 0.086, 相差4倍
速率为300m/s 间隔偏差为 25.8m
因此进行舍入是有效处理
实际问题办理
浮点 0.1 + 0.2 不即是 0.3
https://stackoverflow.com/questions/53975208/why-does-it-seem-like-my-floating-point-value-is-not-equal-to-itself
https://stackoverflow.com/questions/3962724/problems-in-floating-point-comparison
办理办法1
许可最大偏差 epsilon,适宜比较大小利用,这个若何用?
代码比对,0.1 + 0.2 = 0.3 时候 涌现给0.3大的数,这便是浮点精度所产生的偏差问题,如,
php -r "var_dump(0.1 + 0.2, (0.1 + 0.2) == 0.3);" 输出 float(0.30000000000000004) bool(false)
这里须要进行两个数比较的时候,须要运行最大偏差值,一些措辞供应一种 espilion 浮点数可表示的最小值
PHP_FLOAT_EPSILON = 2.220446049250313E-16
php -r "var_dump((0.1 + 0.2 - 0.3) <= PHP_FLOAT_EPSILON);”
输出
bool(false)
完备转为10进制,忽略浮点,decimal 库,decimal是打算机仿照出来,给原来的浮点运算是慢非常多,一样平常场景已经知足利用
其余一种办法利用bcmath进走运算
php -r "var_dump(bcadd(0.1,0.2, 17), bcadd(0.1,0.2,17) == 0.3);"
保留小数点17位的缘故原由是由于 0.1 + 0.2 浮点值为 0.30000000000000004 小数点17位
上面实现,bcadd(0.1,0.2, 17) = 0.30000000000000000 且是字符串
实现了 0.3 比对的时候精确比对
考试测验过其他措辞如go措辞
package main import "fmt" func main() { f32 := 0.1 + 0.2 a := fmt.Sprintf(“%.17f", f32); fmt.Println(a); } 输出0.29999999999999999
如果不指定 小数点多少位,golang 默认帮你提取,如 直接 0.1 + 0.2 = 0.3 是相等的,少了很多问题,一旦指定精度如0.1+0.2 一旦指定保留小数17位就会产生误 猜想golang自己进行后续多个00的时候自动偶数舍入
128位long double, 32位 float 与 double 的存储是若何处理的
https://stackoverflow.com/questions/32167925/how-does-a-32-bit-machine-compute-a-double-precision-number
分开存储,针对这更高精度的存储,须要扩大寄存器的利用存储
为什么 0.1 显示到0.1是 但运算的时候会产生差异 0.100000001490116119384765625
由于输入0.1的时候取整后,运算的时候,是全部位数一起进走运算
银行系统是如何处理浮点的?
场景: 用度 of --- $1,290 被9人平分 --- $1,290 / 9 每人能获取到: 143.3333333333 如果这个是银行给客户的 银行不会向上取证,如,保留小数点后两位 ,143.33 而不会143.34 如果是客户给银行的 须要给 143.34
打算机存储构造解析
通过 decimal data type 且与舍入位数处理,数据库的decimal 类型
Decimal 构造
mysql 的实现
http://mysql.taobao.org/monthly/2021/03/02/
struct decimal_t { int intg, frac, len; bool sign; decimal_digit_t buf; }; 通过 buf 数组进行位数// decimal(81, 18) 63 个整数数字, 18 个小数数字, 用满全体 buffer// 123456789012345678901234567890123456789012345678901234567890123.012345678901234567 decimal_t dec_81_digit = { int intg = 63; int frac = 18; int len = 9; bool sign = false; buf = {123456789, 12345678, 901234567, 890123456, 789012345, 678901234, 567890123, 12345678, 901234567} };
java 的 BigInteger 也是差不多通过 数组,切好小数点的长度放入数组里面
https://zazalu.space/2019/09/25/java-amount-calculation/
无符号浮点?
按照IEEE 754的表述,浮点是通过首位0/1表示正负,没有表示为符号型,而且浮点是关心小数点的精度问题
http://steve.hollasch.net/cgindex/coding/ieeefloat.html
总结
有限的精度不是紧张问题,打算相对偏差才是
改进方向,须要提高运算时候的精度,如扩大exp和frac,不断靠近真实数
现在知道 为什么 0.1 + 0.2 不即是 0.3
参考资料
浮点二进制科学打算办法表示,描述 E M 的逻辑关系
https://en.wikipedia.org/wiki/Single-precision_floating-point_format
https://en.wikipedia.org/wiki/Floating-point_arithmetic#Floating-point_arithmetic_operations
https://en.wikipedia.org/wiki/Exponent_bias
https://medium.com/starbugs/see-why-floating-point-error-can-not-be-avoided-from-ieee-754-809720b32175
浮点科学打算办法的转换
https://stackoverflow.com/questions/3954498/how-to-convert-float-number-to-binary
https://stackoverflow.com/questions/10687016/what-is-e-in-floating-point
https://stackoverflow.com/questions/588004/is-floating-point-math-broken
打算器
https://www.h-schmidt.net/FloatConverter/IEEE754.html
https://www.binaryconvert.com/result_float.html?decimal=048046048049
https://tool.oschina.net/hexconvert/
银行处理浮点
https://www.reddit.com/r/webdev/comments/73vtwv/financial_calculations_large_decimal_precision/
https://www.zhihu.com/question/22536323
https://en.m.wikipedia.org/wiki/Decimal_data_type
bias参考资料
https://en.wikipedia.org/wiki/Exponent_bias
https://sites.google.com/site/nutncsie10412/ge-ren-jian-jie/fu-dian-shu-biao-shi-fa
https://stackoverflow.com/questions/2835278/what-is-a-bias-value-of-floating-point-numbers#:~:text=By%20using%20a%20bias%20representation,looks%20like%20a%20smaller%20integer.&text=As%20you%20can%20see%2C%20even,out%20in%20the%20correct%20order.