Basic question: How far do I have to go to assure that integer math is done correctly? For example, this is probably overdone:

unsigned long burnTime = 0UL;
unsigned long curBurnTime = 0UL;
// Do some stuff that sets the above variables to millis() at various times
// Later on...
unsigned long adjustedBurnTime = (unsigned long) ((burnTime + curBurnTime) / 1000UL);

Would the math be done correctly if I went to a more minimal last statement (since all the elements of the equation are unsigned longs)? Like this:

unsigned long adjustedBurnTime = ((burnTime + curBurnTime) / 1000UL);

Or even:

unsigned long adjustedBurnTime = ((burnTime + curBurnTime) / 1000);
  • 3
    Only one way to really find out! Compile them both and disassemble them. – Ignacio Vazquez-Abrams Nov 13 '14 at 22:26
  • 2
    @IgnacioVazquez-Abrams either that or read through the GCC compiler code. :) Printing output to serial is, of course, the easiest! – Anonymous Penguin Nov 13 '14 at 22:30
  • 1
    This issue is very relavent to time; check out playground.arduino.cc/Code/TimingRollover it outlines the same issue. Where I would agree with TMA, in that since all are casted the same, it is not needed. However, I always play it safe. In case the casting was changed. – mpflaga Nov 14 '14 at 14:31
  • 1
    I compiled all three of the examples above and the result was three identical hex files. Unless I'm missing something it seems I've answered my question. ...Am I missing something? – bluesmoke Nov 14 '14 at 19:27
  • 1
    No, your're not; the hex file exactly represents your code (plus some loading instructions). If two hex files are identical, and presented to the same loader, the results (the memory loads) have to be identical. – JRobert Nov 15 '14 at 18:36

Any good C manual will tell you the result type for each basic math operation on given types. But briefly, the basic math operators return a result as wide as the widest operand, with the narrower operand being widened to match the wider one, if they differ. The same with assignment: assigning a result of a given type to a variable of the same type will not involve any conversion.

tl;dr: No, you're not missing anything. You don't need any casts in your example.

PS: One thing you do need to be aware of is whether any of your intermediate results will overflow the arithmetic type you're using. For example, the final result may be not exceed an unsigned long but the expressions (burnTime + curBurnTime) must also not exceed it. This is a greater concern with smaller data-types, of course.

PPS: Good on you for tackling fixed point arithmetic rather than just reaching for the floating-point library!

  • Thanks, that's a great answer because it explains not just whether but why. My uninformed guess would have been the opposite. Also very appreciative of the warning on intermediate results; it would have been just a matter of time until that bit me. – bluesmoke Nov 14 '14 at 23:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.