学python第四天遇到一个奇怪的问题
其中遇到一个怪事,有个list我的创建方法和答案不太一样0是我的解法,1是标准答案
possible_ms_1 =
possible_ms_0 =
print(possible_ms_1)
print(possible_ms_0)
print(possible_ms_1 == possible_ms_0)1号输出是这样的
[-1.0, -0.9, -0.8, -0.7000000000000001, -0.6000000000000001, -0.5, -0.4, -0.30000000000000004, -0.2, -0.1, 0.0, 0.1, 0.2, 0.30000000000000004, 0.4, 0.5, 0.6000000000000001, 0.7000000000000001, 0.8, 0.9, 1.0]0号输出是这样的
[-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]为什么!这尼玛不是一个意思么!!为什么会不一样!!
PS: 在做的是codecademy的小作业,直接导致了part2最后算出来的结果不一样
jupyter链接在这
https://static-assets.codecademy.com/Paths/data-science-career-path/linear-regression/Reggies-Linear-Regression.zip
有兴趣的可以把标准答案里的 "* 0.1",改成"/ 10"试试看
想了一晚上都没想通,郁闷睡觉
本帖最后由 13号 于 2022-5-5 00:11 编辑
不知道为啥,但是简单的说,float本来就是近似表达,看起来只是这两种计算方式下,表达的数据有区别。
你可以认为作为float时, -0.7000000000000001 和 -0.7 就是一个值。 "正确"的float判断是否相等的方式就是设置一个阈值,只要小于这个阈值就认为是同一个数。 瞎猜的,你乘0.1相当于转浮点了,除以10还当整数?
编程语言里本来二进制数据放十进制算就回出现莫名其妙的零头。要不你换换用numpy 或者mathematia 试试。 nexus1 发表于 2022-5-5 00:07
瞎猜的,你乘0.1相当于转浮点了,除以10还当整数?
编程语言里本来二进制数据放十进制算就回出现莫名其妙的 ...
>>> list(map(type, possible_ms_1))
[<class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>]
>>> list(map(type, possible_ms_0))
[<class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>, <class 'float'>]
都是浮点(其实第二个不是浮点的话,直接就是0,1了,不会出现小数) 因为10是准确数,0.1是近似数 本帖最后由 littleneko 于 2022-5-5 00:21 编辑
IEEE754 浮点数的精度问题,0.1 已经不能被精确表示了,再说 float/double == 比较是没有意义的,看来 codecademy 里是用的 == 比较的浮点数的值,可以狠狠地批判一番了 10是精确的10,0.1是个0.10000000001之类的玩意
— from motorola XT2125-4, Android 11 of S1 Next Goose v2.5.2-play https://juejin.cn/post/7010416601711427615
楼上好像都没提到,楼主可能不知道这个知识点,先看看浮点数的精度问题吧 本帖最后由 革萌 于 2022-5-5 01:00 编辑
就是float算不准 https://0.30000000000000004.com/
这是个经典梗了。
所以浮点型判断,不要用等号,而应该用专门的isclose函数。
>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
>>> import math
>>> import numpy as np
>>> math.isclose(0.1+0.2, 0.3)
True
>>> np.isclose(0.1+0.2, 0.3)
True 兄弟这是之前没学过别的语言啊。。所有语言统统都有float问题,像java里就是用BigDecimal来解决算钱之类的高精度浮点 kll85757 发表于 2022-5-5 02:26
我一直以为只有js有浮点运算的精度问题。。
不然为什么float和double的中文叫单精度浮点和双精度浮点
只要它还是二进制计算机就一定会有这样的问题 本帖最后由 alann 于 2022-5-5 08:19 编辑
这个问题我也一直没完全搞明白,为什么1/10直接出来0.1,不是说0.1无法被被浮点精确表示吗?楼里已经有人验证了算出来的数是float型,既然是用float储存,为什么还能精确显示出0.1? alann 发表于 2022-5-5 08:10
这个问题我也一直没完全搞明白,为什么1/10直接出来0.1,不是说0.1无法被被浮点精确表示吗?楼里已经有人验 ...
最简单的实现就是舍弃小于阈值的尾数,再依次去掉末尾的0,然后输出就是了啊。 alann 发表于 2022-5-5 08:10
这个问题我也一直没完全搞明白,为什么1/10直接出来0.1,不是说0.1无法被被浮点精确表示吗?楼里已经有人验 ...
因为大部分语言显示浮点数都会自动rounding。
rounding 方式方法都不尽相同,屏幕显示数和实际数也多少有些出入,显示相同的数也不一定实际相同。 kll85757 发表于 2022-5-5 02:26
我一直以为只有js有浮点运算的精度问题。。
乆都是JS的错啦
—— 来自 Xiaomi Redmi K30 5G, Android 11上的 S1Next-鹅版 v2.5.4 学了点pandas来处理表格,就发现这个问题了,原来是这个原因,顺道问一下,一般这种情况标准是怎么处理的?我都是每次round一下 接着用就是了,你又不造火箭在乎这点误差?或者你学python是为了输出数值龟龟整整的好看? 大概理解了
那为什么这两个list里面
调用每一个去==对比
像-1.0 -0.9这些都没事是true,偏偏-0.7就有问题false呢?
—— 来自 OnePlus KB2005, Android 12上的 S1Next-鹅版 v2.5.4 很简单,浮点数有精度位数
有些浮点运算后二进制表示是一致的,就是相等
有些浮点运算会导致二进制表示跟直接写出来的浮点数不等,那就失败 所以是不是/10的这些数实际也带了很长的尾巴,只是这些变量有个打印时自动rounding的开关是开的,而乘0.1算出来的变量的这个开关是关的。 本帖最后由 tsubasa9 于 2022-5-5 10:26 编辑
alann 发表于 2022-5-5 10:18
所以是不是/10的这些数实际也带了很长的尾巴,只是这些变量有个打印时自动rounding的开关是开的,而乘0.1算 ...
不是,这是浮点数的ieee表示的问题,不是什么rounding不rounding的问题
在ieee表示下浮点数的乘法和除法的过程,和人类习惯的运算方法并不相同,导致结果不一致
tsubasa9 发表于 2022-5-5 10:21
不是,这是浮点数的ieee表示的问题,不是什么rounding不rounding的问题
那还是1/10和1*0.1在内存中的储存值不一样?虽然类型都是float? alann 发表于 2022-5-5 10:25
那还是1/10和1*0.1在内存中的储存值不一样?虽然类型都是float?
浮点数的乘法和除法在ieee表示下并不是通常的那种,并不是精确的倒数关系 本帖最后由 superlattice 于 2022-5-5 11:12 编辑
alann 发表于 2022-5-5 10:25
那还是1/10和1*0.1在内存中的储存值不一样?虽然类型都是float?
二进制乘除法和十进制乘除法实现不一样,不是互为逆运算
如果按楼上都指定十进制运算就没事,解释器内部会用别的逻辑
如果一个11进制的外星人脑控地球人(只会进制转换和10进制运算)做浮点运算,也会出现类似的问题
【【官方双语】我试图搞坏这台100万刀的电脑 - 逛逛IBM Z16大型机#linus谈科技-哔哩哔哩】 https://b23.tv/dDNk6lL
这玩意内部有原生10进制BCD码运算器,普通二进制计算机没有,也是制霸金融业这种快算十进制数需求的原因之一。 superlattice 发表于 2022-5-5 11:07
二进制乘除法和十进制乘除法实现不一样,不是互为逆运算
如果按楼上都指定十进制运算就没事,解释器内部 ...
可是不管过程怎么计算,终归结果还是用float储存的吧,说明float也是可以精确储存0.1的? 本帖最后由 tsubasa9 于 2022-5-5 11:22 编辑
alann 发表于 2022-5-5 11:18
可是不管过程怎么计算,终归结果还是用float储存的吧,说明float也是可以精确储存0.1的? ...
单就这个问题,不行
0.1用ieee表示末尾有一串小数,只是不显示而已
虽然楼上讲了一堆,但进制并不是计算有误差的原因
顺便这个网址可以看浮点的ieee表示,以及误差
https://www.h-schmidt.net/FloatConverter/IEEE754.html
alann 发表于 2022-5-5 11:18
可是不管过程怎么计算,终归结果还是用float储存的吧,说明float也是可以精确储存0.1的? ...
https://blog.csdn.net/weixin_39986543/article/details/110656404
https://p.sda1.dev/5/4787e858e4fe5c3ff6eb43a29906f7ca/92bcc6d**98b5cca628c5720977985.png
0.1不是二进制整数,不能被精确表示 如果1/10和1*0.1都有尾巴,那岂不是又回到我前面的假设,变量有个隐藏的print显示时自动rounding的开关,1/10的变量这个隐藏开关是打开的,1*0.1的变量这个隐藏开关是关的。 alann 发表于 2022-5-5 11:36
如果1/10和1*0.1都有尾巴,那岂不是又回到我前面的假设,变量有个隐藏的print显示时自动rounding的开关,1/ ...
反正都不准,何必纠结这个,换个cpu结果可能又变了。
CPU和软件的具体实现都可以造成影响。 alann 发表于 2022-5-5 11:36
如果1/10和1*0.1都有尾巴,那岂不是又回到我前面的假设,变量有个隐藏的print显示时自动rounding的开关,1/ ...
谁告诉你1.0的显示有尾巴,这里不都在说主楼的那几个么
实际上所有显示都有rounding,包括你看到的3.000……004也隐藏了尾巴 alann 发表于 2022-5-5 11:36
如果1/10和1*0.1都有尾巴,那岂不是又回到我前面的假设,变量有个隐藏的print显示时自动rounding的开关,1/ ...
而且与其在这里汴京不如直接去看浮点数ieee表示以及乘除法实现原理 本帖最后由 RJG丶one 于 2022-5-5 12:26 编辑
应该就是精度的问题。10能被精确表示,0.1不能。
想象一下,0.1具有1e-7的精度,乘了7约等于乘了10,精度被放大到了1e-6,而float就6位有效数字,是不是明显会有问题?
正常的结果只能说是碰巧误差没有放大或者放大后还落在有效区间内。 本帖最后由 诶哟卧草 于 2022-5-5 12:48 编辑
其实我觉得4.9999999 还是5还是5.0000001也无所谓了,目前我还没有计算机思维感觉这几个数都一样。
但我最好奇的是,为什么用在代码里最后造成的运算结果差异会那么大。
就是我丢的下载链接里的Reggie_Linear_Regression_Solution.ipynb这个,直接丢进vs code里run all就行
答案用的* 0.1,运算结果是
best_m 0.30000000000000004
best_b 1.7000000000000002
smallest_error4.999999999999999
我用的是/ 10,结果是
best_m: 0.4, best_b: 1.6, smallest_error: 5.0
我感觉我才是正确答案啊,codecademy的答案不对
smallest_error差不多,但是m和b就差的有些多了
懒得下载的话我直接把代码贴出来大家可以跑跑看,就是根据一些坐标来统计线性回归的一个小作业def get_y(m, b, x):
y = m*x + b
return y
def calculate_error(m, b, point):
y_point = get_y(m, b, point)
return abs(point - y_point)
def calculate_all_error(m ,b ,datapoints):
total_error = 0
for dp in datapoints:
error = calculate_error(m ,b ,dp)
total_error += error
return total_error
possible_ms =
possible_bs =
# possible_ms =
# possible_bs =
smallest_error = float("inf")
datapoints = [(1, 2), (2, 0), (3, 4), (4, 4), (5, 3)]
for m_item in possible_ms:
for b_item in possible_bs:
new_error = calculate_all_error(m_item, b_item, datapoints)
if new_error < smallest_error:
smallest_error = new_error
best_b = b_item
best_m = m_item
print(f"best_m: {best_m}, best_b: {best_b}, smallest_error: {smallest_error}") 你猜猜为什么皮衣黄会吹嘘自家的双精度浮点?? a是-10到11,除数是10,为啥除出来是小数
—— 来自 vivo V1981A, Android 11上的 S1Next-鹅版 v2.5.2-play
页:
[1]
2