简体   繁体   中英

Incorrect linear interpolation with large x values using Math.Net Numerics

I'm trying to use Math.NET Numerics to do interpolation of a DateTime - Value series. I started off with linear interpolation, but am getting some very off looking results.

Running this test:

public class script{

public void check_numerics()
  {
    var ticks = DateTime.Now.Ticks;
    Console.WriteLine("Ticks: " + ticks);
    var xValues = new double[] { ticks, ticks + 1000, ticks + 2000, ticks + 3000, ticks + 4000, ticks + 5000 };
    var yValues = new double[] {0, 1, 2, 3, 4, 5};
    var spline = Interpolate.LinearBetweenPoints(xValues, yValues);
    var ticks2 = ticks;
    for (int i = 0; i < 10; i++)
    {
      ticks2 += 500;
      Console.WriteLine(spline.Interpolate(ticks2));
    }
  }
}

This gives:

Ticks: 635385235576843379
0.5
1
1.5
2
2.42857142857143 // this should be 2.5
3
3.5
4
4.5
5

Notice that 2.4285 is fairly wrong. At a different time (different ticks value) a different value will be "wrong". Is there a "bug" with large x values in Math.NET or am I expecting too much?

Just confirming the comments above as the maintainer of Math.NET Numerics:

The distance (epsilon) between the closest numbers of this magnitude that can be represented at double precision is 128:

Precision.EpsilonOf(ticks); // 128

This means that if you add or substract 128/2-1 = 63 from this number, you get back exactly the same number:

long ticks = DateTime.Now.Ticks // 635385606515570758
((long)(double)ticks)           // 635385606515570816
((long)(63+(double)ticks))      // 635385606515570816
((long)(-63+(double)ticks))     // 635385606515570816
((long)(65+(double)ticks))      // 635385606515570944
((long)(-65+(double)ticks))     // 635385606515570688

The incremental steps of 500 are very close to these 128 and effectively get rounded to multiples of 128 (eg 512), so it's not surprising that there will be some artifacts like this.

If you reduce the time precision to milliseconds by dividing the ticks by 10000, as suggested by James, you get an epsilon of 0.0078125, and accurate results even for steps of 1 instead of 500.

Precision.EpsilonOf(ticks/10000); // 0.0078125

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM