Bizarre, simple math not giving expected result.

Hi, I've been try to do some simple math in a function and for the life of me I can't get it working. I've been trying for to many hours.

In the function below it checks the last feed time to the current time to find out how many seconds its been since the last feeding. Then the seconds get converted to minutes and hours. Then the minutes loop at 60, so 58min, 59min, 0min, 1min, etc...

That all works great, now I'm trying to take my elapsedSec and have a separate variable loop at 3600 seconds or 1 hour.

So I'm taking the total elaspsedSec and subtracting that from the elaspedHr * 3600.

As an example this is the results I'm getting.

Lets say last feeding was just over 16 hours.

In the serial window it will tell me the elaspedSec = 57805 - correct In the serial window it will tell me the elaspedHr = 16 - correct In the serial window it will tell me the elaspedMin = 3 - correct

So far so good, its been 16hrs and 3mins.

Then I do this.

feedSeconds = (elapsedSec - (elapsedHr * 3600));

expecting 205 but I get 65741??

I don't see how its getting 65741 from what I have.

Here's the complete function.

time_t calcFeedingMin()
{
  // need to retrieve and calculate last feeding time

  if (EEPROM.read(0)==1)
  {
    RTC.now();
    time_t currentStamp = tmConvert_t(year(),month(),day(),hour(),minute(),second());

    byte lastSec = 0;
    byte lastMin = EEPROM.read(1);
    byte lastHr = EEPROM.read(2);
    byte lastDay = EEPROM.read(3);
    byte lastMon = EEPROM.read(4);
    int lastYear = (EEPROM.read(5)+2000);

    time_t lastStamp = tmConvert_t(lastYear,lastMon,lastDay,lastHr,lastMin,lastSec);
    long elapsedSec = (currentStamp-lastStamp);  // this returns the total seconds since last feeding
        
    int elapsedHr = elapsedSec/60/60; // this returns total hours
    int elaspedMin = elapsedSec/60;  // this returns total minutes
    elaspedMin = elaspedMin - (elapsedHr * 60);  // this loops minutes at 60
    
    Serial.println(elapsedSec);  // result is as expected
    Serial.println(elaspedMin);  // result is as expected
    Serial.println(elapsedHr);  // result is as expected    
    
    feedSeconds = (elapsedSec - (elapsedHr * 3600));  // result very unexpected
    // feedSeconds is a long declared globally but should be an int I would think as this number should never be larger than 3599. Doesn't make any difference. Have tried all kinds of formulas and different variable types but nothing seems to work.
    
    Serial.println(feedSeconds);  // result unexpected
    return elaspedMin;
  }
  else if (EEPROM.read(0)==0)
  {
    return 0;
  }
}

So what the heck could I be missing?

Hmm. Interesting :)

http://www.gammon.com.au/forum/?id=12146

    feedSeconds = (elapsedSec - (elapsedHr * 3600));  // result very unexpected

In the serial window it will tell me the elaspedHr = 16 - correct

So 16 * 3600 = 57600 which does not fit into an it. Trouble brewing.

57600 - 65536  = -7936     // 65536 is 2^16
57805 - (-7936) = 65741

Results entirely as expected. :P

@robsworld78: Please don't delete your original post like that. I spent 10 minutes replying, and now the reply looks completely meaningless. Makes me not want to help next time.

I still have the code, thankfully, so I'll reproduce it here to try to salvage my reply.

time_t calcFeedingMin()
{
  // need to retrieve and calculate last feeding time

  if (EEPROM.read(0)==1)
  {
    RTC.now();
    time_t currentStamp = tmConvert_t(year(),month(),day(),hour(),minute(),second());

    byte lastSec = 0;
    byte lastMin = EEPROM.read(1);
    byte lastHr = EEPROM.read(2);
    byte lastDay = EEPROM.read(3);
    byte lastMon = EEPROM.read(4);
    int lastYear = (EEPROM.read(5)+2000);

    time_t lastStamp = tmConvert_t(lastYear,lastMon,lastDay,lastHr,lastMin,lastSec);
    long elapsedSec = (currentStamp-lastStamp);  // this returns the total seconds since last feeding

    int elapsedHr = elapsedSec/60/60; // this returns total hours
    int elaspedMin = elapsedSec/60;  // this returns total minutes
    elaspedMin = elaspedMin - (elapsedHr * 60);  // this loops minutes at 60

      Serial.println(elapsedSec);  // result is as expected
    Serial.println(elaspedMin);  // result is as expected
    Serial.println(elapsedHr);  // result is as expected    

    feedSeconds = (elapsedSec - (elapsedHr * 3600));  // result very unexpected
    // feedSeconds is a long declared globally but should be an int I would think as this number should never be larger than 3599. Doesn't make any difference. Have tried all kinds of formulas and different variable types but nothing seems to work.

    Serial.println(feedSeconds);  // result unexpected
    return elaspedMin;
  }
  else if (EEPROM.read(0)==0)
  {
    return 0;
  }
}

elapsedHr was 16 elapsedSec was 57805

The OP expected feedSeconds to be 57805 - (16 * 3600) = 205 seconds. What he actually got was 65741.

Above, I explain why. Integer truncation.

Sorry about that, it was still in the browser so I replaced it. Won’t do it again. :slight_smile:

Yes 57600 won’t fit in an int but the equazion says to subtract that from 58000, so the number is only 400.

Oddly its working now and I still have the exact code I posted.

I did have feedSeconds as a long when I posted, not an int. I just changed it to an int and it still gives the expected result. Working fine now. Don’t know why.

robsworld78: Sorry about that, it was still in the browser so I replaced it. Won't do it again. :)

Yes 57600 won't fit in an int but the equazion says to subtract that from 58000, so the number is only 400.

Oddly its working now and I still have the exact code I posted.

But the rollover happened before you did the subtraction. So the thing that was subtracted wasn't what you thought it was.

Unless you specify otherwise, all math is done with 16 bit integers.

Oddly it is working now, but I bet it will crash once the time numbers get big enough to roll over again.

True, it could happen just before and give an odd result. I've changed feedSeconds back to a long.

None of these number will ever be larger than 172800 and that's really pushing it.

robsworld78: True, it could happen just before and give an odd result. I've changed feedSeconds back to a long.

None of these number will ever be larger than 172800 and that's really pushing it.

Yes that REALLY is pushing it for an int type value. :)

robsworld78: Yes 57600 won't fit in an int but the equazion says to subtract that from 58000, so the number is only 400.

 int elaspedMin = elapsedSec/60;  // this returns total minutes
    elaspedMin = elaspedMin - (elapsedHr * 60);  // this loops minutes at 60

Yes but that is all integer arithmetic. And (elapsedHr * 60) is done first, so you get the truncation before the subtraction.

[quote author=Nick Gammon date=1424484702 link=msg=2103981]

 int elaspedMin = elapsedSec/60;  // this returns total minutes
    elaspedMin = elaspedMin - (elapsedHr * 60);  // this loops minutes at 60

Yes but that is all integer arithmetic. And (elapsedHr * 60) is done first, so you get the truncation before the subtraction. [/quote] Yes I understand now, thanks! I've changed it to a long so it should be good.