如何使用定义数量的样本对 3 points/numbers 进行插值? (在 C# 中)

How to interpolate through 3 points/numbers with a defined number of samples? (in c#)

所以例如我们有 1、5 和 10,我们想在它们之间插值 12 个点,我们应该得到:

1.0000        
1.7273   
2.4545    
3.1818   
3.9091    
4.6364   
5.4545   
6.3636   
7.2727  
8.1818    
9.0909    
10.0000   

假设我们有 5、10、4 和 12 点,我们应该得到:

5.0000
5.9091
6.8182
7.7273
8.6364
9.5455
9.4545
8.3636
7.2727
6.1818
5.0909
4.0000

问题是在给定端点和交点的情况下对两条具有不同斜率的直线进行插值。

插值定义如下:在数值分析的数学领域,插值是一种在一组离散的已知数据点范围内构造新数据点的方法。

我厌倦了人们对难题的解决方案给予负面评价。这不是一个简单的问题,而是一个需要"thinking out of the box"的问题。让我们看看以下输入的解决方案:1 12 34

我选择这些数字是因为结果都是整数

步长L(Lower)=1到12的元素距离=2

步长H(Higher) = 元素从12到34的距离= 4

所以答案是:1 3 5 7 9 11 [12] 14 18 22 26 30 34

注意第6点11到中心的距离为1(L的一半)

注意中心点12到第7点的距离是2(H的一半)

最后注意到第6点和第7点之间的距离是3.

我的结果缩放比例与 OP 的第一个示例完全相同。 很难看到 OP 发布的带有小数输入的序列。如果您查看 OP 第一个示例并计算前 6 个点的步距,您将得到 0.72。最后 6 点的距离是 0.91。然后计算第 6 个点到中心的距离为 0.36(0.72 的一半)。然后中心到第 7 点 0.45(一半 0.91)。请原谅我将数字四舍五入了一点。


和初中学算数列和几何数列一样的数列题。然后作为奖励问题,你得到了序列 23、28、33、42、51、59、68、77、86,结果是纽约市第三大道地铁系统的火车站。解决这样的问题你需要考虑 "Outside the Box",它来自 IBM 给求职者的测试。这些是可以解决九点问题的人:http://www.brainstorming.co.uk/puzzles/ninedotsnj.html


我在点数为偶数时得出结果,在您的情况下为 12。如果点数为奇数,您将需要完成代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        const int NUMBER_POINTS = 12;
        static void Main(string[] args)
        {
            List<List<float>> tests = new List<List<float>>() {
                new List<float>() { 1,5, 10},
                new List<float>() { 5,10, 4}
            };

            foreach (List<float> test in tests)
            {
                List<float> output = new List<float>();

                float midPoint = test[1];

                if(NUMBER_POINTS % 2 == 0)
                {
                    //even number of points

                    //add lower numbers
                    float lowerDelta = (test[1] - test[0])/((NUMBER_POINTS / 2) - .5F);
                    for (int i = 0; i < NUMBER_POINTS / 2; i++)
                    {
                        output.Add(test[0] + (i * lowerDelta)); 
                    }
                    float upperDelta = (test[2] - test[1]) / ((NUMBER_POINTS / 2) - .5F); ;
                    for (int i = 0; i < NUMBER_POINTS / 2; i++)
                    {
                        output.Add(test[1] + (i * upperDelta) + (upperDelta / 2F));
                    }
                }
                else
                {
                }

                Console.WriteLine("Numbers = {0}", string.Join("   ", output.Select(x => x.ToString())));

            }
            Console.ReadLine();

        }
    }
}

这是一个通用的解决方案,遵循以下原则:

  • 执行线性插值
  • 它计算一个"floating point index"到输入数组
  • 此索引用于select 1(如果小数部分非常接近于 0)或 2 来自输入数组的数字
  • 该索引的整数部分是基本输入数组索引
  • 小数部分表示我们应该向下一个数组元素移动多远

这应该适用于您需要的任何大小的输入数组和输出集合。

public IEnumerable<double> Interpolate(double[] inputs, int count)
{
    double maxCountForIndexCalculation = count - 1;
    for (int index = 0; index < count; index++)
    {
        double floatingIndex = (index / maxCountForIndexCalculation) * (inputs.Length - 1);

        int baseIndex = (int)floatingIndex;
        double fraction = floatingIndex - baseIndex;

        if (Math.Abs(fraction) < 1e-5)
            yield return inputs[baseIndex];
        else
        {
            double delta = inputs[baseIndex + 1] - inputs[baseIndex];
            yield return inputs[baseIndex] + fraction * delta;
        }
    }
}

它会生成您在问题中显示的两个输出集合,但除此之外,我还没有对其进行测试。执行的错误检查很少,因此您应该添加必要的位。