0

I'm using Math.Net to calculate the determinate of basic matrices for a larger project. As part of my unit tests I was having issues that converting a float to an int was different when debugging the test. It seems attaching the debugger produces different results to runnign without it.

using System;
using MathNet.Numerics.LinearAlgebra;

public class Test
{
    public static void Main(string[] args)
    {
        Matrix<float> a = Matrix<float>.Build.Dense(2, 2, new float[] { 10, 19, 25, 10 });

        Console.WriteLine("Det {0}", a.Determinant());
        Console.WriteLine("Det Int {0}", (int)a.Determinant());
        Console.WriteLine("Det Trunc {0}", Math.Truncate(a.Determinant()));
        Console.WriteLine("Det Floor {0}", Math.Floor(a.Determinant()));
    }
}

When running the test normally I get the following results:

Det -375
Det Int -374
Det Trunc -374
Det Floor -375

however when debugging the code I get this:

Det -375
Det Int **-375**
Det Trunc **-375**
Det Floor **-376**

I've read through this question but it doesn't seem to address my problem. Running in release mode rather than debug mode has no effect on the results, it seems to only be related to having the debugger attached.

What is going on and how can I reduce the likelihood of this error?

Edit: Using Matrix<double> rather than Matrix<float> produces the correct answers. I'm guessing there is some sort of precision error but I don't understand why.

Community
  • 1
  • 1
Jonathan
  • 585
  • 7
  • 27
  • Why doesn't the linked answer answer your question? – Patrick Hofman Nov 26 '14 at 11:37
  • @PatrickHofman It seems to be talking about debug/release mode rather than running with or without the debugger. Running in release mode has no effect on the results of this code. – Jonathan Nov 26 '14 at 11:38
  • Okay. That is useful information to include in your post. – Patrick Hofman Nov 26 '14 at 11:39
  • It's not really Floor() or Truncate() that's different, the cast to `(int)` also differs. There must be a tiny difference in the result of `Determinant()`. It's not in the code you posted here. – H H Nov 26 '14 at 11:52
  • @HenkHolterman I was using `a.Determinate().ToString("n10")` to print out the entire float, but the results are exactly `-375` both times. – Jonathan Nov 26 '14 at 11:57
  • It always returns a `double`, not a `float`. Try `"n20"` – H H Nov 26 '14 at 12:03
  • `a.Determinate()` returns a float I think. Using `a.Determinate() == -375f` produces `False` though, despite `ToString("n30")` produces the same result. – Jonathan Nov 26 '14 at 12:09
  • Note that 1 sample should no make you feel safe. This can easily happen with `` too. – H H Nov 26 '14 at 13:24

1 Answers1

0

Algorithms for computing determinants are generally numerically unstable, which is why they're best avoided if possible (notably, LAPACK does not provide any routine for computing determinants).

My guess is that the Determinant function is calling an LU decomposition routine, and that debug mode reorders the series of computations, resulting in a slight perturbation that pushes it over the integer boundary.

Simon Byrne
  • 7,694
  • 1
  • 26
  • 50