'
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 四位有效数字,
都没有解决。
求助各位大佬,有没有什么好办法
1
viggoc 2020-03-31 10:37:28 +08:00 via Android 1
保留有效数字以后本来就没办法求和回复,想要精准就用两个数存成分数形式吧
|
2
littleylv 2020-03-31 10:41:39 +08:00 5
想要保证 100 ?最后一个值用 100 减去前面的总和就行了
|
6
realpg 2020-03-31 10:59:19 +08:00 1
"保留两位小数"
|
7
whusnoopy 2020-03-31 11:04:33 +08:00 2
跟 Python 没关系啊,本来就是有精度损失的
100/3 = 33.33 100/3 = 33.33 100/3 = 33.33 33.33+33.33+33.33 = 99.99 你取多少位精度最后都会差个 1 |
8
jmc891205 2020-03-31 11:05:07 +08:00 1
第一 这个事情跟 Python 没关系
第二 你用一堆近似值求和得到的只会是近似值 |
9
b821025551b 2020-03-31 11:11:05 +08:00 1
没办法,你怎么用小数表示 1/3
|
11
Kakus 2020-03-31 11:12:15 +08:00 1
“100 减去前面总和” 要注意前面数值不能四舍五入,不然会出现最后一个比例为负值的情况。前面要用去尾方式处理。
|
12
Kakus 2020-03-31 11:15:27 +08:00 2
如果数据个数比较多,去尾累积误差就比较大,此时可以换成四舍五入,然后找出最大的那一条数据,误差都给他
|
13
Or2 2020-03-31 11:16:36 +08:00 1
Decimal(str)应该可以,Decimal(float) Decimal(double)不可以
|
14
huigeer 2020-03-31 11:16:51 +08:00 1
2 楼真相
|
16
Jooooooooo 2020-03-31 11:24:47 +08:00 1
相减是对的
|
17
bitdepth 2020-03-31 11:34:35 +08:00 via iPad 1
from decimal import *
IEEE 754 了解一下 |
18
niubee1 2020-03-31 11:42:53 +08:00 1
基本的数学原理,分数表示的无理数没有办法用有限的小数位表示,只能近似约等,也就是丢失精度,这是初中数学学的。
|
20
ColinDowney 2020-03-31 11:59:56 +08:00 via Android 1
2 楼精彩
|
21
ClericPy 2020-03-31 12:14:01 +08:00 1
用计算机算小数还要那么精确... 转 Fraction 或者小数同乘 1000 转整试试?
|
25
no1xsyzy 2020-03-31 12:54:29 +08:00 2
方便方法就是 #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 ) 将余偏加到下个数上去。 |
26
zane1994 2020-03-31 13:07:33 +08:00 1
使用四舍六入五成双,可以解决一部分
|
27
mw717if OP 感谢各位大佬,不一一 @骚扰了,最后用二楼方法解决问题,自己图样,还是要多学习
|
28
no1xsyzy 2020-03-31 14:37:10 +08:00 1
几个方法的比较,采用 943 个 1,即每个 0.106 左右,取 0.01 精确度恰好提升
默认方法最后会凭空多出 3.7% 可以看到 rest2last 采用 round even (四舍六入五凑偶)就会导致最后一个是负的 而如果采用 rest2max 则会导致其中一个过分地大 而只有 dipping 保证够稳定 https://gist.github.com/no1xsyzy/088c44304d4186e0bea5704b0b8c2e66 |
31
no1xsyzy 2020-03-31 17:56:17 +08:00
@NeinChn #30 是我记错英文名了
应该叫 dithering,抖动,处理的就是非精确数字化导致的偏差,将比单位还小的量随机地抖动到附近的值上去 |
33
no1xsyzy 2020-03-31 18:36:11 +08:00
@NeinChn #32 我这算是 DSP 的,提供的是一种舒服的心理感觉,大概从这个了解到的:
https://xiph.org/video/vid2.shtml (章节 “dither”) 金融场景倒是不知道,话说算比例的话我隐约感觉看到过总比例保留 99.99%,而且直接在 “总计” 行 “比例(%)” 列写着 “99.99” 反正是不可能用抖动这种随机办法的。实际上我说的 “保证够稳定” 是针对 “应对不同数据集能够保证比例值的相对有效性”。但本身因为用了随机所以同样数据集每次结果都不一样(除非被 srand(同一个值))。 |