1
\$\begingroup\$

This algorithm is intended to determine the epsilon of a given double precision number. As numbers increase in value, their accuracy decreases. This algorithm will return the smallest increment / decrement possible at any given value.

Given the way floating point numbers are structured, is there logically any situation where this algorithm won't work? It has worked fine for whatever numbers I've thrown at it.

public enum EZeroDirection { TowardsZero, AwayFromZero };

[StructLayout(LayoutKind.Explicit)]
private struct DL
{
    [FieldOffset(0)]
    internal double D;

    [FieldOffset(0)]
    internal long L;
}

/// <summary>
/// Returns the dynamic epsilon of this Double. If the value is NaN or ±Inf, or the initial result overflows, the result will be null.
/// </summary>
/// <remarks>See (http://bit.ly/10KS2wo)</remarks>
/// <param name="dir">Determines if the epsilon is calculated from the delta of its next value towards zero or away from zero. Choose the direction 
/// the value moves in. Note: EZeroDirection.TowardsZero allows proper processing of Double.MaxValue and Double.MinValue.</param>
/// <returns>Double?</returns>
public static Double? DynamicEpsilon(this Double a, EZeroDirection dir = EZeroDirection.TowardsZero)
{
    if (!double.IsNaN(a) && a != double.NegativeInfinity && a != double.PositiveInfinity)
    {
        DL dl = new DL();
        dl.D = a;
        dl.L -= ((dir == EZeroDirection.TowardsZero) ? 1 : -1);

        if (!double.IsNaN(dl.D))
        {
            return Math.Abs(a - dl.D);
        }
    }

    return null;
}
\$\endgroup\$
8
  • \$\begingroup\$ Can you add an explanation or a link to explain what this is supposed to do? And/or sample input. I get 0 no matter what I pass in. \$\endgroup\$
    – Bobson
    Commented Jun 13, 2013 at 13:24
  • 1
    \$\begingroup\$ How are you inspecting what you get back? try pass in something like 1E+100, which will give you back a large number. \$\endgroup\$
    – IamIC
    Commented Jun 13, 2013 at 14:05
  • \$\begingroup\$ I ported and adapted this from C, so I don't have a link to how it works (although the remark shows the source of where it came from, which has an extended discussion on the topic). \$\endgroup\$
    – IamIC
    Commented Jun 13, 2013 at 14:05
  • \$\begingroup\$ Ah, I'd broken it in adding it to LINQpad. I'm getting results now, although I don't know what they mean. \$\endgroup\$
    – Bobson
    Commented Jun 13, 2013 at 14:37
  • \$\begingroup\$ Why do you need to do this? In most cases, the exact precision of double shouldn't matter to you. \$\endgroup\$
    – svick
    Commented Jun 13, 2013 at 15:54

1 Answer 1

3
\$\begingroup\$
a != double.NegativeInfinity && a != double.PositiveInfinity

This could be simplified to just double.IsInfinity(a). Though as far as I know, it is correct. I was worried that there may be more values representing infinity, like there are for NaN, but that doesn't seem to be the case.


Otherwise, your method seems to work to me in all edge cases, including +/-0, double.MaxValue and double.Epsilon (though you should write unit tests for these just in case). In the case of +/-0 and TowardsZero, D will become NaN, so your method returns null, which I think is correct behavior.

\$\endgroup\$
3
  • \$\begingroup\$ Thanks @svick. I did test all edge cases (except -0, which I don't know how to generate). Thanks for the IsInfinity tip. \$\endgroup\$
    – IamIC
    Commented Jun 14, 2013 at 6:40
  • \$\begingroup\$ Per this article (en.wikipedia.org/wiki/Endianness) one may "safely assume" that the endiansess is the same for integers and FP numbers, so I think this code should work on both platforms. \$\endgroup\$
    – IamIC
    Commented Jun 14, 2013 at 6:58
  • \$\begingroup\$ @IanC I assumed that IEEE 754 did specify endianness. I removed that part from my answer. \$\endgroup\$
    – svick
    Commented Jun 14, 2013 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.