在列表

时间:2016-05-25 12:58:47

标签: algorithm iteration numeric numerical-methods

我有一个复杂的算法来计算函数f(x)的结果。在现实世界中,f(x)是连续函数。然而,由于算法中的舍入误差,计算机程序中不是这种情况。下图给出了一个示例:

enter image description here

此外,我有一个包含数千个值的列表。

我正在寻找满足Fi值的所有x值,即f(xi)= Fi

我可以通过简单地迭代x值来解决这个问题,如下面的伪代码:

for i=0 to NumberOfChecks-1 do
begin

  //calculate the function result with the algorithm
  x=i*(xmax-xmin)/NumberOfChecks;
  FunctionResult=CalculateFunctionResultWithAlgorithm(x);

  //loop through the value list to see if the function result matches a value in the list
  for j=0 to NumberOfValuesInTheList-1 do
  begin
    if Abs(FunctionResult-ListValues[j])<Epsilon then
    begin
      //mark that element j of the list matches 
      //and store the corresponding x value in the list
    end
  end

end

当然有必要使用大量的支票。否则我会错过一些x值。检查次数越多,结果越完整和准确。该列表完成90%或95%是可以接受的。

问题在于这种强力方法需要花费太多时间。正如我之前提到的,f(x)的算法非常复杂,检查次数很多,需要花费太多时间。

对于这个问题,什么是更好的解决方案?

5 个答案:

答案 0 :(得分:3)

另一种方法是分两部分:生成所有结果,对它们进行排序,然后与现有结果的排序列表合并。

第一步是计算所有结果并将其与生成它们的x值一起保存。那就是:

results = list of <x, result>

for i = 0 to numberOfChecks
    //calculate the function result with the algorithm
    x=i*(xmax-xmin)/NumberOfChecks;
    FunctionResult=CalculateFunctionResultWithAlgorithm(x);
    results.Add(x, FunctionResult)
end for

现在,按resultsFunctionResult列表进行排序,并按结果对FunctionResult-ListValues数组进行排序。

您现在有两个可以线性移动的排序列表:

i = 0, j = 0;
while (i < results.length && j < ListValues.length)
{
    diff = ListValues[j] - results[i];
    if (Abs(diff) < Episilon)
    {
        // mark this one with the x value
        // and move to the next result
        i = i + 1
    }
    else if (diff > 0)
    {
        // list value is much larger than result. Move to next result.
        i = i + 1
    }
    else
    {
        // list value is much smaller than result. Move to next list value.
        j = j + 1
    }
}

答案 1 :(得分:2)

  1. 对列表进行排序,生成包含的数组SortedListValues 排序的ListValues和数组SortedListValueIndices 包含每个条目的原始数组中的索引 SortedListValues。你实际上只需要第二个和 您可以通过对数组进行排序来创建单个排序 (value,index)的元组使用value作为排序键。

  2. 0..NumberOfChecks-1中迭代您的范围并计算。{ 每一步的函数值,然后使用二进制斩 在排序列表中搜索它的方法。

  3. 的伪代码:

    // sort as described above
    SortedListValueIndices = sortIndices(ListValues);
    
    for i=0 to NumberOfChecks-1 do
    begin
    
      //calculate the function result with the algorithm
      x=i*(xmax-xmin)/NumberOfChecks;
      FunctionResult=CalculateFunctionResultWithAlgorithm(x);
    
      // do a binary chop to find the closest element in the list
      highIndex = NumberOfValuesInTheList-1;
      lowIndex = 0;
      while true do
      begin
         if Abs(FunctionResult-ListValues[SortedListValueIndices[lowIndex]])<Epsilon then
         begin
           // find all elements in the range that match, breaking out
           // of the loop as soon as one doesn't
           for j=lowIndex to NumberOfValuesInTheList-1 do
           begin
             if Abs(FunctionResult-ListValues[SortedListValueIndices[j]])>=Epsilon then    
               break
             //mark that element SortedListValueIndices[j] of the list matches 
             //and store the corresponding x value in the list
           end
           // break out of the binary chop loop
           break
         end
    
         // break out of the loop once the indices match
         if highIndex <= lowIndex then
            break
    
         // do the binary chop searching, adjusting the indices:
         middleIndex = (lowIndex + 1 + highIndex) / 2;
         if ListValues[SortedListValueIndices[middleIndex] < FunctionResult then
             lowIndex = middleIndex;
         else          
         begin
             highIndex = middleIndex;        
             lowIndex = lowIndex + 1;
         end
      end
    end
    

    可能的并发症:

    • 二进制印章没有考虑到epsilon。取决于 您的数据可能是也可能不是问题。如果可以接受的话 该列表只有90或95%完成,这可能没问题。如果没有那么 你需要扩大范围才能将其考虑在内。
    • 我假设您希望能够为每个FunctionResult匹配多个x值。如果没有必要,您可以简化代码。

答案 2 :(得分:2)

当然,这在很大程度上取决于数据,尤其是Fi的数字分布。另一个问题是f(x)看起来非常跳跃,消除了&#34;假设附近值的概念&#34;。

但是可以优化搜索。

下图。

  1. 以足够的粒度穿过F(x),定义粗略的 min (红线)和 max (绿线),使用合适的公差(&#34; air&#34; 或&#34;差距&#34;介于两者之间)。最小和最大之间的区域是&#34; AREA&#34;。
  2. 查看每个Fi值点击 AREA的位置,相应地在X轴上执行堆叠标记(&#34; MARKING&#34;)(可以是多个细分) X)。
  3. 在彼此之上有许多MARKING(较高的总和 - 垂直黑色&#34;总和&#34;箭头),执行密集命中测试,从而增加整体 有机会获得尽可能多的点击量。在其他地方做更多稀疏测试。
  4. 尽可能多地加强此架构(降低容差)。
  5. 编辑:Fi有点令人困惑。它是一个有序数组还是有随机顺序(如我所假设的那样)?
  6. enter image description here

答案 3 :(得分:2)

Jim Mischel的解决方案可以在O(i + j)中使用,而不是您目前拥有的O(i * j)解决方案。但是,他的代码中存在(非常)小错误。正确的代码是:

    diff = ListValues[j] - results[i]; //no abs() here
    if (abs(diff) < Episilon) //add abs() here
    {
        // mark this one with the x value
        // and move to the next result
        i = i + 1
    }

答案 4 :(得分:-1)

最好的方法将转发函数f(x)的性质。

  1. 最佳解决方案是,如果您可以将翻转创建为F(x)并使用它

  2. 如你所说F(x)是连续的:
    因此,您可以开始评估少量远点,然后查找有意义的范围,并优化f(x)=Fi的x的“假设” 它不是防弹,但它是一种选择。

    e.g。 Fi=5.7; f(1)=1.4 ,f(4)=4,f(16)=12.6, f(10)=10.1, f(7)=6.5, f(5)=5.1, f(6)=5.8,您可以5 < x < 7

  3. 在与#1相同的行上,并且IF F(x)难以计算,您可以使用插值,然后仅在可能的值处评估F(x)