On Mon, Apr 3, 2017 at 10:18 PM, Colin Bartlett <colinb2r / googlemail.com> wrote:
> I've been looking at the C code for the Date class (and at some of the
> C code for the Time class) and it seems to be possible to make some of
> this quite a bit faster (from 5 to 70 times faster, depending on the
> function, computer, compiler options, etc), partly by replacing some
> floating point calculations by integer calculations, and partly by
> using some different algorithms.
>
> While doing that I found these leap year functions in
> ruby-2.4.0/ext/date/date_core.c
>
> #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
> #define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d))
>
> inline static int
> c_gregorian_leap_p(int y)
> {
>     return (MOD(y, 4) == 0 && y % 100 != 0) || MOD(y, 400) == 0;
> }
>
> and in ruby-2.4.0/time.c
>
> static int
> leap_year_p(long y)
> {
>     return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
> }
>
> Unless I'm missing something (which is not impossible):
>
> 1. Instead of using "MOD", the date_core.c code could just use the
> time.c code, of course with int y instead of long y.

Is it guaranteed that for all x : long this holds:

x % 100 == ((int) x) % 100

? Put differently, since 100 is not a pure power of two wouldn't we
change the outcome of that calculation?

> I don't see that
> there is any need to use "MOD" instead of "%": all we are interested
> in here is whether y is or is not exactly divisible by 4, 100 or 400,
> and it doesn't matter whether, for example,
>     "y % 4" is implemented as "y - 4 * trunc(y / 4)" or "y - 4 * floor(y / 4)"

If you care for efficiency and we do not have negative values we could
also replace x % 4 == 0 with

x & 0x3 == 0

But I would consider that a micro optimization that the compiler might
do anyway.

> So as I see it, the time.c (and date_core.c) code isn't wrong, because
> it gives the correct result but it is a little slower than it could
> be, and this could be remedied by simply moving two brackets.

Can you show some figures about the speed difference? It would also be
interesting what difference it makes for real Ruby programs.

Kind regards

robert

-- 
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can
- without end}
http://blog.rubybestpractices.com/

Unsubscribe: <mailto:ruby-talk-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>