首页 » PHP教程 » php浮点比拟年夜小技巧_深入理解计算机系统 浮点 01 02 不等于 03

php浮点比拟年夜小技巧_深入理解计算机系统 浮点 01 02 不等于 03

访客 2024-11-09 0

扫一扫用手机浏览

文章目录 [+]

为什么是一种近似值的演出办法?

由于打算机是二进制表示,通过2^-n ,表示小数点的数字,这种办法有些数字不能表示出来

php浮点比拟年夜小技巧_深入理解计算机系统  浮点  01  02 不等于 03

如 0.1 ~= 0.100000001490116119384765625,通过打算机CPU的精度进行减少偏差

php浮点比拟年夜小技巧_深入理解计算机系统  浮点  01  02 不等于 03
(图片来自网络侵删)

打算机是若何表示的

浮点分,单精度与双精度,在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.

标签:

相关文章

介绍白点控制之路,从原理到方法

白点,作为生活中常见的现象,无处不在。对于如何控制白点,许多人却感到困惑。本文将从原理出发,探讨白点的控制方法,并结合实际案例,为...

PHP教程 2025-01-03 阅读1 评论0

介绍直播王者,如何开启你的电竞直播之旅

随着电竞产业的蓬勃发展,越来越多的年轻人投身于电竞直播行业。王者荣耀作为一款备受欢迎的MOBA手游,吸引了大量玩家和观众。如何开启...

PHP教程 2025-01-03 阅读1 评论0