views:

548

answers:

5

I have a code wriiten in C which is intended for a 16-bit microcontroller. The code essentially does lot of floating point arithmatic.

The arithmatic works fine till the result is positive; but in case of subtraction if the expected result is negative; I get a zero.

result = 0.005 - 0.001;      is correctly computed as 0.004
result = 0.001 - 0.005;      is always zero.

Any clue why is such a behavior for float?

+5  A: 

Interesting. It could quite easily be a fault in the floating point software. Embedded systems often include floating point as an option so as to keep the code size down.

I'm not sure that's the problem here though since you're first statement works.

What happens with:

result = 0.005 - 0.001;
result = -result;

result = 0.002 - 0.001;
result = 0.002 - 0.002;
result = 0.002 - 0.003;

result = 0.001 - 0.002;
result = 0.001 - 0.003;
result = 0.001 - 0.004;

The idea here is to collect useful information as to what could be causing it, a common thing to do in forensics. The results of those calculations are likely to be helpful in determining the actual problem.

Update 1:

Based on your results in the comments:

result = 0.005 - 0.001;  // 0.004
result = -result;        // 0.000
result = 0.002 - 0.001;  // 0.001
result = 0.002 - 0.002;  // 0.000
result = 0.002 - 0.003;  // 0.000
result = 0.001 - 0.002;  // 0.000
result = 0.001 - 0.003;  // 0.000
result = 0.001 - 0.004;  // 0.000

It looks like your floating point library has a serious shortcoming. Two more questions:

  • How are you printing out the results (show us the actual code)?
  • Which micro-controller and development environment are you using?

There may be some problem with the way you're printing or it may be a limitation of your environment.

Update 2:

Ajit, I think you're really going to have to give us some code to help you out. Not necessarily your real code (your concern about releasing the real code is understood), just some that demonstrates the problem.

Based on some of your comments, to wit:

Adriaan, the datatype for "result" is of float i.e. 32 bit representation (single). I have CAN as the system interface and hence I am multiplying the result by 1000 to send ti over the CAN. If it happens to be a negative number like -0.003 then I am expecting FF FD in the CAN message. I do not have a debugger.

I'm not sure I totally understand, but I'll give it a shot.

You have a 32-bit float, e.g., -0.003 and you multiply it by 1000 and put it in an integer (0xfffd is the 16-bit 2s complement representation of -3). So what happens when you run something like the following code:

int main(void) {
    float w = -0.003;
    int x = (int)(w * 1000);
    int y = -3;
    int z = -32768;
    // show us you code here for printing x, y and z.
    return 0;
}

The reason I want you to test an integer is that it may have nothing to do with floats at all. It may be that the float value is perfectly correct but there's some problem with the way you're printing it (the CAN method).

If "CAN" is some sort of serial interface, it may be there's a restriction on the bytes you're allowed to send across it. I can envisage a scenario where the high bytes are used as packet markers so that FF may actually end the message prematurely. That's why I also want you to test -32768 (0x8000).

It's hard to believe that STMicroelectronics would produce such a braindead runtime system that it couldn't handle negative floats. It seems much more likely to me that the information is being corrupted somewhere else (e.g., the "printing" process, whatever that may be).

paxdiablo
Here are the observations:result = 0.005 - 0.001; = 0.004result = -result; = 0result = 0.002 - 0.001; = 0.001result = 0.002 - 0.002; = 0result = 0.002 - 0.003; = 0result = 0.001 - 0.002; = 0result = 0.001 - 0.003; = 0result = 0.001 - 0.004; = 0Alsoresult = 0.01 - 0.04; = 0result = 0.01 - 0.05; = 0
Ajit
Pax, Its a ST10 series controller.
Ajit
Hey Pax,I got the fix. As you said, there is no problem with floating point arithmatic at all. The problem lies in the conversion of negative float to integer. For ST10, float w = -0.003; int x = (int)(w * 1000);results in Zero.The correct method is:1. float w = -0.003; float a = -w;2. int b = (int)(a * 1000);3. int c = -b;Thus "C" would have the signed integer corresponding to the negative float value.Thanks for your help !!!!Cheers :-)
Ajit
@Ajit, that's bizarre, and not at all what C should do. It's almost like, in your first case, it's doing int x = (int)(w) * 1000; which *would* give zero since it makes w an integer first (zero) then multiplies that by 1000 (still zero). The code you show should be fine. You should contact the people that made your compiler and let them know - this is definitely a bug.
paxdiablo
A: 

Does the microcontroller have hardware for floating-point? Probably not; microcontrollers generally don't. So, this might be a bug or limitation in the software implementation of floating-point arithmetic. Look for documentation, and/or read the source if you have it.

unwind
No the micro does not have teh floating point harware. But instead it has floating point libraries. From some previous projects, there is no error in the .lib.
Ajit
A: 

Is it possible that you are trying to print out the result of 0.001 - 0.005 as a 5 character field? If so, the result will be displayed as rounded to 0.0.

Stephen C
Thanks Stephen but I am multiplying the result by 1000 to view it as an integer.
Ajit
A: 

Can you provide more context? In this example, the evaluation is propably done by the compiler as both constants are known at the time of compilation. What is the type of 'result'? (i.e. IEEE-754 half or single or double?) How do you evaluate this? Using a debugger, if-statement or with a printf? The reason I'm asking this is because there may be a red herring. For instance if you format incorrectly using printf, you may just not see the minus sign. When you take a look at the binary representation (i.e. by printf("%lx", result) if it is 32-bit) and check the sign bit.

Adriaan
Adriaan, the datatype for "result" is of float i.e. 32 bit representation (single). I have CAN as the system interface and hence I am multiplying the result by 1000 to send ti over the CAN. If it happens to be a negative number like -0.003 then I am expecting FF FD in the CAN message. I do not have a debugger.
Ajit
A: 

It's not an inherently C thing, so it's down to the things you haven't said:-

  • Controller (ST10 Apparently)
  • Compiler (Cosmic software? If so is standards compliant)
  • Floating point library (From the compiler?)
  • The program (Shortest complete program that demonstrates it would be good.)

Could it be your cast converting from floating point to an int that you haven't shown?

JonB
Doesn't seem like because the same code works when in result is positive.I can not share the program with you due to IP issues. sorry for that.
Ajit
Surely you could do a short form of it though?I feel other parts of the code are more likely to be the problem. Your knowledge of what is in "result" is only inferred after all.
JonB
int x = (int)(w * 1000); results in ZeroTry 1000.0 it's doing an implicit conversion treating 1000 as a const int.
JonB