我的模型中有计算用户分数的函数:
def score
(MULTIPLER * Math::log10(bets.count * summary_value ** accuracy + 1)).floor
end
我的意思是测试它是否以对数方式增长?
测试的目的不是证明它总是有效(这是静态类型/证明的区域),而是检查它是否可能有效。这通常足够好。我猜你是为游戏做的,以及如何确保该功能不会“增长”过快。
我们可以做到这一点的一种方法是尝试多个值,并检查它们是否遵循一般的对数模式。
例如,考虑一个纯对数函数f(x) = log(x)
(任何底):
If f(x) = y
, then f(x^n)
= f(x) * n
.
So, if f(x^n) == (f(x) * n)
, then the function is logarithmic.
Compare that to a linear function, eg f(x) == x * 2
. f(x^n) = x^n * 2
, ie x^(n - 1)
times bigger (a lot bigger).
You may have a more complex logarithmic function, eg f(x) = log(x + 7) + 3456
. The pattern still holds though, just less accurately. So what I did was:
x = 1
f(x^n) - f(x) * n
.f((x*100)^n) - f(100x) * n
If (3)/(2) is less than 10, it is almost certainly not linear, and probably logarithmic. The 10 is just an arbitrary number. Most linear functions will be different by a factor of more than a billion. Even functions like sqrt(x)
will have a bigger difference than 10.
我的示例代码只会让该score
方法接受一个参数,然后对其进行测试(为了简单起见+我没有您的支持代码)。
require 'rspec'
require 'rspec/mocks/standalone'
def score(input)
Math.log2(input * 3 + 1000 * 3) * 3 + 100 + Math.sin(input)
end
describe "score" do
it "grows logarithmacally based on input" do
x = 50
n = 8
c = score(1)
result1 = (score(x ** n) - c) / ((score(x) -c) * n)
x *= 100
result2 = (score(x ** n) - c) / ((score(x) -c) * n)
(result2 / result1).abs.should be < 10
end
end
虽然我几乎忘记了复杂的数学知识,但事实似乎并不能阻止我回答这个问题。
我的建议如下
describe "#score" do
it "grows logarithmically" do
round_1 = FactoryGirl.create_list(:bet, 10, value: 5).score
round_2 = FactoryGirl.create_list(:bet, 11, value: 5).score
# Then expect some math relation between round_1 and round_2,
# calculated by you manually.
end
end
一般来说,查看函数是否增长的最好方法是在图表上绘制一些数据。只需使用一些绘图 gem 并评估结果。
对数函数将始终如下所示:
(来源:sosmath.com)
然后,您可以通过参数调整它的增长速度,并重新绘制图表,直到您发现自己对结果感到满意。
如果您需要将此函数视为一个黑匣子,唯一真正的解决方案是获取一堆值并查看它们的曲线是否可以很好地近似为对数曲线,重点关注大n
. 如果您可以对其设置合理的界限,例如a log(n) < score(n) < b log(n)
某些值a
,b
那么您可以检查一下。