Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Making a math project in unity. Trying to make a derivative function but can't get it right.

Discussion in 'Scripting' started by hochbergtal, Jul 29, 2023.

  1. hochbergtal

    hochbergtal

    Joined:
    Jul 29, 2023
    Posts:
    1
    I'm trying to make a derivative function for complex numbers (that's why I'm using Vector2 instead of float), but it always results in a Stack Overflow Exception error. can someone explain what is the problem and how to fix it?

    Code (CSharp):
    1. Func<Vector2, Vector2> derivative(Func<Vector2, Vector2> f, int n)
    2.     {
    3.         Func<Vector2, Vector2> currentFunc = f;
    4.         for (int i = 1; i <= n; i++)
    5.         {
    6.             currentFunc = z => (currentFunc(z + new Vector2(Mathf.Epsilon, Mathf.Epsilon)) - currentFunc(z)) / Mathf.Epsilon;
    7.         }
    8.         return currentFunc;
    9.     }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Sounds like perhaps you're calling yourself recursively, almost certainly on line 6 where you wrap the delegate with a previous delegate, then return it.

    Attach the debugger, put a breakpoint in and let 'er rip.

    To understand recursion, you must first understand recursion.
     
    Last edited: Jul 29, 2023
    exiguous and orionsyndrome like this.
  3. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    and the other one: "once you understand the recursion, it's recursively understood"
     
    exiguous likes this.
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,495
    Your issue is this part:
    Code (CSharp):
    1. currentFunc = z => (currentFunc(
    The main issue is that you create a "closure" and closures capture variables, not values. That means the "currentFunc" inside the closure is the same variable as the one you assign your closure to. So you have an infinite recursion as the method / delegate you call inside your closure will be the closure itself. The only way to break this is to create a new variable inside the for loop like this:

    Code (CSharp):
    1.  Func<Vector2, Vector2> currentFunc = f;
    2.         for (int i = 1; i <= n; i++)
    3.         {
    4.             Func<Vector2, Vector2> tmp = currentFunc;
    5.             currentFunc = z => (tmp(z + new Vector2(Mathf.Epsilon, Mathf.Epsilon)) - tmp(z)) / Mathf.Epsilon;
    6.         }
    7.         return currentFunc;
     
  5. karliss_coldwild

    karliss_coldwild

    Joined:
    Oct 1, 2020
    Posts:
    530
    Once you solve your recursion issue you will likely face the next problem. I doubt trying to calculate derivative of function by naively using `(f(x+epsilon)-f(x))/epsilon` will produce meaningful result. As the epsilon approaches zero, result will approach the derivate of function, but only up to a certain point after which you will hit the precision limits of floating point and for any nontrivial calculation you will likely get garbage.

    Mathf.Epsilon is smallest (closest to zero not biggest negative) value that floating point numbers can represent. This means that this also smallest step (in the best cases) for changes in function output. If you wanted to calculate derivative for for f(x)=1.5x near zero, you would get either 1 or 2 since floating point can only represent 0 * eps, 1*eps and 2*eps.
    That was the best case scenario. Away from 0, difference between two constitutive floating point numbers is much bigger than Mathf.Epsilon. This means that for most floating point numbers x+eps = x, and I am not speaking abstractly, adding Mathf.Epsilon to a variable will leave it's bits unchanged. In case of derivative calculations that means you will get 0, since f(x+eps)-f(x)=f(x)-f(x)=0 for all x > 1e-29.

    Numbers don't even have to be very big for this to be a problem. Next floating point number after 1 is 1.00000011921 or ~ 1+1.19e-7. But Mathf.Epsilon is 1.40129846432e-45. That's already 10^38 times bigger step by just going from 0 to 1.
     
  6. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    It's funny coz it's true.

    Anyway, with so many radically different takes on what's wrong here, I think OP is a cowboy :) (no offense)
     
    Bunny83 and PraetorBlue like this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    As a great man once observed,

    "Think of [floating point] as JPEG of numbers." - orionsyndrome on the Unity3D Forums

    :)
     
    Anthiese, Bunny83 and orionsyndrome like this.