问题的出处是某医院公布的一组数据,有 50 名患者,临床试验某种药剂后,52.4% 不咳嗽了,69.6% 乏力症状消失。问咳嗽的病人有几个,乏力的病人有几个,因为显然并不是所有病人都有这两种症状。
一开始因为分母不大,我使用穷举的方法求解,代码如下:
In [4]: for i in range(1, 51):
...: for j in range(1, 51):
...: if '%.3f' % (i / j) == '0.696':
...: print(i, j)
能够得到正确结果。但后来想这算法显然不行啊,有没有更好的计算方法呢?
首先想的是能不能从小数点后面的数字倒推分母,或者缩小分子分母的可能取值区间,因为每个素数分母能够产生的小数样式是有限的,即 n-1 个。但因为代数水平太低,不知道该怎么计算,最后可能还是会变成穷举或者查表法,就放弃了。
后来 google 了一下发现有个包叫 fractions,可以实现浮点数到分数的转换功能,在我实验的时候恰好看到了一组结果:
In [11]: Fraction(0.6959).limit_denominator()
Out[11]: Fraction(6959, 10000)
做这个实验是因为原本 69.6% 就是个约数,用这个包是算不出 50 以下的结果的,我就想试试自己添几位看能不能试出结果,没想到一下子试出一个素数,fractions 包给了我一个看起来很弱智的结果。但我突然想到,把小数简单乘 10 直到获得整数,再求最大公约数不就算出来了么。于是我的算法变成了:
In [14]: from math import gcd
In [15]: gcd(696, 1000)
Out[15]: 8
In [16]: 696/8
Out[16]: 87.0
In [17]: 1000/8
Out[17]: 125.0
最后我去看了一眼 fractions 的源码,开头就是一个
def gcd(a, b):
"""Calculate the Greatest Common Divisor of a and b.
看来通用的方法就是这么算的。
至于约数的问题,最后也没想出好办法。
来源:oschina
链接:https://my.oschina.net/lionets/blog/3163654