Python 做除法算比例,结果加起来不是 100

2020-03-31 10:32:09 +08:00
 mw717if

'

    divisor = sum(list(dept_id2count.values()))
    
    divisor = str(divisor)
    
    getcontext().prec = 4
    
    dept_id2p = {}
    
    for dept_id in dept_id2count:
    
        count = dept_id2count[dept_id]
        
        dividend = str(100 * count)  # 被除数
        
        dept_id2p[dept_id] = Decimal(dividend) / Decimal(divisor)
        
        print(Decimal(dividend) / Decimal(divisor))

计算代码如上,输出如下。算每个 count 占总数的比例,最后把比例存到 mysql,保留两位小数。 """

1.781

6.334

0.009013

0.9311

0.02471

0.1105

14.28

24.70

0.4394

11.09

0.01872

4.541

0.06418

13.75

2.486

1.953

0.4429

4.833

4.242

0.08313

1.931

0.7320

0.06604

1.762

3.397

99.99

"""

问题是这些比例加起来不是 100,

一开始用 float 保留两位小数,

后来改成 decimal 四位有效数字,

都没有解决。

求助各位大佬,有没有什么好办法

4670 次点击
所在节点    Python
34 条回复
ClericPy
2020-03-31 12:14:01 +08:00
用计算机算小数还要那么精确... 转 Fraction 或者小数同乘 1000 转整试试?
no1xsyzy
2020-03-31 12:28:54 +08:00
@niubee1 #18 分数表示的无理数?分数不都是有理数吗?
承认吧,你数学也不行(
niubee1
2020-03-31 12:35:26 +08:00
@no1xsyzy 被发现了........ 初中以后的数学都还给老师了
vyronlee
2020-03-31 12:39:49 +08:00
@no1xsyzy 哈哈哈,人艰不拆
no1xsyzy
2020-03-31 12:54:29 +08:00
方便方法就是 #2 补余,但要注意小心 #11 提到的情况,比如 100.0/94=1.1,1.1*93=102.3,最后一个必须是 (-2.3) 才行。
但如 #12 所说去尾的话也有问题,去尾得到 1.0,1.0*93=93.0,最后一个必须是 7.0

更好的方法是抖动下降
a/b = x*10^-y + z/b,其中 a,b,x,y,z∈Z ∧ 0≤z*10^y < b
那么最终结果
有 z/b 的概率是 (x+1)*10^-y (余偏 1-z/b )
有 1-z/b 的概率是 x*10^-y (余偏 z/b )
将余偏加到下个数上去。
zane1994
2020-03-31 13:07:33 +08:00
使用四舍六入五成双,可以解决一部分
mw717if
2020-03-31 13:33:20 +08:00
感谢各位大佬,不一一 @骚扰了,最后用二楼方法解决问题,自己图样,还是要多学习
no1xsyzy
2020-03-31 14:37:10 +08:00
几个方法的比较,采用 943 个 1,即每个 0.106 左右,取 0.01 精确度恰好提升
默认方法最后会凭空多出 3.7%
可以看到 rest2last 采用 round even (四舍六入五凑偶)就会导致最后一个是负的
而如果采用 rest2max 则会导致其中一个过分地大
而只有 dipping 保证够稳定
https://gist.github.com/no1xsyzy/088c44304d4186e0bea5704b0b8c2e66
hxtheone
2020-03-31 15:30:13 +08:00
@littleylv #2 逻辑鬼才, 捡到宝了
NeinChn
2020-03-31 17:15:09 +08:00
@no1xsyzy
这种方式的术语叫什么名字,我搜了一下 dipping 没有找到类似的解释
no1xsyzy
2020-03-31 17:56:17 +08:00
@NeinChn #30 是我记错英文名了
应该叫 dithering,抖动,处理的就是非精确数字化导致的偏差,将比单位还小的量随机地抖动到附近的值上去
NeinChn
2020-03-31 18:00:14 +08:00
@no1xsyzy 了解了
不知道在金融场景上是怎么处理这种情况的
没做过这方面的考虑的确实比较少
no1xsyzy
2020-03-31 18:36:11 +08:00
@NeinChn #32 我这算是 DSP 的,提供的是一种舒服的心理感觉,大概从这个了解到的:
https://xiph.org/video/vid2.shtml (章节 “dither”)

金融场景倒是不知道,话说算比例的话我隐约感觉看到过总比例保留 99.99%,而且直接在 “总计” 行 “比例(%)” 列写着 “99.99”
反正是不可能用抖动这种随机办法的。实际上我说的 “保证够稳定” 是针对 “应对不同数据集能够保证比例值的相对有效性”。但本身因为用了随机所以同样数据集每次结果都不一样(除非被 srand(同一个值))。
NeinChn
2020-03-31 18:58:35 +08:00
@no1xsyzy 嗯,感觉输入输出必须得稳定才行.不然有 diff 就容易出问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/657839

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX