如何测试函数是否以对数方式增长?

时间:2013-06-07 15:22:14

标签: ruby rspec tdd bdd

我的模型中有功能可以计算用户的分数:

def score
  (MULTIPLER * Math::log10(bets.count * summary_value ** accuracy + 1)).floor
end

我的观点是测试它是否以对数方式增长?

4 个答案:

答案 0 :(得分:1)

测试的目的不是证明它始终有效(这是静态打字/校样的区域),而是要检查它是否正常工作。这通常足够好。我猜你是在为游戏做这件事,以及确保这个功能不会“快速”增长的原因。

我们可以这样做的方法是尝试一些值,并检查它们是否遵循一般的对数模式。

例如,考虑一个纯对数函数f(x) = log(x)(任何基数):

如果f(x) = y,则f(x^n) = f(x) * n

所以,如果f(x^n) == (f(x) * n),那么函数是对数的。

将其与线性函数进行比较,例如f(x) == x * 2f(x^n) = x^n * 2,即x^(n - 1)倍(更大)。

您可能具有更复杂的对数函数,例如f(x) = log(x + 7) + 3456。虽然不太准确,但模式仍然存在。所以我做的是:

  1. 尝试使用x = 1
  2. 计算常量值
  3. 找出差异f(x^n) - f(x) * n
  4. 找出f((x*100)^n) - f(100x) * n
  5. 的绝对差异

    如果(3)/(2)小于10,则几乎肯定不是线性的,并且可能是对数的。 10只是一个任意数字。大多数线性函数的差异将超过十亿。即使像sqrt(x)这样的函数也会有比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
    

答案 1 :(得分:0)

虽然我几乎忘记了复杂的数学知识,但事实似乎无法阻止我回答这个问题。

我的建议如下

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

答案 2 :(得分:0)

一般来说,查看函数是否增长的最佳方法是在图表上绘制一些数据。只需使用一些图形绘制宝石并评估结果。

对数函数将始终如下所示:

log func image http://www.sosmath.com/algebra/logs/log4/log004.gif

然后,您可以通过参数调整其增长速度,并重新绘制图表,直到您发现自己对结果感到满意为止。

答案 3 :(得分:0)

如果您需要将此功能视为黑盒子,唯一真正的解决方案是获取一组值,并查看它们的曲线是否通过对数曲线很好地近似,重点关注大n。如果您可以对其进行合理限制,例如对于某些值a log(n) < score(n) < b log(n)a b,那么您可以检查一下。