Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

Cuberoot?

Discussion in 'Scripting' started by zigs, Nov 3, 2009.

  1. zigs

    zigs

    Joined:
    May 27, 2009
    Posts:
    145
    Hello everyone.
    I need to take the cube root of a number. However, there's no cube root function simmilar to Mathf.Sqrt, and Math.Pow doesn't work with values below 1.
    What else could I do? :(

    Thanks in advance.
    - Chris
     
    Bunny83 likes this.
  2. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    Mathf.Pow works fine for this. Just use a fraction of one (one third, for a cube root) as the 2nd param.

    Code (csharp):
    1. Mathf.Pow(myValue, 1f / 3f)
     
  3. zigs

    zigs

    Joined:
    May 27, 2009
    Posts:
    145
    oh, whops, forgot to add the f's.. freaking floating points :s
    Oh well, thanks a bunch :)
     
    Bunny83 likes this.
  4. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,374
    Sorry for the necro, but it using Mathf.Pow() does not work in case of taking the cube root of a negative number. It throws a NaN.

    You can't do Mathf.Pow(-7, 1/3) but you can do Math.cbrt(-7)

    The code below will solve the NaN but it is not exactly elegant. Missing feature in the math library?

    Code (CSharp):
    1.  
    2. float CubeRoot(float d) {
    3.  
    4.     if (d < 0.0f) {
    5.  
    6.         return -Mathf.Pow(-d, 1f / 3f);
    7.     }
    8.  
    9.     else {
    10.  
    11.         return Mathf.Pow(d, 1f / 3f);
    12.     }
    13. }
     
    Last edited: Nov 7, 2017
  5. junestone

    junestone

    Joined:
    May 30, 2017
    Posts:
    42
    Deeeds likes this.
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    @junestone, I'm confused. Why do you believe this issue is related to Mathf.Pow or taking cube roots? Or are you just hijacking the thread?
     
    TaleOf4Gamers likes this.
  7. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,374
    Probably an accidental post in the wrong thread. Happened to me too once. Something to do with click-not-look.
     
    JoeStrout likes this.
  8. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Submit it as a bug so they can look at it.

    Also, you could condense that
    Code (csharp):
    1.  
    2. return Mathf.Pow(Mathf.Abs(d), 1f / 3f);
    3.  
     
  9. McDev02

    McDev02

    Joined:
    Nov 22, 2010
    Posts:
    664
    Well mathematically it is correct. Roots of negative values only work with imaginary numbers.
    Your example by negating the result if hte value is negative is jsut wrong. If you need it for some purpose you can use that method. Otherwise using Abs() as shown above is an alternative.
     
    JoeStrout likes this.
  10. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    Returns NaN?

    This possibly handles a value Elecman's
    does not, specifically the value -0, I believe IEEE 754 rules may not let -0 be less than +0 but it is still a negative number which may be an issue?
     
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Well, no, in certain cases (the Nth root where N is an odd integer), the result is real (i.e. the imaginary part is zero). This is one of those cases. The cube root of -8 really is -2, since -2 * -2 * -2 == -8.
     
  12. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    I dunno if there may be some complex part due to 1/3 not exactly represented as a floating point
     
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Oh yes, I'm sure this is why the built-in Pow doesn't even attempt it. Just pointing out that, in a purely mathematical sense, it is a valid thing to ask for in these special cases.
     
  14. McDev02

    McDev02

    Joined:
    Nov 22, 2010
    Posts:
    664
    Most likely it is flaoting points. So maybe we need a funtion like this?
    Not sure if I goot all the possibilities here.
    Code (CSharp):
    1. public float RootX(float f, int degree)
    2. {
    3.     if (degree < 1) return float.NaN;
    4.     if (f < 0)
    5.     {
    6.         if (degree % 2 != 1) return float.NaN;
    7.         return -UnityEngine.Mathf.Pow(Mathf.Abs(f), 1f / degree);
    8.     }
    9.     else
    10.         return UnityEngine.Mathf.Pow(f, 1f / degree);
    11. }
     
  15. nat42

    nat42

    Joined:
    Jun 10, 2017
    Posts:
    353
    Seems a bit excessive, what's wrong with the -3rd root of 3?

    And again, not sure but you might need to handle f=-0
     
  16. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,374
    Yes, that is what I meant.

    In case anyone is wondering, I actually found a real world use case where this is an issue. When solving a Cubic function using the code in the link below, it won't work in some cases if you replace the Math.cbrt with the Unity suggested alternative.
    https://www.cs.rit.edu/~ark/pj/lib/edu/rit/numeric/Cubic.shtml

    Solving a Cubic function is needed if you want to reverse solve a Catmull-Rom spline, or in layman's terms, find x for a certain y on a spline instead of trying a bunch of 0 to 1 spline values and finding the closest one.
     
  17. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,556
    May be rewritten as:
    Code (CSharp):
    1.  
    2. float CubeRoot(float d) {
    3.         return Mathf.Pow(Mathf.Abs(d), 1f / 3f) * Mathf.Sign(d);
    4.     }
     
    Last edited: Jul 9, 2018
    Elecman likes this.
  18. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,374
    Thanks! Without a conditional statement it will faster to execute.
     
  19. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,556
    Well, no. This version is more concise and nice to look at, but it will surely be slower than the original.

    Mathf.Abs is easy to appear in the Profiler when used extensively (it does some inner calls to the .net "abs" methods). I'm even using my own Abs version which simply returns "a < 0? -a : a". On the other way, Mathf.Sign surely has its internal conditionals too.

    My contribution to the thread was not really useful in terms of performance, sorry for that.
     
    Bunny83 likes this.
  20. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,374
    Interesting. I use the Abs version in a shader which is much faster than using a conditional statement. But I guess that is to be expected on a GPU.
     
  21. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    46
    C# now has a built in MathF class (capital F, separate from Unity's Mathf class with a lowercase f) that has a cube root function. If you import the
    System
    namespace, you can get the cube root of a number by doing
    MathF.Cbrt(x)
     
  22. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    2,556
    Please don't necro-post a thread started in the early Obama administration, and dormant for the past five years. It's against the forum rules, and just drags up irrelevant threads into everyone else's feed.
     
  23. MitchStan

    MitchStan

    Joined:
    Feb 26, 2007
    Posts:
    577
    Not irrelevant for me. Thanks for necro-ing a very meaningful thread started way back in the early days of the Obama administration.
     
  24. Infinite-3D

    Infinite-3D

    Joined:
    Jan 5, 2020
    Posts:
    46
    Sorry, I didn't mean to break the rules. Even though this thread is old, it still shows up in search results so I was just making sure anyone stumbling upon this from a search engine (like myself) is aware of the changes made to C# since this was posted. (this thread is the very first result for the google search "unity cuberoot")
     
    MitchStan likes this.