Precision loss of floats

Hello! I am posting a simple code to explain the issue I ran across recently.

#include <malloc.h>

int Function(float **a);

void setup() {
int i;
float **a_;

     a_ = (float**) malloc(2*sizeof(float*));  
     for (i = 0; i < 2; i++) a_[i] = (float*) malloc(2*sizeof(float)); 

     a_[0][0] = 697.29;
     a_[0][1] = 380.39;

     a_[1][0] = 380.39;
     a_[1][1] = 209.72;

     Serial.begin(9600);

     Serial.print("Before function call a[0][0] = ");     
     Serial.println(a_[0][0],6);
     
     if (Function(a_) == 0) Serial.println("Function OK!");
     
//     Serial.println(0.000000000000123*1./1.,16);//This test however is accurate!

     for (i = 0; i < 2; i++) free(a_[i]);
     free(a_);

}//setup

void loop() {
     while(1);
}//loop

int Function(float **a) {
  
    Serial.print("After function call  a[0][0] = ");
    Serial.println(a[0][0],6);

    return 0;
}//Function

The serial monitor replies as follows:
Before function call a[0][0] = 697.289978
After function call a[0][0] = 697.289978
Function OK!
So, my question is: Where did the precission loss come from? The element a_[0][0] is initialized with 697.290 neither more nor less. Needless to say, if I keep on computing the results get even worse. I am using Arduino Mega 2560 rev. 2. Could anybody please explain what is going on here? Thank you in advance!

You could have made a simpler example:

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  float foo = 697.29;
  Serial.println (foo);
  }  // end of setup

void loop () { }

Output:

697.29

So far so good.


void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  float foo = 697.29;
  Serial.println (foo, 6);
  }  // end of setup

void loop () { }

Output:

697.289978

So?

A float has ~7.2 digits accuracy. If you round, you get 697.29.

A float has ~7.2 digits accuracy

Note - that's 7 TOTAL significant digits. Not 7 digits "after the decimal point."

I suppose that the problem reduces to the closest number the decimal digit could be represented through. I have tried out the same problem in Visual Studio. This kind of issue does not exist there. Any ideas how to avoid it in Arduino?
BTW, thanks for the Wiki article.

I have tried out the same problem in Visual Studio. This kind of issue does not exist there.

This kind of issue happens with all floating-point representations, but it will be less noticeable with the 64 bit floats you'll have access to in VS.
On an AVR Arduino, float and double are both 32 bits.

single floats, which have 32 bits in total devote only 23 bits to the "mantissa", which
is responsible for the fundamental precision of the type. The mantissa value has an
assumed leading one which is not stored, so it is effectively 24 bits.

The Actual precision varies from about 6.9 to 7.2 decimal digits depending on
the value.

For instance successive representable numbers from 1.0 up are

1.0
1.00000012   (change is 0.12ppm, one part in 2^23)
1.00000024
1.00000036

and successive representable numbers down from 1.0 are

1.0
0.99999994  (change is 0.06ppm, one part in 2^24)
0.99999988
0.99999982

So the precision depends on where the value falls w.r.t powers of 2.

Thank everybody very much for the thorough explanations which are very useful for me.
Meanwhile, I encounterred an interesting code here:
http://codepad.org/9pHEO4tx