# Arithmetic Overflow ATmega328

I have written the following function to calculate the current timestamp (since 00h Jan 1 1900). The output I get is:

Current Time & Date : 20:5:32 25/7/2014<\r>
2014 7 25 20 5 32<\r>
retval 1 3597523200<\r>
retval 2 3597523200<\r>
retval 3 3613161600<\r>
retval 4 3615235200<\r>
retval 5 3615241664<\r>
retval 6 3615241964<\r>
retval 7 3615241996<\r>
retval 8 3615241996<\r>
Current time timestamp 3615241996


Basically I am printing the retval (function return value) at every step to check and verify the calculations.

The calculation match up till retval 4 (when current day hours are converted to seconds). I think it might be due to arithmetic overflow but not sure.

The issue seems to be happening in this line:

retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);


retval is uint32_t and d.hr is uint16_t

uint32_t DS1307_GET_CURRENT_TIMESTAMP()
{
uint32_t retval = SECONDS_SINCE_1900_TO_2014;
ds1307 d;
DS1307_GET_DATETIME(&d);
printf("%u %u %u %u %u %u\r", d.yy,d.mm,d.dd,d.hr, d.min, d.sec);
printf("retval 1 %"PRIu32"\r", retval);
//process complete years since 2014 to current year
uint8_t i=0;
for(i=0; i<(d.yy - 2014); i++)
{
if(DS1307_IS_LEAP_YEAR(2014+i)==0) retval += 31622400;
else retval += 31536000;
}
printf("retval 2 %"PRIu32"\r", retval);

//process complete months from beginning of current year to current date/time
for(i=1; i<d.mm; i++)
{
if((i==1) || (i==3) || (i==5) || (i==7) || (i==8) || (i==10) || (i==12))
{
//31 days
retval += (31 * 86400);
}
else if ((i==4) || (i==6) || (i==9) || (i==11))
{
//30 days
retval += (30 * 86400);
}
else
{
//i==2==february. check if leap year
if(DS1307_IS_LEAP_YEAR(d.yy)==0) retval += (29 * 86400);
else retval += (28 * 86400);
}
}
printf("retval 3 %"PRIu32"\r", retval);

//process complete days from beginning of month till current date
retval += ((d.dd-1) * 86400);
printf("retval 4 %"PRIu32"\r", retval);

//process hours, min and seconds - CALCULATION DEVIATES HERE.
retval += (d.hr * 60 * 60); printf("retval 5 %"PRIu32"\r", retval);
retval += (d.min * 60); printf("retval 6 %"PRIu32"\r", retval);
retval += d.sec; printf("retval 7 %"PRIu32"\r", retval);

printf("retval 8 %"PRIu32"\r", retval);

return retval;
}


20 * 60 * 60 = 72000

You need to perform the multiplication in 32 bits in order to avoid an overflow.

retval += (d.hr * 60UL * 60);

• Ok. So when I write a c arithmetic statement (multiplication in this context) how does c decide what would be the overflow point or what's the maximum size of that operation? Does it depend on the size of the storage registers the platform provides (16 bit in AVR case)? – Ankit Jul 25 '14 at 20:56
• It depends on the size of int unless one of the operands overrides it, hence the L suffix on the literal (for long). – Ignacio Vazquez-Abrams Jul 25 '14 at 21:23
• Now that I think about it, there's no reason for it to be signed... – Ignacio Vazquez-Abrams Jul 25 '14 at 23:21

(3615235200-3613161600)/(24*60*60) = 24, so the change at 'retval 4' is correct and not an overflow, so your assertion that they are correct "til you get to retval 4" is false.

retval 5 however gives (3615241664-3615235200) = 60*60*20 - 2**16, so there is an overflow. Use a uint32_t on the right hand side of retval += d.hr * uint32_t(60 * 60u).

Before your edit, you were missing a space between "retval 3" and "3613161600" .

• The space after retval 3 is a typo. I'm taking that into consideration. Also as mentioned, retval 4 is correct. It's retval 5 that is giving the wrong result. Lastly, as shown in output, the code is being run @ July 25, 2014 – Ankit Jul 25 '14 at 16:14