Boost logo

Boost :

Subject: Re: [boost] [chrono/date] conversion between concrete dates
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2013-05-10 13:45:39


Le 08/05/13 19:29, Howard Hinnant a écrit :
> On May 8, 2013, at 12:08 PM, Vicente J. Botet Escriba <vicente.botet_at_[hidden]> wrote:
>
>> Hi,
>>
>> as the conversion between concrete dates could be expensive I guess that these conversion must be explicit.
>>
>> But this has some consequences when used the implicit conversion was hidden a not efficient implementation, e.g.
>>
>> date ISO_week_start = mon <= jan/day(4)/y;
>>
>> jan/day(4)/y should be ymd_date as is the efficient representation.
>>
>> The date generator was declared as
>>
>> date operator<=(weekday wd, date x);
>>
>> but it works efficiently only for days_date. If we provide only the functions that are efficient we should declare it as
>>
>> days_date operator<=(weekday wd, days_date x);
>>
>> So the preceding expression would need an explicit conversion
>>
>> days_date ISO_week_start = mon <= days_date(jan/day(4)/y);
>>
>> Do we want to go on this direction?
>>
>> A radical alternative to the explicit construction, if we want to make evident that the conversion operation could be expensive, is to use a compute_ factory
>>
>> days_date ISO_week_start = mon <= compute_days_date(jan/day(4)/y);
>>
>> Best,
>> Vicente
>>
>> P.S. the generator function is just an example needing explicit conversion.
>
> I think we should consider the route of an explicit conversion between the serial date and the ymd date, and see where field experience takes us.
>
> In some timings I did last weekend I was getting about 1.2ns for a field->serial conversion averaged over 200 years, and 18ns for a serial->field conversion averaged over the same range. I was just timing the conversion function, and not any validation checks.
>
> If experience holds that serial->field is 15X the cost of field->serial, a possibility is for a hybrid approach: implicit in one direction and explicit in the other. However I wouldn't take these numbers as fact. This is just one report from one machine and one implementation.
>
>
Hi,

I have updated the test to use my current public interface.

I'm getting the following:

clang 3.2
* empty field->serial ~0.15ns.
* field->serial ~7.5ns.
* empty serial->field ~0.65ns.
* serial->field ~17.4ns.

gcc-4.8.0
* empty field->serial ~0.2ns.
* field->serial ~10.2ns.
* empty serial->field ~0ns.
* serial->field ~20.6ns.

I will check the field -> serial implementation to see why is much less
efficient than yours.

When I add validation on the source date format I get

clang 3.2
* empty field->serial ~6.3ns.
* field->serial ~13.4ns.
* empty serial->field ~1ns.
* serial->field ~17.9ns.

gcc-4.8.0
* empty field->serial ~7.5ns.
* field->serial ~15.7ns.
* empty serial->field ~1ns.
* serial->field ~21.7ns.

Best,
Vicente

==============

#include <boost/chrono/date/date.hpp>

using namespace boost::chrono;
const int Ymin = 1900;
const int Ymax = 2100;

void empty_encoding_perf()
{
   int count = 0;
   auto t0 = boost::chrono::high_resolution_clock::now();
   for (int y = Ymin; y <= Ymax; ++y)
   {
     bool is_l = year(y).is_leap();
     for (int m = 1; m <= 12; ++m)
     {
       int last = month(m).days_in(is_l).count();
       for (int d = 1; d <= last; ++d)
       {
         ymd_date dt1(year(y), month(m), d);
         if(dt1.is_valid())
         ++count;
       }
     }
   }
   auto t1 = boost::chrono::high_resolution_clock::now();
   typedef boost::chrono::duration<float, boost::nano> sec;
   auto encode = t1 - t0;
   std::cout << count << '\n';
   std::cout << encode.count() / count << '\n';
   std::cout << sec(encode).count() / count << '\n';
}

void encoding_perf()
{
   int count = 0;
   auto t0 = boost::chrono::high_resolution_clock::now();
   for (int y = Ymin; y <= Ymax; ++y)
   {
     bool is_l = year(y).is_leap();
     for (int m = 1; m <= 12; ++m)
     {
       int last = month(m).days_in(is_l).count();
       for (int d = 1; d <= last; ++d)
       {
         ymd_date dt1(year(y), month(m), d);
         volatile days_date dt2(dt1);
         if(dt1.is_valid())
         ++count;
       }
     }
   }
   auto t1 = boost::chrono::high_resolution_clock::now();
   typedef boost::chrono::duration<float, boost::nano> sec;
   auto encode = t1 - t0;
   std::cout << count << '\n';
   std::cout << encode.count() / count << '\n';
   std::cout << sec(encode).count() / count << '\n';
}

void empty_decoding_perf()
{

   const int k0 =
days_date(year(Ymin)/month(1)/1).days_since_epoch().count();
   const int k1 =
days_date(year(Ymax)/month(12)/31).days_since_epoch().count();
   int count = 0;
   auto t0 = boost::chrono::high_resolution_clock::now();
   for (int k = k0; k <= k1; ++k)
   {
     days_date dt1((days(k)));
     if(dt1.is_valid())
     ++count;

   }
   auto t1 = boost::chrono::high_resolution_clock::now();
   typedef boost::chrono::duration<float, boost::nano> sec;
   auto decode = t1 - t0;
   std::cout << count << '\n';
   std::cout << decode.count() / count << '\n';
   std::cout << sec(decode).count() / count << '\n';
}
void decoding_perf()
{

   const int k0 =
days_date(year(Ymin)/month(1)/1).days_since_epoch().count();
   const int k1 =
days_date(year(Ymax)/month(12)/31).days_since_epoch().count();
   int count = 0;
   auto t0 = boost::chrono::high_resolution_clock::now();
   for (int k = k0; k <= k1; ++k)
   {
     days_date dt1((days(k)));
     volatile ymd_date dt2(dt1);
     if(dt1.is_valid())
     ++count;

   }
   auto t1 = boost::chrono::high_resolution_clock::now();
   typedef boost::chrono::duration<float, boost::nano> sec;
   auto decode = t1 - t0;
   std::cout << count << '\n';
   std::cout << decode.count() / count << '\n';
   std::cout << sec(decode).count() / count << '\n';
}

int main()
{
   empty_encoding_perf();
   encoding_perf();
   empty_decoding_perf();
   decoding_perf();

   return 1;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk