C# 实现Excel的线性插值Forecast函数

来源:互联网 发布:石川绫子 知乎 编辑:程序博客网 时间:2024/05/22 08:54

最近做了一个项目涉及到插值算法,有源数据和插值后的数据,但不知道使用的具体是什么插值算法,尝试了5,6种不同的算法,但均和目标数据不匹配。后决定试试Excel里面的线性插值,一对比数据,结果发现使用的就是这个算法。

其中做excel实验的方法是模仿的这个网址:

http://forums.codeguru.com/showthread.php?461020-Forecast-function

里面提供了公式是:FORECAST(E19,OFFSET($C$4,MATCH(E19,$B$4:$B$12,1)-1,0,2),OFFSET($B$4,MATCH(E19,$B$4:$B$12,1)-1,0,2))

问题原型:在一组源数据中(x[ ],y[ ]),待插值的对象是key,求的插值后的y值。

上面公式大体意思是:找到小于并最接近key的x的index,得到两个匹配的数组 x_map[] = {x,x[index+1]}, y_map[] = {y,y[index+1]},因此上面公式变成了

forecast(key,y_map[], x_map[]);


下面贴出实现的代码

 public class ExcelInterAlgorithm    {       public static double Compute(double[] x_Values, double[] y_Values, double key)       {           int index = binarySearch(x_Values,key);           if (index == -1)           {               throw new IndexOutOfRangeException("超过插值范围");           }           double[] Xnear = new double[2] { x_Values[index], x_Values[index + 1] };           double[] Ynear = new double[2] { y_Values[index], y_Values[index + 1] };           return Math.Round(getValue(Xnear, Ynear, key), 3);       }        private static double getValue(double[] x_map, double[] y_map, double key)       {           double x_Avg = GetAverage(x_map);           double y_Avg = GetAverage(y_map);           double forecast = 0f;           double b = 0f;           double a = 0f;           double tempTop = 0f;           double tempBottom = 0f;           for (int i = 0; i < y_map.Length; i++)           {               tempTop += (x_map[i] - x_Avg) * (y_map[i] - y_Avg);               tempBottom += Math.Pow(((x_map[i] - x_Avg)), 2f);           }           b = tempTop / tempBottom;           a = y_Avg - b * x_Avg;           forecast = a + b * key;           return forecast;       }       /// <summary>       /// 得到平均值       /// </summary>       /// <param name="data"></param>       /// <returns></returns>       private static double GetAverage(double[] data)       {           double total = 0;           for (int i = 0; i < data.Length; i++)           {               total += data[i];           }           return total / data.Length;       }       /// <summary>       /// 二分查找       /// </summary>       /// <param name="dlist"></param>       /// <param name="x"></param>       /// <returns></returns>       public static int binarySearch(double[] dlist, double x)       {           if (x < dlist[0] || x > dlist[dlist.Length - 1]) return -1;                      int low = 0;           int high = dlist.Length - 1;           while (low <= high)           {               int middle = (low + high) / 2;               if (middle == dlist.Length - 1)               {                   return middle;               }               if (dlist[middle] == x)               {                   return middle;               }               else               {                   if (dlist[middle] < x)                   {                                             if (x < dlist[middle + 1])                       {                           return middle;                       }                       else                       {                           low = middle + 1;                           continue;                       }                   }                   else                   {                                             if (x > dlist[middle - 1])                       {                           return middle - 1;                       }                       else                       {                           high = middle - 1;                           continue;                       }                   }               }           }           return -1;       }    }

其中,查找算法用的是二分查找。

0 0