So the past couple weeks we’ve been working on our autonomous code on a test robot. Over this time we’ve been having problems and wracking our brains about outputs that just don’t seem to make sense. I managed to track down at least one of the problems today and it appears to be a compiler bug. This is not a request for help but just trying to inform everyone else of the issue.
If you use the following statement:
long coeff_1 = 90/2*40;
coeff_1 will equal 8. Now this is obviously not the correct value (it should be 1800). For some reason, the compiler appears to do math in initalization statements (for long’s at least) in a 8-bit space (1800 = 8 in an 8-bit space).
If you use this code:
long coeff_1 = 1800;
it will work correctly.
The long and the short of it is to always do any math out before putting it in the source code. While it’s more work for you, it results in correctly generated code.
I’m not sure where to report this bug to Microchip so if anyone knows, please tell me.
I’ve noticed in general that the C18 compiler handles casting in interesting and often unexpected ways. If you explicitly cast one of those numbers as a long, it should work correctly. However, your point that you should work out as much math as you can before putting it into the code is absolutely correct, in that you’ll always get the right answer, and it takes fewer processor cycles.
I don’t think this is a casting error. Assuming there’s some optimization in the compiler, the compiler will do the math before hand (because it can) and save the cycles on the processor. However, the compiler is incorrectly calculating the output. I don’t have the compiled version handy to check the assembly but I may check that tomorrow afternoon.
I wouldn’t call it an error on your part, but rather an eccentricity of the compiler. I too have noticed any number of weird losses of precision or other unexpected results. I sure can’t read assembly, but I’ll be interested to hear what you turn up tomorrow.
I believe what happens is that because 90, 2, and 45 all fit in a char (it may only look at the 90), the compiler will use that size for all its intermediate results. (I’m not saying it’s right. Just that’s the way it is.)
90L/2*40 should work as you expect. (90L tells the compiler that the 90 is a long constant.)
There is a compiler option to tell it to promote for intermediate steps, which is what you are expecting. Otherwise, it saves stack space and processing power by doing the calculations as chars.
AFAIK, this behavior is in violation of the ANSI standard, but is very common for embedded processors.