This project has moved and is read-only. For the latest updates, please go here.

AlmostZero Question

Sep 2, 2009 at 5:03 PM

Hey Guys,

There is a dnA bug report that the sparse matrix is returning differing results for Gram–Schmidt than a dense matrix.  The problem boils down to that any value (in absolute) less than 2.220e-16 (epsilon) is automatically treated as zero. This is also how we've implemented AlmostZero in Math.NET Numerics.

I'm wondering if this is correct.  The AlmostEqual methods are correct if the values being tested are greater than one. But does it hold for values less than one? 

Using a common why to compute machine epsilon:

var epsilon = 1.0;

do {
epsilon /= 2.0;

} while (1.0 + (epsilon / 2.0) != 1.0);

Console.WriteLine(1.0 == 1.0 + (epsilon / 2));
Console.WriteLine(1.1234567890123456 == 1.1234567890123456 + (epsilon / 2));

Console.WriteLine(0.0 == 0.0 + (epsilon / 2));
Console.WriteLine(0.9 == 0.9 + (epsilon / 2));

The first two print statments print true as expected, but not the last two.  

I'm I missing something really obvious?

Thanks,

Marcus

Sep 2, 2009 at 5:56 PM

Hi Marcus,

Epsilon is magnitude-dependent, that's why Iridium comes with an EpsilonOf method to find out the matching epsilon for the provided number.

  • EpsilonOf(0.9) < Epsilon(1.0)
  • EpsilonOf(1.0) = "Epsilon" as understood by mathematicians
  • EpsilonOf(0.0) = double.Epsilon = "Epsilon" as understood by .Net Framework designers ;)

That doesn't answer your question though.

Sep 2, 2009 at 6:01 PM

Some fun facts about System.double I blogged about some time ago:

  • a double can represent 0xFFDFFFFFFFFFFFFF = 18437736874454810623 distinct numbers
  • there are 450359962736 doubles between 1.0001 and 1.0002
  • 54975581 between 10'000.0001 and 10'000.0002
  • 52 between 10'000'000'000.0001 and 10'000'000'000.0002
  • the smallest difference between neighbor numbers is 4.941E-324 for 0, and the biggest difference 1.996E+292 for double.MaxValue?
  • the difference between 1.0 and the biggest number smaller than 1.0 is 1.110E-16

That still doesn't answer your question though.

Chris

Sep 2, 2009 at 6:42 PM

Hi Chris,

>Epsilon is magnitude-dependent, that's why Iridium comes with an EpsilonOf method to find out the matching epsilon for the provided number.

Thanks for the explanation (and the fun facts).  I'll try to work EpsilonOf into AlmostEqual/AlmostZero and the dnA sparse code.

Thanks,

Marcus

Sep 2, 2009 at 6:47 PM

Hi Marcus,

Of course that still leaves the issue of how to deal with zero.

I think we should be more careful with using AlmostZero without providing an appropriate epsilon as argument that fits the whole current problem/task magnitude. I already removed the AlmostZero call in SpecialFunctions.Hypotenuse, since it caused a weird convergence bug in Iridium's SVD routine.

Thanks,
Chris

Sep 12, 2009 at 10:12 AM

Hi Chris,

I'm going to remove the AlmostZero function.  As I was removing it from dnA, there were very cases where we actually needed such a function.  In those cases using AlmostEquals was fine.

Regards,

Marcus

Sep 22, 2009 at 1:00 AM

Looks like the commit on the 20th contains a call to AlmostZero in SpecialFunctions/Gamma.Cs


What would be the correct value to use if employing AlmostEqual(a,x)

x= 0.0?

 

Also, hello to everyone.

Sep 22, 2009 at 8:26 AM

Hi bearrito,

GitHub was a bit fussy last week (I think they were coping with a DOS attack) and I couldn't apply all my commits to mainline. It should be fixed now (and I did exactly what you suggested).

Cheers, Jurgen