This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Floating Addition - Loosing data

Hello,

I'm making use of floating math in my application and have run into a little problem with floating addition. It seems that the floating addition operation looses data at some point. I setup the following test program:

#include <intrins.h>

void main(void)
  {
  float t, v;
  unsigned int i;

  while(1)
    {
    // this block uses multiplication
    for(i=1; i<1000; i++)
      {
      t = 5964.1 * i;
      v = t/i;

      if(v != 5964.1)
        _nop_();
      }

    t = 0;

    // this block will continuously add  5964.1
    for(i=1; i<1000; i++)
      {
      t += 5964.1;
      v = t/i;

      if(v != 5964.1)
        _nop_();
      }
    }
  }

My project is setup using the P89C668 with all default options EXCEPT "bits to round for float compare" is set to 1. I tried all levels of optimization and the result was the same in all cases.

I then set a breakpoint on each nop. When I simulate the program and hit run, a break occurs on the second nop. This would indicate that the addition opperation lost some data.

Whats happening here? Why would the addition opperation not properly calculate the result while the multiplication does?

Thanks
Philip

Parents
  • Not all numbers can be represented precisely in floating-point format.

    The equals operator typically just does a bit-for-bit compare between two floats; if they're close, but not exactly the same, the comparison fails. The usual procedure is to code some tolerable range of error into the comparison, rather than using "==".

    if (fabs(v - i) < Tolerance)
       { // v and i are "close enough" to equal
       }
    

    Since floating point math is all software on the 8051 anyway, the Keil compiler helps with this problem by giving you an option of how fuzzy you want equality to be. The "bits to round for compare" option (or FLOATFUZZY directive) controls how close floats must be to compare equal.

    However, that setting only affects comparisons. It doesn't help with accumulated error due to iteration. Adding something to itself 1000 times gives you a thousand opportunities to accumulate error. Multiplication gives you one. When I run the code on the simulator, v comes out to be 5964.101, not 5964.1(00).

    IEEE 754 has 23 bits of mantissa. 5964.1 is (1.)01110100110000011001101, which is really 5964.1001. 5964.101 is 01110100110000011001101, which is really 5964.1011.

    5964.100 -> 01110100110000011001101
    5964.101 -> 01110100110000011001111
    

    Note that these values are different in the next-to-last bit position. If you only round off 1 bit, then the two values will not compare equal. You'd need to use even more "fuzz" if you want the two values to compare equal.

Reply
  • Not all numbers can be represented precisely in floating-point format.

    The equals operator typically just does a bit-for-bit compare between two floats; if they're close, but not exactly the same, the comparison fails. The usual procedure is to code some tolerable range of error into the comparison, rather than using "==".

    if (fabs(v - i) < Tolerance)
       { // v and i are "close enough" to equal
       }
    

    Since floating point math is all software on the 8051 anyway, the Keil compiler helps with this problem by giving you an option of how fuzzy you want equality to be. The "bits to round for compare" option (or FLOATFUZZY directive) controls how close floats must be to compare equal.

    However, that setting only affects comparisons. It doesn't help with accumulated error due to iteration. Adding something to itself 1000 times gives you a thousand opportunities to accumulate error. Multiplication gives you one. When I run the code on the simulator, v comes out to be 5964.101, not 5964.1(00).

    IEEE 754 has 23 bits of mantissa. 5964.1 is (1.)01110100110000011001101, which is really 5964.1001. 5964.101 is 01110100110000011001101, which is really 5964.1011.

    5964.100 -> 01110100110000011001101
    5964.101 -> 01110100110000011001111
    

    Note that these values are different in the next-to-last bit position. If you only round off 1 bit, then the two values will not compare equal. You'd need to use even more "fuzz" if you want the two values to compare equal.

Children