From: Ondrej Bilka Date: 2006-09-10T23:15:13+09:00 Subject: Re: bignums On Sun, Sep 10, 2006 at 05:05:22AM +0200, nobu@ruby-lang.org wrote: > Hi, > > At Sat, 9 Sep 2006 19:10:04 +0900, > Ondrej Bilka wrote in [ruby-core:08819]: > > I thought that assembler has something like MULC which like ADC handles > > carry but didnt find anything. Assembler IMUL usualy result in twice large number stored at two registers. But it's not crossplatform. GAS manual doesnt mention amd64 only ia-64. Don't know how with other platforms. > > I written another patch. > > For 32 bits I use long long multiplication which is faster than checking by division. > > For 64bits I have heuristic that if both are <2**31 is not necessary > > perform check. But I am not sure if it will cause slowdown or speedup. > > You should use SIGNED_VALUE. > I forgot about "if (a == 0) return x;" Its not needed in 32bit case so I moved it. Originaly I thought that I can do it without division. Because I dont know how get overflow flag in c it will be there until I discover how use assembler on 64bits. I dont quite understand ia-64 registers. GAS seem not support amd64. Or I have error in this asm( "imul %%rdx;"/*tried imuld ...too*/ :"=a"(x),"=d"(y) :"a"(x),"d"(y)); Index: numeric.c =================================================================== RCS file: /src/ruby/numeric.c,v retrieving revision 1.143 diff -p -U2 -r1.143 numeric.c --- numeric.c 4 Sep 2006 20:10:45 -0000 1.143 +++ numeric.c 10 Sep 2006 12:15:12 -0000 @@ -1974,18 +1974,34 @@ fix_mul(VALUE x, VALUE y) volatile #endif - long a, b, c; + SIGNED_VALUE a, b; +#if SIZEOF_VALUE * 2 <= SIZEOF_LONG_LONG + LONG_LONG d; +#else + SIGNED_VALUE c; VALUE r; +#endif a = FIX2LONG(x); - if (a == 0) return x; - b = FIX2LONG(y); + +#if SIZEOF_VALUE * 2 <= SIZEOF_LONG_LONG + d = (LONG_LONG)a * b; + if (FIXABLE(d)) return LONG2FIX(d); + return rb_ll2inum(d); +#else +# define SQRT_LONG_MAX (1<<((SIZEOF_VALUE*CHAR_BIT-1)/2)) + /*tests if N*N would overflow*/ +# define FIT_SQRT_LONG(n) (((n)=-SQRT_LONG_MAX)) + if (FIT_SQRT_LONG(a) && FIT_SQRT_LONG(b)) + return LONG2FIX(a*b); c = a * b; r = LONG2FIX(c); + if (a == 0) return x; if (FIX2LONG(r) != c || c/a != b) { r = rb_big_mul(rb_int2big(a), rb_int2big(b)); } return r; +#endif } switch (TYPE(y)) { > > -- > Nobu Nakada