Mass of Earth results in overflow - huh?

Hi all, since this issue has me at a total loss, I decided to register.
A small introduction: I'm an electro engineering student and we've been using Arduino as the brains of our robots since September. However, I have been programming in other languages since quite a while before that.

Now, I've done my research and still can't figure out what's causing the overflow error I'm getting.
The assignment was to simulate the rotation of the moon and ISS around the Earth in Excel, and then write Arduino code to do the same thing. Did the simulation and thought I'd quickly write the program, easy-peasy, but for some reason the mass of the Earth and the Moon are overflowing my float? How is that possible?
I double checked the range of the numbers a float can contain, aparently up to 3.402E+38 so why are 5.97E24 and 7.35E22 causing this problem? Even if I use those exact numbers in the G*(M1*M2)/r^2 formule, it doesn't work, although it should result something like 2.1E20...

Here's the 'important' part of the code (but it's in Dutch, so might be hard to 'read'):

//variabelen en constanten
float G = 6.67428E-11;
int deltaTijd = 30;
float tijd = 0; //variabel om mee te werken
float input = 0; //gebruiker invoer

//Aarde in km/s en kg
float Aarde_massa = 5.9742E24;
float Aarde_snelheid = (2*4621*PI)/(27.23*24*60*60);

//Maan in kilometer, km/s en kg
float Maan_hoogte = (384450+(12756/2)-4621);
float Maan_massa = 7.35E22;
float Maan_snelheid = (((12756+(2*384400))*PI)/(29.53*24*60*60));

//ISS in kilometers en kilogrammen
float ISS_hoogte = 435+(12756/2);
float ISS_massa = 450000;
float ISS_snelheid = 7.660;

//variabelen om mee te werken
float F_Aarde_Maan = 0;
float F_Aarde_ISS = 0;
float F_Maan_ISS = 0;
float Aarde_X = 0;
float Aarde_Y = 4621;
float Aarde_VX = Aarde_snelheid;
float Aarde_VY = 0;
float Maan_X = 0;
float Maan_Y = Maan_hoogte;
float Maan_VX = Maan_snelheid;
float Maan_VY = 0;
float ISS_X = 0;
float ISS_Y = ISS_hoogte;
float ISS_VX = ISS_snelheid;
float ISS_VY = 0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("Voer een tijd in seconden in.");
  while(!Serial.available()>0) {
    
  }
  input = Serial.parseInt();
  for(tijd = 0; tijd<input; tijd=tijd+deltaTijd) {
  F_Aarde_Maan = G*(Maan_massa*Aarde_massa)/(sq(Maan_X-Aarde_X)+sq(Maan_Y-Aarde_Y));
  F_Aarde_ISS = G*(ISS_massa*Aarde_massa)/(sq(ISS_X)+sq(ISS_Y));
  F_Maan_ISS = G*(Maan_massa*ISS_massa)/(sq(Maan_X-ISS_X)+sq(Maan_Y-ISS_Y));

  Serial.print(F_Aarde_Maan);
  Serial.print("  ");
  Serial.print(F_Aarde_ISS);
  Serial.print("  ");
  Serial.println(F_Maan_ISS);

Hope someone can tell me why it's overflowing, and even resulting 'inf' when I try to Serial.print() the large numbers. Or is it the Serial.print() that's actually overflowing and do I need to use some different function in Arduino to print these large numbers?

int ISS_massa = 450000;

Back to the reference page you go.

Oh right, overlooked that one. But doesn't change anything :wink:
Any other tips?

Does your answer fit into 4 bytes? Back to the reference page you go! :wink:
http://arduino.cc/en/Reference/Float
http://arduino.cc/en/Reference/Double

edit: Do any of these calculations (or any single calculation in these) exceed that limit? It doesn't need to be the final answer. Any calculation that exceeds the limit will overflow.

  F_Aarde_Maan = G*(Maan_massa*Aarde_massa)/(sq(Maan_X-Aarde_X)+sq(Maan_Y-Aarde_Y));
  F_Aarde_ISS = G*(ISS_massa*Aarde_massa)/(sq(ISS_X)+sq(ISS_Y));
  F_Maan_ISS = G*(Maan_massa*ISS_massa)/(sq(Maan_X-ISS_X)+sq(Maan_Y-ISS_Y));

Aren't all those masses (and hence the results of the calculations) already known? Why not just enter the values after calculating them on a calculator?

Alternatively do them as a series of separate calculations with saved results rather than all in a single calculation. That way at least you will be able to see where the overflow is.

Given that an unsigned long can have a value up to 2^32 why not just use integer maths?

...R

Arendo:
I double checked the range of the numbers a float can contain, aparently up to 3.402E+38 so why are 5.97E24 and 7.35E22 causing this problem? Even if I use those exact numbers in the G*(M1*M2)/r^2 formule, it doesn't work, although it should result something like 2.1E20...

That is because 5.97E24 * 7.35E22 == 4.38795e+47, which exceeds the range of float. Note, at each step of the calculation, the values have to fit within the boundaries of the floating point the calculations are done in (float in this case).

Now, if you were on a PC/Mac and used double instead of float, that would be no problem, since the range of double on those systems is approximately 1.0E+308. Unfortunately on AVR based Arduinos (not Arm based systems), double uses the float format internally, so you are limited to 1.0e+38. Arm based systems (Due, DigiX, Teensy 3.x) do support a double that can go up to 1.0e+308.

On some systems, float calculations are done in a higher precision while the values are in registers, and then converted back to float at the end of the calculation. The original C compiler on the PDP-11 did this, and 32-bit compilers on the x86 did this if the calculation could be done in the 80-bit floating point stack on the 80387. On other machines, the calculations are done in the floating point type used.

MichaelMeissner:

Arendo:
I double checked the range of the numbers a float can contain, aparently up to 3.402E+38 so why are 5.97E24 and 7.35E22 causing this problem? Even if I use those exact numbers in the G*(M1*M2)/r^2 formule, it doesn't work, although it should result something like 2.1E20...

That is because 5.97E24 * 7.35E22 == 4.38795e+47, which exceeds the range of float. Note, at each step of the calculation, the values have to fit within the boundaries of the floating point the calculations are done in (float in this case).

Now, if you were on a PC/Mac and used double instead of float, that would be no problem, since the range of double on those systems is approximately 1.0E+308. Unfortunately on AVR based Arduinos (not Arm based systems), double uses the float format internally, so you are limited to 1.0e+38. Arm based systems (Due, DigiX, Teensy 3.x) do support a double that can go up to 1.0e+308.

On some systems, float calculations are done in a higher precision while the values are in registers, and then converted back to float at the end of the calculation. The original C compiler on the PDP-11 did this, and 32-bit compilers on the x86 did this if the calculation could be done in the 80-bit floating point stack on the 80387. On other machines, the calculations are done in the floating point type used.

This is exactly the kind of answer I was looking for, thanks a lot.

I wonder if it will work if I just strip E11 from the masses, since G = 6.xE-11... Gonna try that...

Oh, and btw, Serial.print(Massa_aarde) resulted in 'ovf' as well, so how does that work? Since that's obviously a value less than 1.0E38...

Just rescale everything. Call the universal gravitational constant G = 1, the Earth's mass =1 and the other masses are then relative to the Earth's. You will then just need to work out what the scale factor for the distance units would be. Remember, neither the computer nor Nature know anything about our units of measurement!

A significant advantage of that approach is faster calculation.

NOte that the standard Serial.print(float value) will output ovf for float values > max long.

Check - Proposed update for the printFloat code of print.cpp - #11 by robtillaart - Libraries - Arduino Forum - for getting SCIentific notation in print

I remember discovering that none of the local mainframes would handle 1/h^2 (plank's constant. And a common sub-expression of physics HWs I once did.) It was an educational experience...

If you work with (mass / distance) everywhere:

force = (mass1 / distance) * (mass2 / distance) * G ;

Then the intermediate results are already sensibly scaled for solar system
calculations at least - may not work for a black hole or neutron star :wink: