2

我正在编写一个 Python 脚本来为心算练习生成问题。加法和乘法很容易,但我在尝试为减法生成公正的问题时遇到了麻烦。

我希望能够指定被减数(第一个数字)的最小值和最大值——例如,对于两位数减法,它应该在 20 到 99 之间。减数还应该有一个范围选项(11-99 , 说)。对于这种情况,答案必须是肯定的,并且最好也以至少 10 为界。

所以:

  • 20 < 被减数 < 99
  • 11 < 减数 < 99
  • 答案 = 被减数 - 减数
  • 答案 >= 10

当然,所有数值都应该用作变量。

我满足以下条件:

ansMin, ansMax = 10, 99
subtrahendMin, minuendMax = 11,99
# the other max and min did not seem to be necessary here,
# and two ranges was the way I had the program set up

answer = randint(ansMin, ansMax)
subtrahend = randint(subtrahendMin, minuendMax - answer)
minuend = answer + subtrahend # rearranged subtraction equation

这里的问题是被减值最终几乎全部超过 50,因为答案和减数是首先生成并相加的,并且只有它们中位于范围底部 25% 的部分才会得到低于 50 的结果%。(编辑:严格来说这不是真的——例如,底部 1% 加上底部 49% 会起作用,而且百分比无论如何都不是描述它的坏方法,但我认为这个想法很清楚。)

我还考虑尝试完全随机生成被减数和减数值,然后如果答案不符合标准(即,被减数比减数至少大于 answerMin 的值并且它们两者都在上面列出的标准内),但我认为这会导致类似的偏见。

我不在乎它是否完全均匀,但这太遥远了。我希望被减值在允许的范围内是完全随机的,而减数值在被减数允许的范围内是随机的(如果我想对了,这将偏向于较低的值)。我认为我并不真正关心答案的分布(只要它没有可笑的偏见)。有没有更好的方法来计算这个?

4

3 回答 3

2

在这种情况下,有几种方法可以定义“无偏见”的含义。我假设您正在寻找的是从允许的问题空间中选择每个可能的减法问题以相等的概率。快速而肮脏的方法:

  1. 在 [x_min, x_max] 中选择随机 x
  2. 在 [y_min, y_max] 中选择随机 y
  3. 如果 x - y < answer_min,丢弃x 和 y并重新开始。

注意粗体部分。如果您只丢弃 y 并保留 x,您的问题将在 x 中均匀分布,而不是在整个问题空间中。您需要确保对于每个有效的 x 至少有一个有效的 y - 这不是您最初选择的范围的情况,我们稍后会看到。

现在是漫长而正确的方法。首先,我们需要找出问题空间的实际大小。

允许的减数集由被减数决定:

x in [21, 99]
y in [11, x-10]

或使用符号常量:

x in [x_min, x_max]
y in [y_min, x - answer_min]

我们可以将其重写为

x in [21, 99]
y = 11 + a
a in [0, x-21]

或再次使用符号常量

x in [x_min, x_max]
y = y_min + a
a in [0, x - (answer_min + y_min)].

由此,我们看到只有 x >= (answer_min + y_min) 存在有效问题,并且对于给定的 x 有 x - (answer_min + y_min) + 1 个可能的减号。

现在我们假设 x_max 没有施加任何进一步的约束,例如 answer_min + y_min >= 0:

x in [21, 99], number of problems:
    (99 - 21 + 1) * (1 + 78+1) / 2
x in [x_min, x_max], number of problems:
    (x_max - x_min + 1) * (1 + x_max - (answer_min + y_min) + 1) / 2

以上是使用算术数列之和的公式获得的。因此,您需要在 [1, 4740] 范围内选择一个随机数。要将这个数字转换为减法问题,我们需要定义问题空间和整数之间的映射。示例映射如下:

  • 1 <=> x = 21, y = 11
  • 2 <=> x = 22, y = 12
  • 3 <=> x = 22, y = 11
  • 4 <=> x = 23, y = 13
  • 5 <=> x = 23, y = 12
  • 6 <=> x = 23, y = 11

等等。请注意,当超过一个三角形数时,x 会跳 1。要从随机数 r 计算 x 和 y,请找到大于或等于 r 的最小三角形数 t,最好通过在预先计算的表中进行搜索;将此数写为 q*(q+1)/2。然后 x = x_min + q-1 和 y = y_min + t - r。

完整程序:

import random

x_min, x_max = (21, 99)
y_min = 11
answer_min = 10

triangles = [ (q*(q+1)/2, q) for q in range(1, x_max-x_min+2) ]
upper = (x_max-x_min+1) * (1 + x_max - (answer_min + y_min) + 1) / 2

for i in range(0, 20):
    r = 1 + random.randrange(0, upper)
    (t, q) = next(a for a in triangles if a[0] >= r)
    x = x_min + q - 1
    y = y_min + t - r
    print "%d - %d = ?" % (x, y)

请注意,对于大多数问题(大约 75%),x 将高于 60。这是正确的,因为对于较低的被减数,被减数的允许值较少。

于 2013-10-15T00:17:48.243 回答
0

我可以看到您的起始值存在一些问题-如果您希望答案始终大于 10-那么您需要增加 MinuendMin 或减少 SubtrahendMin,因为 20-11 小于 10...您还定义了答案最小值和最大值为 3,9 - 这意味着答案永远不会超过 10...

除此之外,我设法通过首先选择被减值,然后根据它和 answerMin 选择减数来获得一个很好的值分布:

ansMin = 10
minuendMin, minuendMax = 20,99
subtrahendMin = 9;

minuend = randint(minuendMin, minuendMax )
subtrahend = randint(subtrahendMin,(minuend-ansMin) ) 
answer = minuend - subtrahend
于 2013-10-14T23:32:27.437 回答
0

你说你已经让加法正常工作了。假设您对加数/总和有类似的限制,您可以重新排列这些因素,以便:

minuend <= sum
subtrahend <= first addend
answer <= second addend

如果需要,可以对乘法/除法进行类似的映射。

于 2013-10-15T01:58:20.413 回答