4
\$\begingroup\$

I tried to check if my vector struct is normalized, and I ended up with this code:

public bool IsNormalized
{
    get
    {
        double len = Length; // Math.Sqrt ((X * X) + (Y * Y) + (Z * Z)); -- X, Y, Z are in double format

        const double min = 1 - 1e-14;
        const double max = 1 + 1e-14;

        return (len >= min && len <= max);
    }
}

Is this solution OK? I read double has 15 digits precision, but 1+1E-15 give 1, so I changed to E14.

Is this all good? I need best accuracy.

\$\endgroup\$
6
\$\begingroup\$

This seems ok, depending on how precise you want it to be (some margin of error will always be needed since this is floating-point, but how much will depend on your needs)

Alternatively, you could check Math.Abs(1 - len) < 1e-14, but I suspect the same precision problems will remain.

I was somewhat surprised that 1 + 1e-15 equals 1, though, because doubles have 52 bits of precision, which should be more than enough to store a difference of 15 digits (-log2(1/10^15) gives me around 49.8, which is less than 52 bits).

So I double checked and 1 - 1.0e-15 does not give me 1.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(1 - 1.0e-15); //Does NOT print 1
        Console.Read();
    }
}

Same thing for 1 + 1.0e-15 (though this one is trickier)

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(1 + 1.0e-15); //Prints 1
        Console.WriteLine(1 + 1.0e-15 == 1); //...but this prints False
        Console.Read();
    }
}

I suspect Console.WriteLine is only printing a limited number of digits: less than the ones double can represent.

As a final note, Sqrt(1) == 1, so instead of using the Length you could use the SquaredLength and save a (potentially expensive) Sqrt operation.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your investigation. I looked in debugger now, and, like you said, it's not equal 1. So I will stick to 1E-15. Also thanks for the SquaredLength tip. I did not understand why it was exposed in some Vector 3D implementations, but now I know it's very useful in my IsNormalized property. \$\endgroup\$ – apocalypse Feb 15 '14 at 15:32
  • 1
    \$\begingroup\$ You're welcome. Note that my Sqrt tip is only needed if you're being bottlenecked. For most "casual" uses, your function works perfectly (and is perhaps more readable) \$\endgroup\$ – luiscubal Feb 15 '14 at 15:34
  • \$\begingroup\$ "I suspect Console.WriteLine is only printing a limited number of digits: less than the ones double can represent." - This should be a well known fact - console is intended to interface with human operators, not examine the miniature of double. If you want more information, look into the double ToString options. \$\endgroup\$ – NPSF3000 Feb 16 '14 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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