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

Store massive numbers?

Discussion in 'Scripting' started by Tovey-Ansell, Oct 2, 2016.

  1. Tovey-Ansell

    Tovey-Ansell

    Joined:
    Jul 8, 2015
    Posts:
    149
    Quick question; writing a script that changes the strength of gravity with height, and I need to use the formula:

    Formula.png

    but I'm not sure how I would store these huge constants, what data type should I use here?

    Thanks,
    Fred T.A
     
  2. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    .NET4 adds a BigInt class, but of course, Unity is still stalled on 3.5. There are third-party "bignum" libraries available but I don't know if any are 3.5-compatible at this point -- or worse, if you need cross-platform availability. (If you happen to have access to VS2008 and you only want to run on Windows, F# had a BigInt data type under .NET 3.5 and it can quite happily produce fully .NET-compatible DLLs... but you should be able to find some C# options.)

    Are you working on some kind of high-accuracy scientific simulation? If not, maybe you can use a different, easier formula. For example:

    https://www.mansfieldct.org/Schools/MMS/staff/hand/lawsgravaltitude.htm

    I mean, if this is for a game, is this a situation where anyone would really notice a 1.2% decrease in gravitational attraction over a 40km travel-distance? And even if it would matter, are you trying to simulate so accurately that it wouldn't be easier and just as convincing to the user if you simplified the problem with a linear scale?
     
  3. Tovey-Ansell

    Tovey-Ansell

    Joined:
    Jul 8, 2015
    Posts:
    149
    It is a game, but it's for college coursework, generally the more complex the computation the more likely you are to be awarded more marks. So there really is no way of storing numbers of this size without the use of third party libraries?
     
  4. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    The main reason for a BigInt (or BigFloat) class in this case would be to get a large number of significant digits. Now the precision of a float is 7 significant digits.. which is far more than you'd likely use. The OP's examples only use 4. If you did need more double's have 15 significant digits of precision, which is impressively accurate.

    For Example, Voyager is 12.5 billion miles away right now. If we wanted to get the circle it makes with the sun it would be a circle 25 billion miles across 78+ billion miles in circumference.. and if you multiplied it out using 15 digits of PI.. you would be off by about 1.5 inches in total Circumference. 1.5 inches out of 78 billion miles. I think we can all agree that is more than enough precision.

    Now you might be worried about magnitude (how many zeros are following that number when you write it all out). Well float goes up to 4E38 (4 followed by 38 zeroes). That is quite a few orders of magnitude bigger than your biggest number, but you could conceivably break this in intermediate multiplications, if you did all the multiplying before dividing them back down. Doubles however go up to roughly 1.8E308. Which is mind boggling big. You literally can't conceive of anything that could use that number :)

    A large estimate of the number of atoms in the universe is 1E82. If we made a box for every atom in the universe. Then we filled every box with a full set of atoms of the universe, our total atoms would only be 1 billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth billionth of the way to 1E308.

    So I think its safe to say you can just use doubles for all your physics math and you won't run into any problem in either precision or magnitude

    Edit: Almost forgot you can easily write these numbers like this in C#:
    Code (CSharp):
    1. double earthMass = 5.972E24;
    2.  
    3. void Start()
    4. {
    5.          Debug.Log(earthMass);
    6. }
    Would print out: 5.972E+24
     
    Last edited: Oct 2, 2016
    Tovey-Ansell likes this.
  5. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Though using a double would be fine, where's the fun. If you feel frisky here is a Scientic Notation data class I whipped up called SciNote. It overrides the 4 standard operators */-+ as well as To.String. It also adds extension methods SciNoe.ToFloat(); and Float.ToSciNote();

    Code (CSharp):
    1. using System;
    2.  
    3. public class SciNote
    4. {
    5.     float mantissa;
    6.     int exp;
    7.  
    8.     public float Mantissa
    9.     {
    10.         get { return mantissa; }
    11.     }
    12.     public int Exp
    13.     {
    14.         get { return exp; }
    15.     }
    16.  
    17.     public SciNote()
    18.     {
    19.         this.mantissa = 0f;
    20.         this.exp = 0;
    21.     }
    22.  
    23.     public SciNote(SciNote other)
    24.     {
    25.         this.mantissa = other.mantissa;
    26.         this.exp = other.exp;
    27.     }
    28.  
    29.     public SciNote(float mantissa, int exp = 0)
    30.     {
    31.         this.mantissa = mantissa;
    32.         this.exp = exp;
    33.         NormalizeMantissa();
    34.     }
    35.     public static SciNote operator *(SciNote a, SciNote b)
    36.     {
    37.         SciNote answer = new SciNote(a);
    38.         answer.mantissa *= b.mantissa;
    39.         answer.exp += b.exp;
    40.         answer.NormalizeMantissa();
    41.         return answer;
    42.     }
    43.     public static SciNote operator /(SciNote a, SciNote b)
    44.     {
    45.         SciNote answer = new SciNote(a);
    46.         answer.mantissa /= b.mantissa;
    47.         answer.exp -= b.exp;
    48.         answer.NormalizeMantissa();
    49.         return answer;
    50.     }
    51.     public static SciNote operator +(SciNote a, SciNote b)
    52.     {
    53.         SciNote answer = new SciNote(a);
    54.         answer.AlignWithBase(b);
    55.         answer.mantissa += b.mantissa;
    56.         answer.NormalizeMantissa();
    57.         return answer;
    58.     }
    59.     public static SciNote operator -(SciNote a, SciNote b)
    60.     {
    61.         SciNote answer = new SciNote(a);
    62.         answer.AlignWithBase(b);
    63.         answer.mantissa -= b.mantissa;
    64.         answer.NormalizeMantissa();
    65.         return answer;
    66.     }
    67.  
    68.     // this is an internal function  only, since it creates a SciNote
    69.     // whose manitssa is not 1<=mantissa<10
    70.     // for use with addition/subtraction only
    71.     private void AlignWithBase(SciNote other)
    72.     {
    73.         while (this.exp < other.Exp)
    74.         {
    75.             this.mantissa /= 10f;
    76.             this.exp++;
    77.         }
    78.         while (this.exp > other.Exp)
    79.         {
    80.             this.mantissa *= 10f;
    81.             this.exp--;
    82.         }
    83.     }
    84.  
    85.     // this makes sure we only have 1 digit
    86.     // left of the decimal.  1<=mantissa<10
    87.     private void NormalizeMantissa()
    88.     {
    89.         while (this.mantissa >= 10)
    90.         {
    91.             this.mantissa /= 10;
    92.             exp++;
    93.         }
    94.         while (this.mantissa < 1)
    95.         {
    96.             this.mantissa *= 10;
    97.             exp--;
    98.         }
    99.     }
    100.  
    101.     public override string ToString()
    102.     {
    103.         string answer = this.mantissa.ToString() + " E";
    104.         if (this.exp < 0)
    105.             answer += "-";
    106.         else
    107.             answer += "+";
    108.         answer += this.exp.ToString();
    109.         return answer;
    110.  
    111.     }
    112. }
    113.  
    114. public static class SciNoteExtenstions
    115. {
    116.     public static float ToFloat(this SciNote value)
    117.     {
    118.         float answer = value.Mantissa;
    119.         int exp = value.Exp;
    120.         while (exp > 0)
    121.         {
    122.             answer *= 10f;
    123.             if (answer > float.MaxValue || answer < float.MinValue)
    124.                 throw new System.ArgumentOutOfRangeException("SciNote Exp Value out of Range -- too large");
    125.             exp--;
    126.         }
    127.  
    128.         while (exp < 0)
    129.         {
    130.             answer /= 10f;
    131.             if (answer == 0 && value.Mantissa != 0)
    132.                 throw new System.ArgumentOutOfRangeException("SciNote Exp Value out of Range -- too small");
    133.             exp++;
    134.         }
    135.         return answer;
    136.     }
    137.  
    138.     public static SciNote ToSciNote(this float value)
    139.     {
    140.         return new SciNote(value, 0);
    141.     }
    142.  
    143.  
    144. }
    145.  
    Here is some random code that uses it:
    Code (CSharp):
    1. void Start () {
    2.         float myFloat = 12614.5f;
    3.         SciNote firstOne = new SciNote(myFloat.ToSciNote());
    4.         SciNote secondOne = new SciNote(5.436f,8);
    5.         SciNote thirdOne = firstOne*secondOne;
    6.      
    7.         Debug.Log(thirdOne.ToString());
    8.     }
    9.    
    If this is a programming class, feel free to use it to score fancy points :) Let me know if you don't understand how any of it is working. If you work it out, you can also implement overrides for all the comparison operators (<,<=, == ,>=, >) and the implicit operators ( sciNoteVarible = (SciNote)someFloat; ) As well as conversion to and from double and int..
     
    Last edited: Oct 2, 2016
    MV10, Tovey-Ansell and Kalladystine like this.
  6. Tovey-Ansell

    Tovey-Ansell

    Joined:
    Jul 8, 2015
    Posts:
    149
    Thanks a bunch for the info, really helpful (and mind blowing), going to stick with doubles for now, but am still running into a few problems...

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class GravityController : MonoBehaviour {
    5.  
    6.    //various constants here
    7.  
    8.     // Update is called once per frame
    9.     void FixedUpdate () {
    10.  
    11.         float earthField;
    12.         float moonField;
    13.         float altitude = guicontroller.altitude;
    14.  
    15.         earthField = (float) (gravitationalConstant * earthMass) / ( Mathf.Pow( (float)(earthRadius + altitude), 2) );
    16.         moonField = (float) (gravitationalConstant * moonMass) / (Mathf.Pow( (float)(moonRadius + (earthMoonSeparation - altitude)), 2) );
    17.         //These effecively use g = (G * mass) / (radius ^ 2) to find strength of the body's gravitational field
    18.  
    19.         gravitationalFieldStrength = earthField - moonField; //subtract the Moon's field from that of the Earth's to find net grav strength
    20.  
    21.         Debug.Log("gravity is: " + gravitationalFieldStrength);
    22.  
    23.         Physics.gravity = new Vector3(0, gravitationalFieldStrength, 0);
    24.     }
    25. }
    26.  
    Using the above code seems to throw all kinds of non-sensical error messages into my console, such as..

    "invalid AABB aabb"
    "invalid AABB result"
    "invalid AABB *this"
    "Converting invalid MinMaxAABB"
    "aabb.IsFinite()"
    "IsFinite(outDistanceForShort)"
    "IsFinite(outDistanceAlongView)"
    etc, etc


    any clue what that means? also, it seems to spit out the final value for gravity as "9.819215E+22", which is effectively the right value, just no where near the correct order of magnitude?
     
  7. takatok

    takatok

    Joined:
    Aug 18, 2016
    Posts:
    1,496
    Yet clearly:

    Code (CSharp):
    1. float earthField;
    2. float moonField;
    your using floats for some of it. I suspect you might get problems with lines like this:
    Code (CSharp):
    1. (float) (gravitationalConstant * earthMass)
    This is not saying turn the entire line into a float, but just the gravConstant*earthmass part. which I could see overflowing the floats size.

    Also Unity's Mathf library is geared around floats. Since all the structs are float based (like Vector3). Also floats are 4 bytes long, and everything with the low level DirectX stuff requires things to be 16 byte aligned so that makes it easy. However you dealing with numbers that are just barely big enough to overflow a float given certain multiplications. I would just convert every value I used to a double and use System.Math.xxx which takes and returns all double arguments.

    If you need to you can convert the final value into a float, to stick it into Unity Physics calculations. Since by then it should be a reasonably sized number, or at least one in the float's range.

    Note: Assuming all your variables are doubles. To convert a line like this to a float:
    Code (CSharp):
    1. (gravitationalConstant * earthMass) / ( Math.Pow( (earthRadius + altitude), 2) );
    You can't just stick (float) in front. that will only convert the first set of parentheses in to a float. You have to encapsulate the entire operation in parthenses like this:
    Code (CSharp):
    1. (float)((gravitationalConstant * earthMass) / ( Mathf.Pow( (earthRadius + altitude), 2) ));
     
    Tovey-Ansell likes this.
  8. Tovey-Ansell

    Tovey-Ansell

    Joined:
    Jul 8, 2015
    Posts:
    149
    Ah okay awesome, I get it now, all is working as intended, (I also had the gravitational constant set as whateverE11, not E-11, which was causing the error in the order of magnitude. I may end up having a go at the fancy solution with your SciNote class if I have the time.

    Thanks for all the help :D
     
  9. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    you might want to have a look around the web for blogs on Kerbal Space Program's recent rework of it's physics system, I seem to remember there are some articles about how they approached things like this a little while ago.
     
  10. Tovey-Ansell

    Tovey-Ansell

    Joined:
    Jul 8, 2015
    Posts:
    149
    Interesting, I knew KSP reworked their physics not long ago, but it didn't occur to me to look into this properly, I'll take a look :)