Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rounding problems when creating date vectors

I want to create a vector containing dates in matlab. For that I specified the start time and the stop time:

WHM01_start = datenum('01-JAN-2005 00:00')
WHM01_stop = datenum('01-SEP-2014 00:00')

and then I created the vector with

WHM01_timevec = WHM01_start:datenum('01-JAN-2014 00:20') - datenum('01-JAN-2014 00:00'):WHM01_stop;

after I want to have time steps of 20 minutes each. Unfortunately I get a rounding error after some thousands of values, leading me to

>> datestr(WHM01_timevec(254160))

ans =

31-Aug-2014 23:39:59

and not as expected, 31-Aug-2014 23:40:00
How can I correct these incorrect values?

Edit: I also saw this thread, but unfortunately I get there a vector per date, and not a number as desired.

like image 499
arc_lupus Avatar asked Feb 10 '23 18:02

arc_lupus


2 Answers

You can give year, month, day, ... in numeric format to the function datenum. Datenum accepts vectors for one or several of its arguments, and if the numbers are too big (for example, 120 minutes), datenum knows what to do with it.

So by supplying the minutes vector in 20-minute increments, you can avoid rounding errors (at least on a 1-second level):

WHM01_start = datenum('01-JAN-2005 00:00');
WHM01_stop = datenum('01-SEP-2014 00:00');

time_diff = WHM01_stop - WHM01_start;

WHM01_timevec = test = datenum(2005,01,01,00,[00:20:time_diff*24*60],00);

datestr(WHM01_timevec(254160))

To answer your comment:

The reason you saw rounding errors was that you used the difference of two big numbers for your time-increments. The difference of large numbers has a (relatively) large rounding error.

Matlab time is counted in days since the (fictional) date 0.0.0000. Your time-increment is 1/3 hour, or 1/(24*3) days. Modifying your original code so that it reads

WHM01_timevec = WHM01_start:1/(24*3):WHM01_stop;

is an alternative way to reduce the rounding error, but for absurdely large time spans the first solution is a more robust approach.

like image 81
Martin J.H. Avatar answered Feb 13 '23 07:02

Martin J.H.


Related answer: use linspace instead of the colon operator :.

%// given
WHM01_start = datenum('01-JAN-2005 00:00')
WHM01_stop = datenum('01-SEP-2014 00:00')

%// number of elements
n = numel(WHM01_start: datenum('01-JAN-2014 00:20') - ...
                       datenum('01-JAN-2014 00:00') : WHM01_stop);

%// creating vector using linspace
WHM01_timevec = linspace(WHM01_start, WHM01_stop, n);

%// proof
datestr(WHM01_timevec(254160))

ans =

31-Aug-2014 23:40:00

Drawback of this solution: to determine the number of elements of the output vector I use the original vector created with :, which is not the best option probably.


Important quote from the linked answer:

Using linspace can reduce the probability of occurance of these issue, it's not a security.

like image 30
Robert Seifert Avatar answered Feb 13 '23 07:02

Robert Seifert