
Le 08/05/13 19:29, Howard Hinnant a écrit :
On May 8, 2013, at 12:08 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> 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; }