设p
为百分比(分子,即 25%),x
乘以初始值,并y
为结果整数。
因为p
是一个百分比,它是 5 的倍数,0 to 100
从那时起我们可以将其表示为p = 5a/100 = a/20
where 0 <= a <= 20
。
因为x
我们有这个约束100 <= x <= 999
。
先挑一个a
满足的0 <= a <= 20
。
接下来我们选择一个x
. 好吧,p * x = (a/20) * x
要成为整数结果,我们只需要 20 来除a * x
。好吧,我们知道20 | (a * x)
("20 除 a * x") 当且仅当
j = (a * x) / 20 (<- j is some integer)
<=> j = (a * x) / (2^2 * 5^1)
既然我们有a
,我们可以用它的素数分解来代替它:
j = (p1^e1 * p2^e2 * ... * pn^en) * x / (2^2 * 5^1)
现在意识到它a
小于 20,所以它的素数分解可能非常简单,并且可能与素数分解“重叠”。例如,如果a = 5
上面的等式简化为
j = x / 4
在这种情况下,很容易看出我们如何生成x
将产生一个整数j
(4 的倍数。尽管您也需要100 <= x <= 9999
!)。所以“重叠”(即分子中的主要因素与分母相同)是非常有益的。这就是最大公约数发挥作用的地方。GCD(a, 20)
是除a
和的最大整数20
。的主要因式分解GCD
正是重叠。它还有一个很好的属性,一旦我们“移除”重叠,结果值:
j = b * x / c
b
具有互质的好特性c
。由此我们知道b * x / c
当且仅当 是整数c | x
。
所以让GCD(a, 20) = k
. 然后根据定义我们有a/k = b
和20/k = c
,所以a/20 = b/c
。因此让x = c * m
wherem
是一个整数。然后我们有:
100 <= m * c <= 9999
=> 100 / c <= m <= 9999 / c
所以我们可以做一个floor(rand(100 / c, 9999 / c))
来生产你的m
.
总结一下:
a = rand(0, 20)
p = 5*a
c = 20 / GCD(a, 20)
m = floor(rand(100 / c, 9999 / c))
x = c * m
y = (p / 100) * x
请注意,这a = 0
实际上是一种极端情况,而且floor()
不会给你一个完全均匀的分布。如果您需要涵盖这些内容,我可能会考虑一下并稍微调整一下答案。另外,欧几里得算法实现起来很简单,你可以查一下。哎呀,因为a < 20
您可能只是对函数进行硬编码:)
编辑我第一次忘记c
在摘要中定义。这是一个生成您在下面的反例的示例:
a = 5
p = 25
c = 20 / GCD(5, 20) = 20 / 5 = 4
m = some integer in [25, 2500). In this case so we randomed 879
x = 3516
y = 879
在这个例子中我们很方便,GCD(a, 20) = 5
所以结果是m = y
,但情况并非总是如此。