Getting a stack overflow exception when normalizing a vector

83 Views Asked by At

I'm making a Vector class in C#, with a normalized parameter, which is the vector normalized. However, when I'm trying to calculate the normalized Vector, I get a stack overflow exception. Is there a better way to do it? Here is my code (inside the constructor):

namespace Vector3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Vector3 vector = new(3, 4, 0);
            Console.WriteLine(vector.magnitude);
            Console.WriteLine(vector.normalized);
        }
    }



    class Vector3
    {
    
        public float x, y, z;
        public readonly float magnitude;
        public readonly Vector3 normalized;

        public Vector3(float x, float y, float z)
        {
            this.x = x;
            this.y = y;
            this.z = z;

            this.magnitude = Convert.ToSingle(Math.Sqrt(Math.Pow(this.x, 2) + Math.Pow(this.y, 2) + Math.Pow(this.z, 2)));
            this.normalized = new Vector3(this.x/this.magnitude, this.y/this.magnitude, this.z/this.magnitude);
            
        }
    }
}
2

There are 2 best solutions below

6
Serg On BEST ANSWER

You have infinite recursion in the constructor. While you creating Vector3, you create another Vector3 inside the constructor for normalized value. And this cycle never ends and finally gives you StackOverflowException

You can use lazy creation of normalized value as shown below.

using System;

namespace Vector3
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Vector3 vector = new(3, 4, 0);
            Console.WriteLine(vector.magnitude);
            Console.WriteLine(vector.normalized);
        }
    }

    class Vector3
    {
        public readonly float x, y, z;
        public readonly float magnitude;
        
        private Vector3 _normalized = null;
        public Vector3 normalized => _normalized ??= new(this.x/this.magnitude,
                                               this.y/this.magnitude, this.z/this.magnitude);

        public Vector3(float x, float y, float z)
        {
            this.x = x;
            this.y = y;
            this.z = z;

            this.magnitude = Convert.ToSingle(Math.Sqrt(Math.Pow(this.x, 2) + Math.Pow(this.y, 2) + Math.Pow(this.z, 2)));
        }
    }
}
0
Guru Stron On

However, when I'm trying to calculate the normalized Vector, I get a stack overflow exception

You are creating a new Vector3 inside the Vector3 ctor, which leads to "infinite" recursive calls ending in StackOverflow exception. Remove the call or make it some kind of lazy initialization. Or expose it with separate GetNormalized method.

Another option is to "break" the recursion, for example you can create another private ctor and pass isNormalized parameter (which would work better with readonly public contract):

class Vector3
{
    public float X { get; }
    public float Y { get; }
    public float Z { get; }
    public float Magnitude { get; }
    public Vector3 Normalized { get; }

    public Vector3(float x, float y, float z):this(x,y,z, false)
    {
    }

    private Vector3(float x, float y, float z, bool isNormalized)
    {
        X = x;
        Y = y;
        Z = z;

        Magnitude = Convert.ToSingle(Math.Sqrt(Math.Pow(X, 2) + Math.Pow(Y, 2) + Math.Pow(Z, 2)));
        Normalized = isNormalized ? this : new Vector3(X/Magnitude, Y/Magnitude, Z/Magnitude, true);
    }
}