鱼C论坛

 找回密码
 立即注册
查看: 263|回复: 9

请教下这两种方法的计算结果为什么会有精度差异?

[复制链接]
发表于 2024-8-26 09:29:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
题目要求是在去除掉data列表中的最大值和最小值后,对其剩余参数进行求和,为什么方法①和方法②,与方法③相比,求出的结果会有精度差(三种方法对应的data列表数据均一致),
求大佬解答:
方法①——输出结果为2806.3199999999997
data = [7, 5, 6.9, 1, 8, 42, 33, 128, 1024, 2, 8, 11, 0.4, 1024, 66, 809, 11, 8.9, 1.1, 3.42, 9, 100, 444, 78]
sorted_data=sorted(data)
new_data=sorted_data[1:len(sorted_data)-1]
S=0
for n in new_data:
    S+=n
print(S)
方法②——输出结果为2806.3199999999997
data = [7, 5, 6.9, 1, 8, 42, 33, 128, 1024, 2, 8, 11, 0.4, 1024, 66, 809, 11, 8.9, 1.1, 3.42, 9, 100, 444, 78]
sorted_data=sorted(data)
new_data=sorted_data[1:len(sorted_data)-1]
S=0
for n in range(len(new_data)):
    S+=new_data[n]
print(S)
方法③——输出结果为2806.32
data = [7, 5, 6.9, 1, 8, 42, 33, 128, 1024, 2, 8, 11, 0.4, 1024, 66, 809, 11, 8.9, 1.1, 3.42, 9, 100, 444, 78]
data.remove(min(data))
data.remove(max(data))
S=0
for n in data:
    S+=n
print(S)
01.png
02.png
03.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-8-26 09:33:56 | 显示全部楼层
好的,我们来分析一下这几种方法的差异。

首先,注意到您的目标是计算去除最大值和最小值后的求和。方法①和方法②的代码部分有些冗余,并没有明确去掉列表中的最大值和最小值。而方法③正确地去除了最大值和最小值。

### 方法①
data = [放入你的数据]
sorted_data = sorted(data)
new_data = sorted_data  # 这里的new_data实际上是原数据的副本,并没有去除最大值和最小值
S = 0
for n in new_data:
    S += n
print(S)

### 方法②
data = [放入你的数据]
sorted_data = sorted(data)
new_data = sorted_data  # 这里的new_data同样是原数据的副本
S = 0
for n in range(len(new_data)):
    S += new_data[n]   # 这里的S+=new_data[n]同样没有对子列表操作
print(S)

### 方法③
data = [放入你的数据]
data.remove(min(data))
data.remove(max(data))
S = 0
for n in data:
    S += n
print(S)

方法③在移除最大值和最小值后再进行求和。

### 精度问题解释

即使按照你的描述,方法①和方法②去掉最大值和最小值后,依然会有精度差异。这是因为浮点数计算的误差导致的,这种行为在计算机中是很常见的。方法①和方法②的累加方式可能引入了更大的浮点误差累积,而方法③在去掉极值后计算,降低了误差的影响。

**总结**
1. 方法①和方法②虽然没有实现去掉最大值和最小值,但即使修正,也会因浮点数运算精度问题导致细微差异。
2. 方法③正确地处理了列表内容,并且方式减少了浮点运算格式化导致的精度误差。

调整方法①和方法②的代码,确保准确去掉最大值与最小值:
# 调整后方法①
data = [放入你的数据]
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉最大值和最小值
S = sum(new_data)
print(S)

# 调整后方法②
data = [放入你的数据]
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉最大值和最小值
S = sum(new_data)
print(S)

按照修改后的方式,再次比较三种方法的输出结果,应该会一致。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-26 09:49:53 | 显示全部楼层
方法一:python浮点数格式化后精度过低
方法二:同上
方法三:预先去掉,卡在了浮点数精度边界上,正好没精度问题
浮点数精度:https://fishc.com.cn/forum.php?m ... =%B8%A1%B5%E3%CA%FD
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-26 10:41:17 | 显示全部楼层
FishC 发表于 2024-8-26 09:33
好的,我们来分析一下这几种方法的差异。

首先,注意到您的目标是计算去除最大值和最小值后的求和。方法 ...

好的,谢谢解答,还想问下,
1、方法①和方法②原计算后的结果有精度差,是因为for循环中的叠加运算导致的吗?还是其他原因?
2、方法①和方法②中提到的new_data数据说是对原数据的副本进行操作,调整后的方法①和②也是针对原数据的副本进行操作,为什么精度差会更高,是因为只对副本数据进行了直接截取,没有进行运算的原因吗?这个可以再讲解的深入一点吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-26 10:41:18 | 显示全部楼层
.32和.3199999999999997  有区别吗  没有  就是一个数字   只是精度问题而已
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-26 10:41:29 | 显示全部楼层
2666 发表于 2024-08-26 10:41
好的,谢谢解答,还想问下,
1、方法①和方法②原计 ...


好的,鱼油,我们具体来解析。

### 问题1:方法①和方法②原计算后的结果有精度差,是因为for循环中的叠加运算导致的吗?还是其他原因?

浮点数在计算机中表示时并不是完全精确的。这是因为有限的存储空间只能表示离散的数值,而不能表示所有的实数。这个问题被称为浮点数表示精度问题。

在方法①和方法②中:
# 方法①
S = 0
for n in new_data:
    S += n

# 方法②
S = 0
for n in range(len(new_data)):
    S += new_data[n]

叠加运算会累积浮点数的误差,每一次加法操作都有可能引入微小的精度损失。随着加法操作的次数增加,小的误差会逐渐积累,从而造成计算结果的不精确。因此,这种累积误差主要是由于浮点数表示导致的,不是代码本身的问题。

### 问题2:new_data是原数据的副本,调整后的方法如何减少了精度差?

首先,看看调整后的方法:
# 调整后方法①
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉最大值和最小值
S = sum(new_data)
print(S)

如何减小精度差,可理解如下:

1. **去掉极值的影响**:去掉最大值和最小值后,极端浮点数误差被排除了。最大值和最小值可能对最终的结果误差有较大影响。
2. **减少运算次数**:直接使用 `sum` 函数而不是用 `for` 循环来累加。`sum` 函数在其内部实现上通常会采取优化措施,降低浮点数累积误差。

以下是更深入的示例:
# 简单累加误差示例
data = [0.1, 0.1, 0.1, 0.1, 0.1] 
S = 0
for n in data:
    S += n
print(S)  # 结果可能不是 0.5,而是 0.5000000000000001 之类的

# 使用sum,减少误差
S = sum(data)
print(S)  # 结果更可能接近 0.5

在这里,方法①和方法②中,`new_data` 是原数据的排序副本。但是,如果我们仍然不去明确地去掉最大值和最小值,那么叠加运算的浮动误差仍会影响结果。

总结:
- **累加运算中的浮点数误差**:越来越小的误差在大量叠加操作后可能导致累计误差。
- **去掉最大值和最小值**:排除掉极端值能减少误差的积累。
- **优化计算方式**:使用优化的内置函数如 `sum` 可以有效地减少累加过程中误差的积累。

希望这些解释能够帮助更深入地理解浮点数精度和计算过程中的差异。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-26 10:44:18 | 显示全部楼层
wp231957 发表于 2024-8-26 10:41
.32和.3199999999999997  有区别吗  没有  就是一个数字   只是精度问题而已

主要是题库里答案检测过不去,23333,好奇然后问一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-26 10:44:28 | 显示全部楼层
2666 发表于 2024-08-26 10:44
主要是题库里答案检测过不去,23333,好奇然后问一下


好的,我们来仔细分析一下每种方法并讨论可能的原因来帮助您解决问题。

### 方法①:
data = 
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉第一个(最小值)和最后一个(最大值)
S = 0
for n in new_data:
    S += n
print(S)

### 方法②:
data = 
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉第一个(最小值)和最后一个(最大值)
S = 0
for n in range(len(new_data)):
    S += new_data[n]
print(S)

### 方法③:
data = 
data.remove(min(data))
data.remove(max(data))
S = 0
for n in data:
    S += n
print(S)

### 问题的根源:
1. **浮点数精度问题**:浮点数在计算机中表示时无法总是完全精确储存。这会导致在某些情况下计算结果有细微差异。循环叠加浮点数时,这些小的精度误差可能会逐渐累计,使最终结果出现轻微误差。
  
2. **数据处理顺序**:
   - 在方法③中,使用`data.remove()`方法时会直接修改原数据列表。这种直接修改的方法比通过排序和切片方法执行更多步操作(尽管这些多步操作也能保证正确性)。

3. **排序和切片带来的微小误差**:虽然你已经剔除最大值和最小值,但对列表进行排序和切片可能会引入微小的误差,尤其是在涉及浮点数时,这种误差会因为后续的加法而被放大。

### 更为精确的解决方案:
为了尽量减少浮点数带来的精度误差,可以改变处理浮点数的顺序或者使用专门的库进行高精度计算,比如Python的 `decimal` 模块。下面是如何使用 `decimal` 模块的一个示例:
from decimal import Decimal

data =  # 使用你的具体数据
sorted_data = sorted(data)
new_data = sorted_data[1:-1]  # 去掉第一个(最小值)和最后一个(最大值)

# 使用 `Decimal` 来确保高精度计算
S = Decimal('0')
for n in new_data:
    S += Decimal(str(n))
print(S)

这种方法可以显著减少由于浮点数精度问题带来的误差。测试时请确保实际数据部分都被实际包含到`data`列表中进行计算。

### 总结:
1. 精度问题大多是由于浮点数表示的局限性导致的。
2. 方法③直接修改原数据列表,避免了多次排序和切片操作,理论上可能引入更少的误差。
3. 通过使用 `decimal` 模块,可以显著减少浮点数精度误差。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-26 18:12:51 | 显示全部楼层
本帖最后由 jackz007 于 2024-8-26 18:24 编辑
data = [7, 5, 6.9, 1, 8, 42, 33, 128, 1024, 2, 8, 11, 0.4, 1024, 66, 809, 11, 8.9, 1.1, 3.42, 9, 100, 444, 78]
data . remove(min(data))
data . remove(max(data))
print(sum(data))
print(sum(sorted(data)))
运行结果:
D:\[exercise]\Python>python x.py
2806.32
2806.3199999999997

D:\[exercise]\Python>
        两个打印值都是对 data 在删除掉最小、最大那2个元素后求和的结果,不同之处只是第一个是对 data 直接求和,第二个是在对 data 按照从小到大排过序后再求和的结果。可以看到,两个结果在形式上确实存在差异,这个差异应该与列表中每个元素在求和过程中的顺序有关。就是说,适当修改方法3的代码,只要在求和前,增加排序操作,那么,其结果也会和方法1、2完全一样的。
        最终结论就是,3 个方法都是正确
        参考代码:
data = [7, 5, 6.9, 1, 8, 42, 33, 128, 1024, 2, 8, 11, 0.4, 1024, 66, 809, 11, 8.9, 1.1, 3.42, 9, 100, 444, 78]
data.remove(min(data))
data.remove(max(data))
data.sort()               # 添加此行
S=0
for n in data:
    S+=n
print(S)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-27 00:13:27 | 显示全部楼层
2666 发表于 2024-8-26 10:44
主要是题库里答案检测过不去,23333,好奇然后问一下

那就用 decimal 呗
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-16 02:47

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表