2000-05-01 13:42:38 +04:00
/**********************************************************************
1998-01-16 15:13:05 +03:00
bignum . c -
$ Author $
created at : Fri Jun 10 00 : 48 : 55 JST 1994
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 07:29:39 +04:00
Copyright ( C ) 1993 - 2007 Yukihiro Matsumoto
2000-05-01 13:42:38 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-01-16 15:13:05 +03:00
2007-06-10 07:06:15 +04:00
# include "ruby/ruby.h"
2012-07-10 17:57:11 +04:00
# include "ruby/thread.h"
2009-05-26 08:58:15 +04:00
# include "ruby/util.h"
* internal.h: declare internal functions here.
* node.h: declare NODE dependent internal functions here.
* iseq.h: declare rb_iseq_t dependent internal functions here.
* vm_core.h: declare rb_thread_t dependent internal functions here.
* bignum.c, class.c, compile.c, complex.c, cont.c, dir.c, encoding.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c, io.c,
iseq.c, load.c, marshal.c, math.c, numeric.c, object.c, parse.y,
proc.c, process.c, range.c, rational.c, re.c, ruby.c, string.c,
thread.c, time.c, transcode.c, variable.c, vm.c,
tool/compile_prelude.rb: don't declare internal functions declared
in above headers. include above headers if required.
Note that rb_thread_mark() was declared as
void rb_thread_mark(rb_thread_t *th) in cont.c but defined as
void rb_thread_mark(void *ptr) in vm.c. Now it is declared as
the later in internal.h.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2011-06-18 02:43:38 +04:00
# include "internal.h"
2002-05-14 10:22:31 +04:00
2012-07-18 22:48:14 +04:00
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
1998-01-16 15:13:05 +03:00
# include <math.h>
2007-05-02 12:12:31 +04:00
# include <float.h>
1999-01-20 07:59:39 +03:00
# include <ctype.h>
2003-12-22 11:23:55 +03:00
# ifdef HAVE_IEEEFP_H
# include <ieeefp.h>
# endif
2008-12-14 06:59:02 +03:00
# include <assert.h>
1998-01-16 15:13:05 +03:00
2013-08-31 16:17:18 +04:00
# if defined(HAVE_LIBGMP) && defined(HAVE_GMP_H)
# define USE_GMP
# include <gmp.h>
# endif
2013-09-07 23:04:23 +04:00
# define RB_BIGNUM_TYPE_P(x) RB_TYPE_P((x), T_BIGNUM)
1999-01-20 07:59:39 +03:00
VALUE rb_cBignum ;
2013-07-07 15:02:47 +04:00
const char ruby_digitmap [ ] = " 0123456789abcdefghijklmnopqrstuvwxyz " ;
2000-06-04 19:32:19 +04:00
2013-07-10 15:10:05 +04:00
# ifndef SIZEOF_BDIGIT_DBL
2013-11-24 08:51:33 +04:00
# if SIZEOF_INT*2 <= SIZEOF_LONG_LONG
2013-07-10 15:10:05 +04:00
# define SIZEOF_BDIGIT_DBL SIZEOF_LONG_LONG
# else
# define SIZEOF_BDIGIT_DBL SIZEOF_LONG
# endif
2013-07-10 09:58:45 +04:00
# endif
2013-07-10 15:48:24 +04:00
STATIC_ASSERT ( sizeof_bdigit_dbl , sizeof ( BDIGIT_DBL ) = = SIZEOF_BDIGIT_DBL ) ;
2013-07-15 08:50:49 +04:00
STATIC_ASSERT ( sizeof_bdigit_dbl_signed , sizeof ( BDIGIT_DBL_SIGNED ) = = SIZEOF_BDIGIT_DBL ) ;
STATIC_ASSERT ( sizeof_bdigit , SIZEOF_BDIGITS < = sizeof ( BDIGIT ) ) ;
STATIC_ASSERT ( sizeof_bdigit_and_dbl , SIZEOF_BDIGITS * 2 < = SIZEOF_BDIGIT_DBL ) ;
STATIC_ASSERT ( bdigit_signedness , 0 < ( BDIGIT ) - 1 ) ;
STATIC_ASSERT ( bdigit_dbl_signedness , 0 < ( BDIGIT_DBL ) - 1 ) ;
STATIC_ASSERT ( bdigit_dbl_signed_signedness , 0 > ( BDIGIT_DBL_SIGNED ) - 1 ) ;
2013-07-10 17:46:38 +04:00
STATIC_ASSERT ( rbignum_embed_len_max , RBIGNUM_EMBED_LEN_MAX < = ( RBIGNUM_EMBED_LEN_MASK > > RBIGNUM_EMBED_LEN_SHIFT ) ) ;
2013-07-10 15:48:24 +04:00
2013-07-17 17:53:24 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
STATIC_ASSERT ( sizeof_long_and_sizeof_bdigit , SIZEOF_LONG % SIZEOF_BDIGITS = = 0 ) ;
# else
STATIC_ASSERT ( sizeof_long_and_sizeof_bdigit , SIZEOF_BDIGITS % SIZEOF_LONG = = 0 ) ;
# endif
2013-06-21 21:22:14 +04:00
# ifdef WORDS_BIGENDIAN
# define HOST_BIGENDIAN_P 1
# else
# define HOST_BIGENDIAN_P 0
# endif
# define ALIGNOF(type) ((int)offsetof(struct { char f1; type f2; }, f2))
2013-09-01 08:03:32 +04:00
/* (!LSHIFTABLE(d, n) ? 0 : (n)) is same as n but suppress a warning, C4293, by Visual Studio. */
2013-06-26 10:27:29 +04:00
# define LSHIFTABLE(d, n) ((n) < sizeof(d) * CHAR_BIT)
# define LSHIFTX(d, n) (!LSHIFTABLE(d, n) ? 0 : ((d) << (!LSHIFTABLE(d, n) ? 0 : (n))))
2013-06-22 08:12:48 +04:00
# define CLEAR_LOWBITS(d, numbits) ((d) & LSHIFTX(~((d)*0), (numbits)))
2013-06-22 04:56:53 +04:00
# define FILL_LOWBITS(d, numbits) ((d) | (LSHIFTX(((d)*0+1), (numbits))-1))
2013-06-25 17:47:39 +04:00
# define POW2_P(x) (((x)&((x)-1))==0)
2013-06-21 21:22:14 +04:00
2007-09-01 16:02:36 +04:00
# define BDIGITS(x) (RBIGNUM_DIGITS(x))
2002-04-10 12:45:26 +04:00
# define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
2000-11-01 11:49:40 +03:00
# define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
2011-05-22 19:37:00 +04:00
# define BIGRAD_HALF ((BDIGIT)(BIGRAD >> 1))
2013-06-25 07:08:23 +04:00
# define BDIGIT_MSB(d) (((d) & BIGRAD_HALF) != 0)
2013-06-23 20:05:15 +04:00
# define BIGUP(x) LSHIFTX(((x) + (BDIGIT_DBL)0), BITSPERDIG)
2010-12-02 11:01:24 +03:00
# define BIGDN(x) RSHIFT((x),BITSPERDIG)
2013-06-21 14:40:19 +04:00
# define BIGLO(x) ((BDIGIT)((x) & BDIGMAX))
# define BDIGMAX ((BDIGIT)(BIGRAD-1))
2013-07-02 15:52:13 +04:00
# define BDIGIT_DBL_MAX (~(BDIGIT_DBL)0)
1998-01-16 15:13:05 +03:00
2013-06-21 21:22:14 +04:00
# if SIZEOF_BDIGITS == 2
# define swap_bdigit(x) swap16(x)
# elif SIZEOF_BDIGITS == 4
# define swap_bdigit(x) swap32(x)
# elif SIZEOF_BDIGITS == 8
# define swap_bdigit(x) swap64(x)
# endif
2008-02-22 13:50:21 +03:00
# define BIGZEROP(x) (RBIGNUM_LEN(x) == 0 || \
( BDIGITS ( x ) [ 0 ] = = 0 & & \
( RBIGNUM_LEN ( x ) = = 1 | | bigzero_p ( x ) ) ) )
2013-06-20 03:09:05 +04:00
# define BIGSIZE(x) (RBIGNUM_LEN(x) == 0 ? (size_t)0 : \
BDIGITS ( x ) [ RBIGNUM_LEN ( x ) - 1 ] ? \
( size_t ) ( RBIGNUM_LEN ( x ) * SIZEOF_BDIGITS - nlz ( BDIGITS ( x ) [ RBIGNUM_LEN ( x ) - 1 ] ) / CHAR_BIT ) : \
rb_absint_size ( x , NULL ) )
2008-02-22 13:50:21 +03:00
2013-08-17 19:48:44 +04:00
# define BIGDIVREM_EXTRA_WORDS 1
2013-07-02 18:49:06 +04:00
# define roomof(n, m) ((long)(((n)+(m)-1) / (m)))
2013-06-19 20:37:14 +04:00
# define bdigit_roomof(n) roomof(n, SIZEOF_BDIGITS)
2013-06-15 15:15:23 +04:00
# define BARY_ARGS(ary) ary, numberof(ary)
2013-06-16 18:16:33 +04:00
# define BARY_ADD(z, x, y) bary_add(BARY_ARGS(z), BARY_ARGS(x), BARY_ARGS(y))
# define BARY_SUB(z, x, y) bary_sub(BARY_ARGS(z), BARY_ARGS(x), BARY_ARGS(y))
2013-08-24 20:51:23 +04:00
# define BARY_SHORT_MUL(z, x, y) bary_short_mul(BARY_ARGS(z), BARY_ARGS(x), BARY_ARGS(y))
2013-06-16 18:16:33 +04:00
# define BARY_DIVMOD(q, r, x, y) bary_divmod(BARY_ARGS(q), BARY_ARGS(r), BARY_ARGS(x), BARY_ARGS(y))
# define BARY_ZERO_P(x) bary_zero_p(BARY_ARGS(x))
2013-06-29 19:57:07 +04:00
# define RBIGNUM_SET_NEGATIVE_SIGN(b) RBIGNUM_SET_SIGN(b, 0)
# define RBIGNUM_SET_POSITIVE_SIGN(b) RBIGNUM_SET_SIGN(b, 1)
2013-07-07 15:02:47 +04:00
# define bignew(len,sign) bignew_1(rb_cBignum,(len),(sign))
2013-07-18 08:00:49 +04:00
# define BDIGITS_ZERO(ptr, n) do { \
BDIGIT * bdigitz_zero_ptr = ( ptr ) ; \
size_t bdigitz_zero_n = ( n ) ; \
while ( bdigitz_zero_n ) { \
* bdigitz_zero_ptr + + = 0 ; \
bdigitz_zero_n - - ; \
} \
} while ( 0 )
2013-08-03 20:58:30 +04:00
# define BARY_TRUNC(ds, n) do { \
while ( 0 < ( n ) & & ( ds ) [ ( n ) - 1 ] = = 0 ) \
( n ) - - ; \
} while ( 0 )
2013-07-22 22:35:27 +04:00
# define KARATSUBA_BALANCED(xn, yn) ((yn) / 2 < (xn))
# define TOOM3_BALANCED(xn, yn) (((yn)+2) / 3 * 2 < (xn))
2013-08-31 16:17:18 +04:00
# define GMP_MUL_DIGITS 20
2013-07-01 17:59:50 +04:00
# define KARATSUBA_MUL_DIGITS 70
# define TOOM3_MUL_DIGITS 150
2013-09-05 03:22:27 +04:00
# define GMP_DIV_DIGITS 20
2013-09-01 18:34:53 +04:00
# define GMP_BIG2STR_DIGITS 20
2013-09-03 15:20:02 +04:00
# define GMP_STR2BIG_DIGITS 20
2013-09-01 18:34:53 +04:00
2013-08-05 18:50:07 +04:00
typedef void ( mulfunc_t ) ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn ) ;
2013-07-11 07:06:02 +04:00
static mulfunc_t bary_mul_toom3_start ;
static mulfunc_t bary_mul_karatsuba_start ;
2013-08-09 23:55:24 +04:00
static BDIGIT bigdivrem_single ( BDIGIT * qds , const BDIGIT * xds , size_t xn , BDIGIT y ) ;
2013-08-05 18:50:07 +04:00
static void bary_divmod ( BDIGIT * qds , size_t qn , BDIGIT * rds , size_t rn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn ) ;
2013-06-06 15:57:35 +04:00
2013-07-01 17:59:50 +04:00
static VALUE bigmul0 ( VALUE x , VALUE y ) ;
2013-07-28 07:12:36 +04:00
static void bary_mul_toom3 ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn ) ;
2013-07-07 15:02:47 +04:00
static VALUE bignew_1 ( VALUE klass , long len , int sign ) ;
static inline VALUE bigtrunc ( VALUE x ) ;
2013-07-01 17:59:50 +04:00
2013-07-16 15:23:03 +04:00
static VALUE bigsq ( VALUE x ) ;
2013-07-07 15:02:47 +04:00
static void bigdivmod ( VALUE x , VALUE y , volatile VALUE * divp , volatile VALUE * modp ) ;
2013-08-03 19:41:31 +04:00
static inline VALUE power_cache_get_power ( int base , int power_level , size_t * numdigits_ret ) ;
2011-05-22 19:37:00 +04:00
2013-08-07 02:43:01 +04:00
# if SIZEOF_BDIGITS <= SIZEOF_INT
static int nlz ( BDIGIT x ) { return nlz_int ( ( unsigned int ) x ) - ( SIZEOF_INT - SIZEOF_BDIGITS ) * CHAR_BIT ; }
# elif SIZEOF_BDIGITS <= SIZEOF_LONG
static int nlz ( BDIGIT x ) { return nlz_long ( ( unsigned long ) x ) - ( SIZEOF_LONG - SIZEOF_BDIGITS ) * CHAR_BIT ; }
# elif SIZEOF_BDIGITS <= SIZEOF_LONG_LONG
static int nlz ( BDIGIT x ) { return nlz_long_long ( ( unsigned LONG_LONG ) x ) - ( SIZEOF_LONG_LONG - SIZEOF_BDIGITS ) * CHAR_BIT ; }
# elif SIZEOF_BDIGITS <= SIZEOF_INT128_T
static int nlz ( BDIGIT x ) { return nlz_int128 ( ( uint128_t ) x ) - ( SIZEOF_INT128_T - SIZEOF_BDIGITS ) * CHAR_BIT ; }
2013-06-30 20:01:53 +04:00
# endif
2013-07-04 15:23:46 +04:00
# define U16(a) ((uint16_t)(a))
# define U32(a) ((uint32_t)(a))
# ifdef HAVE_UINT64_T
# define U64(a,b) (((uint64_t)(a) << 32) | (b))
# endif
# ifdef HAVE_UINT128_T
# define U128(a,b,c,d) (((uint128_t)U64(a,b) << 64) | U64(c,d))
# endif
/* The following scirpt, maxpow.rb, generates the tables follows.
def big ( n , bits )
ns = [ ]
( ( bits + 31 ) / 32 ) . times {
ns < < sprintf ( " 0x%08x " , n & 0xffff _ffff )
n > > = 32
}
" U#{bits}( " + ns . reverse . join ( " , " ) + " ) "
end
def values ( ary , width , indent )
lines = [ " " ]
ary . each { | e |
lines < < " " if ! ary . last . empty ? & & width < ( lines . last + e + " , " ) . length
lines . last < < e + " , "
}
lines . map { | line | " " * indent + line . chomp ( " " ) + " \n " } . join
end
[ 16 , 32 , 64 , 128 ] . each { | bits |
max = 2 * * bits - 1
exps = [ ]
nums = [ ]
2. upto ( 36 ) { | base |
exp = 0
n = 1
while n * base < = max
exp + = 1
n * = base
end
exps < < exp . to_s
nums < < big ( n , bits )
}
puts " #ifdef HAVE_UINT#{bits}_T "
2013-07-04 18:41:26 +04:00
puts " static const int maxpow#{bits}_exp[35] = { "
2013-07-04 15:23:46 +04:00
print values ( exps , 70 , 4 )
puts " }; "
2013-07-04 18:41:26 +04:00
puts " static const uint#{bits}_t maxpow#{bits}_num[35] = { "
2013-07-04 15:23:46 +04:00
print values ( nums , 70 , 4 )
puts " }; "
puts " #endif "
}
*/
# ifdef HAVE_UINT16_T
2013-07-04 18:41:26 +04:00
static const int maxpow16_exp [ 35 ] = {
2013-07-04 15:23:46 +04:00
15 , 10 , 7 , 6 , 6 , 5 , 5 , 5 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
} ;
2013-07-04 18:41:26 +04:00
static const uint16_t maxpow16_num [ 35 ] = {
2013-07-04 15:23:46 +04:00
U16 ( 0x00008000 ) , U16 ( 0x0000e6a9 ) , U16 ( 0x00004000 ) , U16 ( 0x00003d09 ) ,
U16 ( 0x0000b640 ) , U16 ( 0x000041a7 ) , U16 ( 0x00008000 ) , U16 ( 0x0000e6a9 ) ,
U16 ( 0x00002710 ) , U16 ( 0x00003931 ) , U16 ( 0x00005100 ) , U16 ( 0x00006f91 ) ,
U16 ( 0x00009610 ) , U16 ( 0x0000c5c1 ) , U16 ( 0x00001000 ) , U16 ( 0x00001331 ) ,
U16 ( 0x000016c8 ) , U16 ( 0x00001acb ) , U16 ( 0x00001f40 ) , U16 ( 0x0000242d ) ,
U16 ( 0x00002998 ) , U16 ( 0x00002f87 ) , U16 ( 0x00003600 ) , U16 ( 0x00003d09 ) ,
U16 ( 0x000044a8 ) , U16 ( 0x00004ce3 ) , U16 ( 0x000055c0 ) , U16 ( 0x00005f45 ) ,
U16 ( 0x00006978 ) , U16 ( 0x0000745f ) , U16 ( 0x00008000 ) , U16 ( 0x00008c61 ) ,
U16 ( 0x00009988 ) , U16 ( 0x0000a77b ) , U16 ( 0x0000b640 ) ,
} ;
# endif
# ifdef HAVE_UINT32_T
2013-07-04 18:41:26 +04:00
static const int maxpow32_exp [ 35 ] = {
2013-07-04 15:23:46 +04:00
31 , 20 , 15 , 13 , 12 , 11 , 10 , 10 , 9 , 9 , 8 , 8 , 8 , 8 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ,
} ;
2013-07-04 18:41:26 +04:00
static const uint32_t maxpow32_num [ 35 ] = {
2013-07-04 15:23:46 +04:00
U32 ( 0x80000000 ) , U32 ( 0xcfd41b91 ) , U32 ( 0x40000000 ) , U32 ( 0x48c27395 ) ,
U32 ( 0x81bf1000 ) , U32 ( 0x75db9c97 ) , U32 ( 0x40000000 ) , U32 ( 0xcfd41b91 ) ,
U32 ( 0x3b9aca00 ) , U32 ( 0x8c8b6d2b ) , U32 ( 0x19a10000 ) , U32 ( 0x309f1021 ) ,
U32 ( 0x57f6c100 ) , U32 ( 0x98c29b81 ) , U32 ( 0x10000000 ) , U32 ( 0x18754571 ) ,
U32 ( 0x247dbc80 ) , U32 ( 0x3547667b ) , U32 ( 0x4c4b4000 ) , U32 ( 0x6b5a6e1d ) ,
U32 ( 0x94ace180 ) , U32 ( 0xcaf18367 ) , U32 ( 0x0b640000 ) , U32 ( 0x0e8d4a51 ) ,
U32 ( 0x1269ae40 ) , U32 ( 0x17179149 ) , U32 ( 0x1cb91000 ) , U32 ( 0x23744899 ) ,
U32 ( 0x2b73a840 ) , U32 ( 0x34e63b41 ) , U32 ( 0x40000000 ) , U32 ( 0x4cfa3cc1 ) ,
U32 ( 0x5c13d840 ) , U32 ( 0x6d91b519 ) , U32 ( 0x81bf1000 ) ,
} ;
# endif
# ifdef HAVE_UINT64_T
2013-07-04 18:41:26 +04:00
static const int maxpow64_exp [ 35 ] = {
2013-07-04 15:23:46 +04:00
63 , 40 , 31 , 27 , 24 , 22 , 21 , 20 , 19 , 18 , 17 , 17 , 16 , 16 , 15 , 15 , 15 ,
15 , 14 , 14 , 14 , 14 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 12 , 12 , 12 , 12 , 12 ,
12 ,
} ;
2013-07-04 18:41:26 +04:00
static const uint64_t maxpow64_num [ 35 ] = {
2013-07-04 15:23:46 +04:00
U64 ( 0x80000000 , 0x00000000 ) , U64 ( 0xa8b8b452 , 0x291fe821 ) ,
U64 ( 0x40000000 , 0x00000000 ) , U64 ( 0x6765c793 , 0xfa10079d ) ,
U64 ( 0x41c21cb8 , 0xe1000000 ) , U64 ( 0x36427987 , 0x50226111 ) ,
U64 ( 0x80000000 , 0x00000000 ) , U64 ( 0xa8b8b452 , 0x291fe821 ) ,
U64 ( 0x8ac72304 , 0x89e80000 ) , U64 ( 0x4d28cb56 , 0xc33fa539 ) ,
U64 ( 0x1eca170c , 0x00000000 ) , U64 ( 0x780c7372 , 0x621bd74d ) ,
U64 ( 0x1e39a505 , 0x7d810000 ) , U64 ( 0x5b27ac99 , 0x3df97701 ) ,
U64 ( 0x10000000 , 0x00000000 ) , U64 ( 0x27b95e99 , 0x7e21d9f1 ) ,
U64 ( 0x5da0e1e5 , 0x3c5c8000 ) , U64 ( 0xd2ae3299 , 0xc1c4aedb ) ,
U64 ( 0x16bcc41e , 0x90000000 ) , U64 ( 0x2d04b7fd , 0xd9c0ef49 ) ,
U64 ( 0x5658597b , 0xcaa24000 ) , U64 ( 0xa0e20737 , 0x37609371 ) ,
U64 ( 0x0c29e980 , 0x00000000 ) , U64 ( 0x14adf4b7 , 0x320334b9 ) ,
U64 ( 0x226ed364 , 0x78bfa000 ) , U64 ( 0x383d9170 , 0xb85ff80b ) ,
U64 ( 0x5a3c23e3 , 0x9c000000 ) , U64 ( 0x8e651373 , 0x88122bcd ) ,
U64 ( 0xdd41bb36 , 0xd259e000 ) , U64 ( 0x0aee5720 , 0xee830681 ) ,
U64 ( 0x10000000 , 0x00000000 ) , U64 ( 0x172588ad , 0x4f5f0981 ) ,
U64 ( 0x211e44f7 , 0xd02c1000 ) , U64 ( 0x2ee56725 , 0xf06e5c71 ) ,
U64 ( 0x41c21cb8 , 0xe1000000 ) ,
} ;
# endif
# ifdef HAVE_UINT128_T
2013-07-04 18:41:26 +04:00
static const int maxpow128_exp [ 35 ] = {
2013-07-04 15:23:46 +04:00
127 , 80 , 63 , 55 , 49 , 45 , 42 , 40 , 38 , 37 , 35 , 34 , 33 , 32 , 31 , 31 , 30 ,
30 , 29 , 29 , 28 , 28 , 27 , 27 , 27 , 26 , 26 , 26 , 26 , 25 , 25 , 25 , 25 , 24 ,
24 ,
} ;
2013-07-04 18:41:26 +04:00
static const uint128_t maxpow128_num [ 35 ] = {
2013-07-04 15:23:46 +04:00
U128 ( 0x80000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x6f32f1ef , 0x8b18a2bc , 0x3cea5978 , 0x9c79d441 ) ,
U128 ( 0x40000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0xd0cf4b50 , 0xcfe20765 , 0xfff4b4e3 , 0xf741cf6d ) ,
U128 ( 0x6558e2a0 , 0x921fe069 , 0x42860000 , 0x00000000 ) ,
U128 ( 0x5080c7b7 , 0xd0e31ba7 , 0x5911a67d , 0xdd3d35e7 ) ,
U128 ( 0x40000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x6f32f1ef , 0x8b18a2bc , 0x3cea5978 , 0x9c79d441 ) ,
U128 ( 0x4b3b4ca8 , 0x5a86c47a , 0x098a2240 , 0x00000000 ) ,
U128 ( 0xffd1390a , 0x0adc2fb8 , 0xdabbb817 , 0x4d95c99b ) ,
U128 ( 0x2c6fdb36 , 0x4c25e6c0 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x384bacd6 , 0x42c343b4 , 0xe90c4272 , 0x13506d29 ) ,
U128 ( 0x31f5db32 , 0xa34aced6 , 0x0bf13a0e , 0x00000000 ) ,
U128 ( 0x20753ada , 0xfd1e839f , 0x53686d01 , 0x3143ee01 ) ,
U128 ( 0x10000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x68ca11d6 , 0xb4f6d1d1 , 0xfaa82667 , 0x8073c2f1 ) ,
U128 ( 0x223e493b , 0xb3bb69ff , 0xa4b87d6c , 0x40000000 ) ,
U128 ( 0xad62418d , 0x14ea8247 , 0x01c4b488 , 0x6cc66f59 ) ,
U128 ( 0x2863c1f5 , 0xcdae42f9 , 0x54000000 , 0x00000000 ) ,
U128 ( 0xa63fd833 , 0xb9386b07 , 0x36039e82 , 0xbe651b25 ) ,
U128 ( 0x1d1f7a9c , 0xd087a14d , 0x28cdf3d5 , 0x10000000 ) ,
U128 ( 0x651b5095 , 0xc2ea8fc1 , 0xb30e2c57 , 0x77aaf7e1 ) ,
U128 ( 0x0ddef20e , 0xff760000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x29c30f10 , 0x29939b14 , 0x6664242d , 0x97d9f649 ) ,
U128 ( 0x786a435a , 0xe9558b0e , 0x6aaf6d63 , 0xa8000000 ) ,
U128 ( 0x0c5afe6f , 0xf302bcbf , 0x94fd9829 , 0xd87f5079 ) ,
U128 ( 0x1fce575c , 0xe1692706 , 0x07100000 , 0x00000000 ) ,
U128 ( 0x4f34497c , 0x8597e144 , 0x36e91802 , 0x00528229 ) ,
U128 ( 0xbf3a8e1d , 0x41ef2170 , 0x7802130d , 0x84000000 ) ,
U128 ( 0x0e7819e1 , 0x7f1eb0fb , 0x6ee4fb89 , 0x01d9531f ) ,
U128 ( 0x20000000 , 0x00000000 , 0x00000000 , 0x00000000 ) ,
U128 ( 0x4510460d , 0xd9e879c0 , 0x14a82375 , 0x2f22b321 ) ,
U128 ( 0x91abce3c , 0x4b4117ad , 0xe76d35db , 0x22000000 ) ,
U128 ( 0x08973ea3 , 0x55d75bc2 , 0x2e42c391 , 0x727d69e1 ) ,
U128 ( 0x10e425c5 , 0x6daffabc , 0x35c10000 , 0x00000000 ) ,
} ;
# endif
2013-07-02 15:52:13 +04:00
static BDIGIT_DBL
maxpow_in_bdigit_dbl ( int base , int * exp_ret )
{
BDIGIT_DBL maxpow ;
int exponent ;
2013-07-04 15:23:46 +04:00
assert ( 2 < = base & & base < = 36 ) ;
2013-07-10 09:58:45 +04:00
{
2013-07-15 06:26:24 +04:00
# if SIZEOF_BDIGIT_DBL == 2
2013-07-04 15:23:46 +04:00
maxpow = maxpow16_num [ base - 2 ] ;
exponent = maxpow16_exp [ base - 2 ] ;
2013-07-10 09:58:45 +04:00
# elif SIZEOF_BDIGIT_DBL == 4
2013-07-04 15:23:46 +04:00
maxpow = maxpow32_num [ base - 2 ] ;
exponent = maxpow32_exp [ base - 2 ] ;
2013-07-10 09:58:45 +04:00
# elif SIZEOF_BDIGIT_DBL == 8 && defined HAVE_UINT64_T
2013-07-04 15:23:46 +04:00
maxpow = maxpow64_num [ base - 2 ] ;
exponent = maxpow64_exp [ base - 2 ] ;
2013-07-10 09:58:45 +04:00
# elif SIZEOF_BDIGIT_DBL == 16 && defined HAVE_UINT128_T
2013-07-04 15:23:46 +04:00
maxpow = maxpow128_num [ base - 2 ] ;
exponent = maxpow128_exp [ base - 2 ] ;
2013-07-10 09:58:45 +04:00
# else
2013-07-04 15:23:46 +04:00
maxpow = base ;
exponent = 1 ;
while ( maxpow < = BDIGIT_DBL_MAX / base ) {
maxpow * = base ;
exponent + + ;
}
2013-07-10 09:58:45 +04:00
# endif
2013-07-02 15:52:13 +04:00
}
* exp_ret = exponent ;
return maxpow ;
}
2013-08-03 19:26:04 +04:00
static inline BDIGIT_DBL
bary2bdigitdbl ( const BDIGIT * ds , size_t n )
{
assert ( n < = 2 ) ;
if ( n = = 2 )
return ds [ 0 ] | BIGUP ( ds [ 1 ] ) ;
if ( n = = 1 )
return ds [ 0 ] ;
return 0 ;
}
static inline void
bdigitdbl2bary ( BDIGIT * ds , size_t n , BDIGIT_DBL num )
{
assert ( n = = 2 ) ;
ds [ 0 ] = BIGLO ( num ) ;
ds [ 1 ] = ( BDIGIT ) BIGDN ( num ) ;
}
2013-07-31 17:42:22 +04:00
static int
bary_cmp ( const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
{
2013-08-03 20:58:30 +04:00
BARY_TRUNC ( xds , xn ) ;
BARY_TRUNC ( yds , yn ) ;
2013-07-31 17:42:22 +04:00
if ( xn < yn )
return - 1 ;
if ( xn > yn )
return 1 ;
while ( xn - - & & xds [ xn ] = = yds [ xn ] )
;
if ( xn = = ( size_t ) - 1 )
return 0 ;
return xds [ xn ] < yds [ xn ] ? - 1 : 1 ;
}
2013-07-13 10:36:40 +04:00
static BDIGIT
2013-07-28 07:12:36 +04:00
bary_small_lshift ( BDIGIT * zds , const BDIGIT * xds , size_t n , int shift )
2013-07-13 10:36:40 +04:00
{
2013-07-13 10:53:12 +04:00
size_t i ;
2013-07-13 10:36:40 +04:00
BDIGIT_DBL num = 0 ;
2013-07-13 18:03:13 +04:00
assert ( 0 < = shift & & shift < BITSPERDIG ) ;
2013-07-13 10:36:40 +04:00
for ( i = 0 ; i < n ; i + + ) {
num = num | ( BDIGIT_DBL ) * xds + + < < shift ;
* zds + + = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
return BIGLO ( num ) ;
}
static void
2013-08-16 04:19:51 +04:00
bary_small_rshift ( BDIGIT * zds , const BDIGIT * xds , size_t n , int shift , BDIGIT higher_bdigit )
2013-07-13 10:36:40 +04:00
{
BDIGIT_DBL num = 0 ;
BDIGIT x ;
2013-07-13 18:03:13 +04:00
assert ( 0 < = shift & & shift < BITSPERDIG ) ;
2013-08-16 04:19:51 +04:00
num = BIGUP ( higher_bdigit ) ;
2013-07-13 10:36:40 +04:00
while ( n - - ) {
num = ( num | xds [ n ] ) > > shift ;
x = xds [ n ] ;
zds [ n ] = BIGLO ( num ) ;
num = BIGUP ( x ) ;
}
}
2013-07-03 07:08:52 +04:00
2008-02-22 13:50:21 +03:00
static int
2013-08-05 18:50:07 +04:00
bary_zero_p ( BDIGIT * xds , size_t xn )
2008-02-22 13:50:21 +03:00
{
2013-08-05 18:50:07 +04:00
if ( xn = = 0 )
2013-06-16 05:41:58 +04:00
return 1 ;
do {
2013-08-05 18:50:07 +04:00
if ( xds [ - - xn ] ) return 0 ;
} while ( xn ) ;
2008-02-22 13:50:21 +03:00
return 1 ;
}
2007-09-01 16:02:36 +04:00
2013-07-07 15:02:47 +04:00
static void
bary_neg ( BDIGIT * ds , size_t n )
{
while ( n - - )
ds [ n ] = BIGLO ( ~ ds [ n ] ) ;
}
2013-06-16 05:41:58 +04:00
static int
2013-07-10 17:06:33 +04:00
bary_2comp ( BDIGIT * ds , size_t n )
2013-06-16 05:41:58 +04:00
{
2013-07-07 15:02:47 +04:00
size_t i ;
2013-07-10 17:06:33 +04:00
i = 0 ;
2013-07-07 15:02:47 +04:00
for ( i = 0 ; i < n ; i + + ) {
2013-07-10 17:06:33 +04:00
if ( ds [ i ] ! = 0 ) {
goto non_zero ;
}
2013-07-07 15:02:47 +04:00
}
return 1 ;
2013-06-16 05:41:58 +04:00
2013-07-10 17:06:33 +04:00
non_zero :
ds [ i ] = BIGLO ( ~ ds [ i ] + 1 ) ;
i + + ;
for ( ; i < n ; i + + ) {
ds [ i ] = BIGLO ( ~ ds [ i ] ) ;
}
return 0 ;
2009-07-16 10:52:29 +04:00
}
2013-07-07 15:02:47 +04:00
static void
bary_swap ( BDIGIT * ds , size_t num_bdigits )
2008-04-06 21:11:50 +04:00
{
2013-07-07 15:02:47 +04:00
BDIGIT * p1 = ds ;
BDIGIT * p2 = ds + num_bdigits - 1 ;
for ( ; p1 < p2 ; p1 + + , p2 - - ) {
BDIGIT tmp = * p1 ;
* p1 = * p2 ;
* p2 = tmp ;
2008-04-06 21:11:50 +04:00
}
}
2013-07-07 15:02:47 +04:00
# define INTEGER_PACK_WORDORDER_MASK \
( INTEGER_PACK_MSWORD_FIRST | \
INTEGER_PACK_LSWORD_FIRST )
# define INTEGER_PACK_BYTEORDER_MASK \
( INTEGER_PACK_MSBYTE_FIRST | \
INTEGER_PACK_LSBYTE_FIRST | \
INTEGER_PACK_NATIVE_BYTE_ORDER )
2007-09-01 16:02:36 +04:00
static void
2013-07-07 15:02:47 +04:00
validate_integer_pack_format ( size_t numwords , size_t wordsize , size_t nails , int flags , int supported_flags )
2007-09-01 16:02:36 +04:00
{
2013-07-07 15:02:47 +04:00
int wordorder_bits = flags & INTEGER_PACK_WORDORDER_MASK ;
int byteorder_bits = flags & INTEGER_PACK_BYTEORDER_MASK ;
if ( flags & ~ supported_flags ) {
rb_raise ( rb_eArgError , " unsupported flags specified " ) ;
2007-09-01 16:02:36 +04:00
}
2013-07-07 15:02:47 +04:00
if ( wordorder_bits = = 0 ) {
if ( 1 < numwords )
rb_raise ( rb_eArgError , " word order not specified " ) ;
}
else if ( wordorder_bits ! = INTEGER_PACK_MSWORD_FIRST & &
wordorder_bits ! = INTEGER_PACK_LSWORD_FIRST )
rb_raise ( rb_eArgError , " unexpected word order " ) ;
if ( byteorder_bits = = 0 ) {
rb_raise ( rb_eArgError , " byte order not specified " ) ;
2007-09-01 16:02:36 +04:00
}
2013-07-07 15:02:47 +04:00
else if ( byteorder_bits ! = INTEGER_PACK_MSBYTE_FIRST & &
byteorder_bits ! = INTEGER_PACK_LSBYTE_FIRST & &
byteorder_bits ! = INTEGER_PACK_NATIVE_BYTE_ORDER )
rb_raise ( rb_eArgError , " unexpected byte order " ) ;
if ( wordsize = = 0 )
rb_raise ( rb_eArgError , " invalid wordsize: % " PRI_SIZE_PREFIX " u " , wordsize ) ;
if ( SSIZE_MAX < wordsize )
rb_raise ( rb_eArgError , " too big wordsize: % " PRI_SIZE_PREFIX " u " , wordsize ) ;
if ( wordsize < = nails / CHAR_BIT )
rb_raise ( rb_eArgError , " too big nails: % " PRI_SIZE_PREFIX " u " , nails ) ;
if ( SIZE_MAX / wordsize < numwords )
rb_raise ( rb_eArgError , " too big numwords * wordsize: % " PRI_SIZE_PREFIX " u * % " PRI_SIZE_PREFIX " u " , numwords , wordsize ) ;
2007-09-01 16:02:36 +04:00
}
2013-07-07 15:02:47 +04:00
static void
integer_pack_loop_setup (
size_t numwords , size_t wordsize , size_t nails , int flags ,
size_t * word_num_fullbytes_ret ,
int * word_num_partialbits_ret ,
size_t * word_start_ret ,
ssize_t * word_step_ret ,
size_t * word_last_ret ,
size_t * byte_start_ret ,
int * byte_step_ret )
2007-09-01 16:02:36 +04:00
{
2013-07-07 15:02:47 +04:00
int wordorder_bits = flags & INTEGER_PACK_WORDORDER_MASK ;
int byteorder_bits = flags & INTEGER_PACK_BYTEORDER_MASK ;
size_t word_num_fullbytes ;
int word_num_partialbits ;
size_t word_start ;
ssize_t word_step ;
size_t word_last ;
size_t byte_start ;
int byte_step ;
2003-04-09 10:44:34 +04:00
2013-07-07 15:02:47 +04:00
word_num_partialbits = CHAR_BIT - ( int ) ( nails % CHAR_BIT ) ;
if ( word_num_partialbits = = CHAR_BIT )
word_num_partialbits = 0 ;
word_num_fullbytes = wordsize - ( nails / CHAR_BIT ) ;
if ( word_num_partialbits ! = 0 ) {
word_num_fullbytes - - ;
}
if ( wordorder_bits = = INTEGER_PACK_MSWORD_FIRST ) {
word_start = wordsize * ( numwords - 1 ) ;
word_step = - ( ssize_t ) wordsize ;
word_last = 0 ;
2007-09-01 16:02:36 +04:00
}
else {
2013-07-07 15:02:47 +04:00
word_start = 0 ;
word_step = wordsize ;
word_last = wordsize * ( numwords - 1 ) ;
2007-09-01 16:02:36 +04:00
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
if ( byteorder_bits = = INTEGER_PACK_NATIVE_BYTE_ORDER ) {
# ifdef WORDS_BIGENDIAN
byteorder_bits = INTEGER_PACK_MSBYTE_FIRST ;
# else
byteorder_bits = INTEGER_PACK_LSBYTE_FIRST ;
# endif
}
if ( byteorder_bits = = INTEGER_PACK_MSBYTE_FIRST ) {
byte_start = wordsize - 1 ;
byte_step = - 1 ;
}
else {
byte_start = 0 ;
byte_step = 1 ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
* word_num_partialbits_ret = word_num_partialbits ;
* word_num_fullbytes_ret = word_num_fullbytes ;
* word_start_ret = word_start ;
* word_step_ret = word_step ;
* word_last_ret = word_last ;
* byte_start_ret = byte_start ;
* byte_step_ret = byte_step ;
2009-07-16 10:52:29 +04:00
}
2013-07-07 15:02:47 +04:00
static inline void
integer_pack_fill_dd ( BDIGIT * * dpp , BDIGIT * * dep , BDIGIT_DBL * ddp , int * numbits_in_dd_p )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
if ( * dpp < * dep & & BITSPERDIG < = ( int ) sizeof ( * ddp ) * CHAR_BIT - * numbits_in_dd_p ) {
* ddp | = ( BDIGIT_DBL ) ( * ( * dpp ) + + ) < < * numbits_in_dd_p ;
* numbits_in_dd_p + = BITSPERDIG ;
}
else if ( * dpp = = * dep ) {
/* higher bits are infinity zeros */
* numbits_in_dd_p = ( int ) sizeof ( * ddp ) * CHAR_BIT ;
}
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
static inline BDIGIT_DBL
integer_pack_take_lowbits ( int n , BDIGIT_DBL * ddp , int * numbits_in_dd_p )
{
BDIGIT_DBL ret ;
ret = ( * ddp ) & ( ( ( BDIGIT_DBL ) 1 < < n ) - 1 ) ;
* ddp > > = n ;
* numbits_in_dd_p - = n ;
return ret ;
1998-01-16 15:13:05 +03:00
}
2013-09-03 02:41:07 +04:00
# if !defined(WORDS_BIGENDIAN)
2013-06-22 18:28:50 +04:00
static int
bytes_2comp ( unsigned char * buf , size_t len )
{
size_t i ;
for ( i = 0 ; i < len ; i + + )
buf [ i ] = ~ buf [ i ] ;
for ( i = 0 ; i < len ; i + + ) {
buf [ i ] + + ;
if ( buf [ i ] ! = 0 )
return 0 ;
}
return 1 ;
}
2013-09-03 02:41:07 +04:00
# endif
2013-06-22 18:28:50 +04:00
2013-07-07 15:02:47 +04:00
static int
bary_pack ( int sign , BDIGIT * ds , size_t num_bdigits , void * words , size_t numwords , size_t wordsize , size_t nails , int flags )
2013-06-29 18:38:26 +04:00
{
2013-07-07 15:02:47 +04:00
BDIGIT * dp , * de ;
unsigned char * buf , * bufend ;
2013-06-29 18:38:26 +04:00
2013-07-07 15:02:47 +04:00
dp = ds ;
de = ds + num_bdigits ;
validate_integer_pack_format ( numwords , wordsize , nails , flags ,
INTEGER_PACK_MSWORD_FIRST |
INTEGER_PACK_LSWORD_FIRST |
INTEGER_PACK_MSBYTE_FIRST |
INTEGER_PACK_LSBYTE_FIRST |
INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP |
INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ) ;
while ( dp < de & & de [ - 1 ] = = 0 )
de - - ;
if ( dp = = de ) {
sign = 0 ;
}
if ( ! ( flags & INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ) ) {
if ( sign = = 0 ) {
MEMZERO ( words , unsigned char , numwords * wordsize ) ;
2013-06-29 17:33:40 +04:00
return 0 ;
2013-07-07 15:02:47 +04:00
}
if ( nails = = 0 & & numwords = = 1 ) {
int need_swap = wordsize ! = 1 & &
( flags & INTEGER_PACK_BYTEORDER_MASK ) ! = INTEGER_PACK_NATIVE_BYTE_ORDER & &
( ( flags & INTEGER_PACK_MSBYTE_FIRST ) ? ! HOST_BIGENDIAN_P : HOST_BIGENDIAN_P ) ;
if ( 0 < sign | | ! ( flags & INTEGER_PACK_2COMP ) ) {
BDIGIT d ;
if ( wordsize = = 1 ) {
* ( ( unsigned char * ) words ) = ( unsigned char ) ( d = dp [ 0 ] ) ;
return ( ( 1 < de - dp | | CLEAR_LOWBITS ( d , 8 ) ! = 0 ) ? 2 : 1 ) * sign ;
}
# if defined(HAVE_UINT16_T) && 2 <= SIZEOF_BDIGITS
if ( wordsize = = 2 & & ( uintptr_t ) words % ALIGNOF ( uint16_t ) = = 0 ) {
uint16_t u = ( uint16_t ) ( d = dp [ 0 ] ) ;
if ( need_swap ) u = swap16 ( u ) ;
* ( ( uint16_t * ) words ) = u ;
return ( ( 1 < de - dp | | CLEAR_LOWBITS ( d , 16 ) ! = 0 ) ? 2 : 1 ) * sign ;
}
# endif
# if defined(HAVE_UINT32_T) && 4 <= SIZEOF_BDIGITS
if ( wordsize = = 4 & & ( uintptr_t ) words % ALIGNOF ( uint32_t ) = = 0 ) {
uint32_t u = ( uint32_t ) ( d = dp [ 0 ] ) ;
if ( need_swap ) u = swap32 ( u ) ;
* ( ( uint32_t * ) words ) = u ;
return ( ( 1 < de - dp | | CLEAR_LOWBITS ( d , 32 ) ! = 0 ) ? 2 : 1 ) * sign ;
}
# endif
# if defined(HAVE_UINT64_T) && 8 <= SIZEOF_BDIGITS
if ( wordsize = = 8 & & ( uintptr_t ) words % ALIGNOF ( uint64_t ) = = 0 ) {
uint64_t u = ( uint64_t ) ( d = dp [ 0 ] ) ;
if ( need_swap ) u = swap64 ( u ) ;
* ( ( uint64_t * ) words ) = u ;
return ( ( 1 < de - dp | | CLEAR_LOWBITS ( d , 64 ) ! = 0 ) ? 2 : 1 ) * sign ;
}
# endif
}
else { /* sign < 0 && (flags & INTEGER_PACK_2COMP) */
BDIGIT_DBL_SIGNED d ;
if ( wordsize = = 1 ) {
* ( ( unsigned char * ) words ) = ( unsigned char ) ( d = - ( BDIGIT_DBL_SIGNED ) dp [ 0 ] ) ;
return ( 1 < de - dp | | FILL_LOWBITS ( d , 8 ) ! = - 1 ) ? - 2 : - 1 ;
}
# if defined(HAVE_UINT16_T) && 2 <= SIZEOF_BDIGITS
if ( wordsize = = 2 & & ( uintptr_t ) words % ALIGNOF ( uint16_t ) = = 0 ) {
uint16_t u = ( uint16_t ) ( d = - ( BDIGIT_DBL_SIGNED ) dp [ 0 ] ) ;
if ( need_swap ) u = swap16 ( u ) ;
* ( ( uint16_t * ) words ) = u ;
return ( wordsize = = SIZEOF_BDIGITS & & de - dp = = 2 & & dp [ 1 ] = = 1 & & dp [ 0 ] = = 0 ) ? - 1 :
( 1 < de - dp | | FILL_LOWBITS ( d , 16 ) ! = - 1 ) ? - 2 : - 1 ;
}
# endif
# if defined(HAVE_UINT32_T) && 4 <= SIZEOF_BDIGITS
if ( wordsize = = 4 & & ( uintptr_t ) words % ALIGNOF ( uint32_t ) = = 0 ) {
uint32_t u = ( uint32_t ) ( d = - ( BDIGIT_DBL_SIGNED ) dp [ 0 ] ) ;
if ( need_swap ) u = swap32 ( u ) ;
* ( ( uint32_t * ) words ) = u ;
return ( wordsize = = SIZEOF_BDIGITS & & de - dp = = 2 & & dp [ 1 ] = = 1 & & dp [ 0 ] = = 0 ) ? - 1 :
( 1 < de - dp | | FILL_LOWBITS ( d , 32 ) ! = - 1 ) ? - 2 : - 1 ;
}
# endif
# if defined(HAVE_UINT64_T) && 8 <= SIZEOF_BDIGITS
if ( wordsize = = 8 & & ( uintptr_t ) words % ALIGNOF ( uint64_t ) = = 0 ) {
uint64_t u = ( uint64_t ) ( d = - ( BDIGIT_DBL_SIGNED ) dp [ 0 ] ) ;
if ( need_swap ) u = swap64 ( u ) ;
* ( ( uint64_t * ) words ) = u ;
return ( wordsize = = SIZEOF_BDIGITS & & de - dp = = 2 & & dp [ 1 ] = = 1 & & dp [ 0 ] = = 0 ) ? - 1 :
( 1 < de - dp | | FILL_LOWBITS ( d , 64 ) ! = - 1 ) ? - 2 : - 1 ;
}
# endif
}
}
# if !defined(WORDS_BIGENDIAN)
if ( nails = = 0 & & SIZEOF_BDIGITS = = sizeof ( BDIGIT ) & &
( flags & INTEGER_PACK_WORDORDER_MASK ) = = INTEGER_PACK_LSWORD_FIRST & &
( flags & INTEGER_PACK_BYTEORDER_MASK ) ! = INTEGER_PACK_MSBYTE_FIRST ) {
size_t src_size = ( de - dp ) * SIZEOF_BDIGITS ;
size_t dst_size = numwords * wordsize ;
int overflow = 0 ;
while ( 0 < src_size & & ( ( unsigned char * ) ds ) [ src_size - 1 ] = = 0 )
src_size - - ;
if ( src_size < = dst_size ) {
MEMCPY ( words , dp , char , src_size ) ;
MEMZERO ( ( char * ) words + src_size , char , dst_size - src_size ) ;
}
else {
MEMCPY ( words , dp , char , dst_size ) ;
overflow = 1 ;
}
if ( sign < 0 & & ( flags & INTEGER_PACK_2COMP ) ) {
int zero_p = bytes_2comp ( words , dst_size ) ;
if ( zero_p & & overflow ) {
unsigned char * p = ( unsigned char * ) dp ;
if ( dst_size = = src_size - 1 & &
p [ dst_size ] = = 1 ) {
overflow = 0 ;
}
}
}
if ( overflow )
sign * = 2 ;
return sign ;
}
# endif
if ( nails = = 0 & & SIZEOF_BDIGITS = = sizeof ( BDIGIT ) & &
wordsize % SIZEOF_BDIGITS = = 0 & & ( uintptr_t ) words % ALIGNOF ( BDIGIT ) = = 0 ) {
size_t bdigits_per_word = wordsize / SIZEOF_BDIGITS ;
size_t src_num_bdigits = de - dp ;
size_t dst_num_bdigits = numwords * bdigits_per_word ;
int overflow = 0 ;
int mswordfirst_p = ( flags & INTEGER_PACK_MSWORD_FIRST ) ! = 0 ;
int msbytefirst_p = ( flags & INTEGER_PACK_NATIVE_BYTE_ORDER ) ? HOST_BIGENDIAN_P :
( flags & INTEGER_PACK_MSBYTE_FIRST ) ! = 0 ;
if ( src_num_bdigits < = dst_num_bdigits ) {
MEMCPY ( words , dp , BDIGIT , src_num_bdigits ) ;
2013-07-18 08:00:49 +04:00
BDIGITS_ZERO ( ( BDIGIT * ) words + src_num_bdigits , dst_num_bdigits - src_num_bdigits ) ;
2013-07-07 15:02:47 +04:00
}
else {
MEMCPY ( words , dp , BDIGIT , dst_num_bdigits ) ;
overflow = 1 ;
}
if ( sign < 0 & & ( flags & INTEGER_PACK_2COMP ) ) {
int zero_p = bary_2comp ( words , dst_num_bdigits ) ;
if ( zero_p & & overflow & &
dst_num_bdigits = = src_num_bdigits - 1 & &
dp [ dst_num_bdigits ] = = 1 )
overflow = 0 ;
}
if ( msbytefirst_p ! = HOST_BIGENDIAN_P ) {
size_t i ;
for ( i = 0 ; i < dst_num_bdigits ; i + + ) {
BDIGIT d = ( ( BDIGIT * ) words ) [ i ] ;
( ( BDIGIT * ) words ) [ i ] = swap_bdigit ( d ) ;
}
}
2013-07-15 16:56:29 +04:00
if ( mswordfirst_p ? ! msbytefirst_p : msbytefirst_p ) {
2013-07-07 15:02:47 +04:00
size_t i ;
BDIGIT * p = words ;
for ( i = 0 ; i < numwords ; i + + ) {
bary_swap ( p , bdigits_per_word ) ;
p + = bdigits_per_word ;
}
}
if ( mswordfirst_p ) {
bary_swap ( words , dst_num_bdigits ) ;
}
if ( overflow )
sign * = 2 ;
return sign ;
}
2013-06-29 17:33:40 +04:00
}
2013-06-16 16:59:26 +04:00
2013-07-07 15:02:47 +04:00
buf = words ;
bufend = buf + numwords * wordsize ;
2013-06-29 18:38:26 +04:00
2013-07-07 15:02:47 +04:00
if ( buf = = bufend ) {
/* overflow if non-zero*/
if ( ! ( flags & INTEGER_PACK_2COMP ) | | 0 < = sign )
sign * = 2 ;
else {
if ( de - dp = = 1 & & dp [ 0 ] = = 1 )
sign = - 1 ; /* val == -1 == -2**(numwords*(wordsize*CHAR_BIT-nails)) */
else
sign = - 2 ; /* val < -1 == -2**(numwords*(wordsize*CHAR_BIT-nails)) */
}
}
else if ( dp = = de ) {
memset ( buf , ' \0 ' , bufend - buf ) ;
}
else if ( dp < de & & buf < bufend ) {
int word_num_partialbits ;
size_t word_num_fullbytes ;
2013-06-29 18:38:26 +04:00
2013-07-07 15:02:47 +04:00
ssize_t word_step ;
size_t byte_start ;
int byte_step ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
size_t word_start , word_last ;
unsigned char * wordp , * last_wordp ;
BDIGIT_DBL dd ;
int numbits_in_dd ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
integer_pack_loop_setup ( numwords , wordsize , nails , flags ,
& word_num_fullbytes , & word_num_partialbits ,
& word_start , & word_step , & word_last , & byte_start , & byte_step ) ;
2002-02-22 13:28:47 +03:00
2013-07-07 15:02:47 +04:00
wordp = buf + word_start ;
last_wordp = buf + word_last ;
2013-06-27 17:54:02 +04:00
2013-07-07 15:02:47 +04:00
dd = 0 ;
numbits_in_dd = 0 ;
2013-06-27 17:54:02 +04:00
2013-07-07 15:02:47 +04:00
# define FILL_DD \
integer_pack_fill_dd ( & dp , & de , & dd , & numbits_in_dd )
# define TAKE_LOWBITS(n) \
integer_pack_take_lowbits ( n , & dd , & numbits_in_dd )
2013-06-27 17:54:02 +04:00
2013-07-07 15:02:47 +04:00
while ( 1 ) {
size_t index_in_word = 0 ;
unsigned char * bytep = wordp + byte_start ;
while ( index_in_word < word_num_fullbytes ) {
FILL_DD ;
* bytep = TAKE_LOWBITS ( CHAR_BIT ) ;
bytep + = byte_step ;
index_in_word + + ;
}
if ( word_num_partialbits ) {
FILL_DD ;
* bytep = TAKE_LOWBITS ( word_num_partialbits ) ;
bytep + = byte_step ;
index_in_word + + ;
}
while ( index_in_word < wordsize ) {
* bytep = 0 ;
bytep + = byte_step ;
index_in_word + + ;
}
if ( wordp = = last_wordp )
break ;
wordp + = word_step ;
}
FILL_DD ;
/* overflow tests */
if ( dp ! = de | | 1 < dd ) {
/* 2**(numwords*(wordsize*CHAR_BIT-nails)+1) <= abs(val) */
sign * = 2 ;
}
else if ( dd = = 1 ) {
/* 2**(numwords*(wordsize*CHAR_BIT-nails)) <= abs(val) < 2**(numwords*(wordsize*CHAR_BIT-nails)+1) */
if ( ! ( flags & INTEGER_PACK_2COMP ) | | 0 < = sign )
sign * = 2 ;
else { /* overflow_2comp && sign == -1 */
/* test lower bits are all zero. */
dp = ds ;
while ( dp < de & & * dp = = 0 )
dp + + ;
if ( de - dp = = 1 & & /* only one non-zero word. */
POW2_P ( * dp ) ) /* *dp contains only one bit set. */
sign = - 1 ; /* val == -2**(numwords*(wordsize*CHAR_BIT-nails)) */
else
sign = - 2 ; /* val < -2**(numwords*(wordsize*CHAR_BIT-nails)) */
}
}
2013-06-27 17:54:02 +04:00
}
2013-07-07 15:02:47 +04:00
if ( ( flags & INTEGER_PACK_2COMP ) & & ( sign < 0 & & numwords ! = 0 ) ) {
unsigned char * buf ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
int word_num_partialbits ;
size_t word_num_fullbytes ;
2007-04-26 19:02:57 +04:00
2013-07-07 15:02:47 +04:00
ssize_t word_step ;
size_t byte_start ;
int byte_step ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
size_t word_start , word_last ;
unsigned char * wordp , * last_wordp ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
unsigned int partialbits_mask ;
int carry ;
2007-04-26 19:02:57 +04:00
2013-07-07 15:02:47 +04:00
integer_pack_loop_setup ( numwords , wordsize , nails , flags ,
& word_num_fullbytes , & word_num_partialbits ,
& word_start , & word_step , & word_last , & byte_start , & byte_step ) ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
partialbits_mask = ( 1 < < word_num_partialbits ) - 1 ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
buf = words ;
wordp = buf + word_start ;
last_wordp = buf + word_last ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
carry = 1 ;
while ( 1 ) {
size_t index_in_word = 0 ;
unsigned char * bytep = wordp + byte_start ;
while ( index_in_word < word_num_fullbytes ) {
carry + = ( unsigned char ) ~ * bytep ;
* bytep = ( unsigned char ) carry ;
carry > > = CHAR_BIT ;
bytep + = byte_step ;
index_in_word + + ;
}
if ( word_num_partialbits ) {
carry + = ( * bytep & partialbits_mask ) ^ partialbits_mask ;
* bytep = carry & partialbits_mask ;
carry > > = word_num_partialbits ;
bytep + = byte_step ;
index_in_word + + ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
if ( wordp = = last_wordp )
break ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
wordp + = word_step ;
}
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
return sign ;
# undef FILL_DD
# undef TAKE_LOWBITS
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
static size_t
integer_unpack_num_bdigits_small ( size_t numwords , size_t wordsize , size_t nails , int * nlp_bits_ret )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
/* nlp_bits stands for number of leading padding bits */
size_t num_bits = ( wordsize * CHAR_BIT - nails ) * numwords ;
size_t num_bdigits = ( num_bits + BITSPERDIG - 1 ) / BITSPERDIG ;
* nlp_bits_ret = ( int ) ( num_bdigits * BITSPERDIG - num_bits ) ;
return num_bdigits ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
static size_t
integer_unpack_num_bdigits_generic ( size_t numwords , size_t wordsize , size_t nails , int * nlp_bits_ret )
2013-06-19 16:19:10 +04:00
{
2013-07-07 15:02:47 +04:00
/* BITSPERDIG = SIZEOF_BDIGITS * CHAR_BIT */
/* num_bits = (wordsize * CHAR_BIT - nails) * numwords */
/* num_bdigits = (num_bits + BITSPERDIG - 1) / BITSPERDIG */
2013-06-19 16:19:10 +04:00
2013-07-07 15:02:47 +04:00
/* num_bits = CHAR_BIT * (wordsize * numwords) - nails * numwords = CHAR_BIT * num_bytes1 - nails * numwords */
size_t num_bytes1 = wordsize * numwords ;
2010-02-26 21:51:02 +03:00
2013-07-07 15:02:47 +04:00
/* q1 * CHAR_BIT + r1 = numwords */
size_t q1 = numwords / CHAR_BIT ;
size_t r1 = numwords % CHAR_BIT ;
2013-06-07 13:25:47 +04:00
2013-07-07 15:02:47 +04:00
/* num_bits = CHAR_BIT * num_bytes1 - nails * (q1 * CHAR_BIT + r1) = CHAR_BIT * num_bytes2 - nails * r1 */
size_t num_bytes2 = num_bytes1 - nails * q1 ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
/* q2 * CHAR_BIT + r2 = nails */
size_t q2 = nails / CHAR_BIT ;
size_t r2 = nails % CHAR_BIT ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
/* num_bits = CHAR_BIT * num_bytes2 - (q2 * CHAR_BIT + r2) * r1 = CHAR_BIT * num_bytes3 - r1 * r2 */
size_t num_bytes3 = num_bytes2 - q2 * r1 ;
/* q3 * BITSPERDIG + r3 = num_bytes3 */
size_t q3 = num_bytes3 / BITSPERDIG ;
size_t r3 = num_bytes3 % BITSPERDIG ;
/* num_bits = CHAR_BIT * (q3 * BITSPERDIG + r3) - r1 * r2 = BITSPERDIG * num_digits1 + CHAR_BIT * r3 - r1 * r2 */
size_t num_digits1 = CHAR_BIT * q3 ;
/*
* if CHAR_BIT * r3 > = r1 * r2
* CHAR_BIT * r3 - r1 * r2 = CHAR_BIT * BITSPERDIG - ( CHAR_BIT * BITSPERDIG - ( CHAR_BIT * r3 - r1 * r2 ) )
* q4 * BITSPERDIG + r4 = CHAR_BIT * BITSPERDIG - ( CHAR_BIT * r3 - r1 * r2 )
* num_bits = BITSPERDIG * num_digits1 + CHAR_BIT * BITSPERDIG - ( q4 * BITSPERDIG + r4 ) = BITSPERDIG * num_digits2 - r4
* else
* q4 * BITSPERDIG + r4 = - ( CHAR_BIT * r3 - r1 * r2 )
* num_bits = BITSPERDIG * num_digits1 - ( q4 * BITSPERDIG + r4 ) = BITSPERDIG * num_digits2 - r4
* end
*/
if ( CHAR_BIT * r3 > = r1 * r2 ) {
size_t tmp1 = CHAR_BIT * BITSPERDIG - ( CHAR_BIT * r3 - r1 * r2 ) ;
size_t q4 = tmp1 / BITSPERDIG ;
int r4 = ( int ) ( tmp1 % BITSPERDIG ) ;
size_t num_digits2 = num_digits1 + CHAR_BIT - q4 ;
* nlp_bits_ret = r4 ;
return num_digits2 ;
}
else {
size_t tmp1 = r1 * r2 - CHAR_BIT * r3 ;
size_t q4 = tmp1 / BITSPERDIG ;
int r4 = ( int ) ( tmp1 % BITSPERDIG ) ;
size_t num_digits2 = num_digits1 - q4 ;
* nlp_bits_ret = r4 ;
return num_digits2 ;
}
}
static size_t
integer_unpack_num_bdigits ( size_t numwords , size_t wordsize , size_t nails , int * nlp_bits_ret )
{
size_t num_bdigits ;
if ( numwords < = ( SIZE_MAX - ( BITSPERDIG - 1 ) ) / CHAR_BIT / wordsize ) {
num_bdigits = integer_unpack_num_bdigits_small ( numwords , wordsize , nails , nlp_bits_ret ) ;
# ifdef DEBUG_INTEGER_PACK
2013-06-07 13:25:47 +04:00
{
2013-07-07 15:02:47 +04:00
int nlp_bits1 ;
size_t num_bdigits1 = integer_unpack_num_bdigits_generic ( numwords , wordsize , nails , & nlp_bits1 ) ;
assert ( num_bdigits = = num_bdigits1 ) ;
assert ( * nlp_bits_ret = = nlp_bits1 ) ;
2013-06-06 15:57:35 +04:00
}
# endif
}
else {
2013-07-07 15:02:47 +04:00
num_bdigits = integer_unpack_num_bdigits_generic ( numwords , wordsize , nails , nlp_bits_ret ) ;
2013-06-06 15:57:35 +04:00
}
2013-07-07 15:02:47 +04:00
return num_bdigits ;
2013-06-06 15:57:35 +04:00
}
2013-07-07 15:02:47 +04:00
static inline void
integer_unpack_push_bits ( int data , int numbits , BDIGIT_DBL * ddp , int * numbits_in_dd_p , BDIGIT * * dpp )
2013-06-10 00:39:05 +04:00
{
2013-07-07 15:02:47 +04:00
( * ddp ) | = ( ( BDIGIT_DBL ) data ) < < ( * numbits_in_dd_p ) ;
* numbits_in_dd_p + = numbits ;
while ( BITSPERDIG < = * numbits_in_dd_p ) {
* ( * dpp ) + + = BIGLO ( * ddp ) ;
* ddp = BIGDN ( * ddp ) ;
* numbits_in_dd_p - = BITSPERDIG ;
}
2013-06-10 00:39:05 +04:00
}
2013-07-07 15:02:47 +04:00
static int
integer_unpack_single_bdigit ( BDIGIT u , size_t size , int flags , BDIGIT * dp )
2013-06-09 20:08:54 +04:00
{
2013-06-16 12:49:26 +04:00
int sign ;
2013-07-07 15:02:47 +04:00
if ( flags & INTEGER_PACK_2COMP ) {
sign = ( flags & INTEGER_PACK_NEGATIVE ) ?
( ( size = = SIZEOF_BDIGITS & & u = = 0 ) ? - 2 : - 1 ) :
( ( u > > ( size * CHAR_BIT - 1 ) ) ? - 1 : 1 ) ;
if ( sign < 0 ) {
u | = LSHIFTX ( BDIGMAX , size * CHAR_BIT ) ;
u = BIGLO ( 1 + ~ u ) ;
}
2013-06-16 05:41:58 +04:00
}
2013-07-07 15:02:47 +04:00
else
sign = ( flags & INTEGER_PACK_NEGATIVE ) ? - 1 : 1 ;
* dp = u ;
return sign ;
2013-06-09 20:08:54 +04:00
}
2013-07-07 15:02:47 +04:00
static int
bary_unpack_internal ( BDIGIT * bdigits , size_t num_bdigits , const void * words , size_t numwords , size_t wordsize , size_t nails , int flags , int nlp_bits )
2013-06-09 20:08:54 +04:00
{
2013-07-07 15:02:47 +04:00
int sign ;
const unsigned char * buf = words ;
BDIGIT * dp ;
BDIGIT * de ;
2013-06-09 20:08:54 +04:00
2013-07-07 15:02:47 +04:00
dp = bdigits ;
de = dp + num_bdigits ;
2013-06-09 20:08:54 +04:00
2013-07-07 15:02:47 +04:00
if ( ! ( flags & INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ) ) {
if ( nails = = 0 & & numwords = = 1 ) {
int need_swap = wordsize ! = 1 & &
( flags & INTEGER_PACK_BYTEORDER_MASK ) ! = INTEGER_PACK_NATIVE_BYTE_ORDER & &
( ( flags & INTEGER_PACK_MSBYTE_FIRST ) ? ! HOST_BIGENDIAN_P : HOST_BIGENDIAN_P ) ;
if ( wordsize = = 1 ) {
return integer_unpack_single_bdigit ( * ( uint8_t * ) buf , sizeof ( uint8_t ) , flags , dp ) ;
}
# if defined(HAVE_UINT16_T) && 2 <= SIZEOF_BDIGITS
if ( wordsize = = 2 & & ( uintptr_t ) words % ALIGNOF ( uint16_t ) = = 0 ) {
2013-07-14 18:28:33 +04:00
uint16_t u = * ( uint16_t * ) buf ;
2013-07-07 15:02:47 +04:00
return integer_unpack_single_bdigit ( need_swap ? swap16 ( u ) : u , sizeof ( uint16_t ) , flags , dp ) ;
}
# endif
# if defined(HAVE_UINT32_T) && 4 <= SIZEOF_BDIGITS
if ( wordsize = = 4 & & ( uintptr_t ) words % ALIGNOF ( uint32_t ) = = 0 ) {
2013-07-14 18:28:33 +04:00
uint32_t u = * ( uint32_t * ) buf ;
2013-07-07 15:02:47 +04:00
return integer_unpack_single_bdigit ( need_swap ? swap32 ( u ) : u , sizeof ( uint32_t ) , flags , dp ) ;
}
# endif
# if defined(HAVE_UINT64_T) && 8 <= SIZEOF_BDIGITS
if ( wordsize = = 8 & & ( uintptr_t ) words % ALIGNOF ( uint64_t ) = = 0 ) {
2013-07-14 18:28:33 +04:00
uint64_t u = * ( uint64_t * ) buf ;
2013-07-07 15:02:47 +04:00
return integer_unpack_single_bdigit ( need_swap ? swap64 ( u ) : u , sizeof ( uint64_t ) , flags , dp ) ;
}
# endif
}
# if !defined(WORDS_BIGENDIAN)
if ( nails = = 0 & & SIZEOF_BDIGITS = = sizeof ( BDIGIT ) & &
( flags & INTEGER_PACK_WORDORDER_MASK ) = = INTEGER_PACK_LSWORD_FIRST & &
( flags & INTEGER_PACK_BYTEORDER_MASK ) ! = INTEGER_PACK_MSBYTE_FIRST ) {
size_t src_size = numwords * wordsize ;
size_t dst_size = num_bdigits * SIZEOF_BDIGITS ;
MEMCPY ( dp , words , char , src_size ) ;
if ( flags & INTEGER_PACK_2COMP ) {
if ( flags & INTEGER_PACK_NEGATIVE ) {
int zero_p ;
memset ( ( char * ) dp + src_size , 0xff , dst_size - src_size ) ;
zero_p = bary_2comp ( dp , num_bdigits ) ;
sign = zero_p ? - 2 : - 1 ;
}
else if ( buf [ src_size - 1 ] > > ( CHAR_BIT - 1 ) ) {
memset ( ( char * ) dp + src_size , 0xff , dst_size - src_size ) ;
bary_2comp ( dp , num_bdigits ) ;
sign = - 1 ;
}
else {
MEMZERO ( ( char * ) dp + src_size , char , dst_size - src_size ) ;
sign = 1 ;
}
}
else {
MEMZERO ( ( char * ) dp + src_size , char , dst_size - src_size ) ;
sign = ( flags & INTEGER_PACK_NEGATIVE ) ? - 1 : 1 ;
}
return sign ;
}
# endif
if ( nails = = 0 & & SIZEOF_BDIGITS = = sizeof ( BDIGIT ) & &
wordsize % SIZEOF_BDIGITS = = 0 ) {
size_t bdigits_per_word = wordsize / SIZEOF_BDIGITS ;
int mswordfirst_p = ( flags & INTEGER_PACK_MSWORD_FIRST ) ! = 0 ;
int msbytefirst_p = ( flags & INTEGER_PACK_NATIVE_BYTE_ORDER ) ? HOST_BIGENDIAN_P :
( flags & INTEGER_PACK_MSBYTE_FIRST ) ! = 0 ;
MEMCPY ( dp , words , BDIGIT , numwords * bdigits_per_word ) ;
if ( mswordfirst_p ) {
bary_swap ( dp , num_bdigits ) ;
}
if ( mswordfirst_p ? ! msbytefirst_p : msbytefirst_p ) {
size_t i ;
BDIGIT * p = dp ;
for ( i = 0 ; i < numwords ; i + + ) {
bary_swap ( p , bdigits_per_word ) ;
p + = bdigits_per_word ;
}
}
if ( msbytefirst_p ! = HOST_BIGENDIAN_P ) {
BDIGIT * p ;
for ( p = dp ; p < de ; p + + ) {
BDIGIT d = * p ;
* p = swap_bdigit ( d ) ;
}
}
if ( flags & INTEGER_PACK_2COMP ) {
if ( flags & INTEGER_PACK_NEGATIVE ) {
int zero_p = bary_2comp ( dp , num_bdigits ) ;
sign = zero_p ? - 2 : - 1 ;
}
else if ( BDIGIT_MSB ( de [ - 1 ] ) ) {
bary_2comp ( dp , num_bdigits ) ;
sign = - 1 ;
}
else {
sign = 1 ;
}
}
else {
sign = ( flags & INTEGER_PACK_NEGATIVE ) ? - 1 : 1 ;
}
return sign ;
2013-06-13 07:20:28 +04:00
}
2013-06-09 20:08:54 +04:00
}
2013-07-07 15:02:47 +04:00
if ( num_bdigits ! = 0 ) {
int word_num_partialbits ;
size_t word_num_fullbytes ;
2013-06-09 20:08:54 +04:00
2013-07-07 15:02:47 +04:00
ssize_t word_step ;
size_t byte_start ;
int byte_step ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
size_t word_start , word_last ;
const unsigned char * wordp , * last_wordp ;
BDIGIT_DBL dd ;
int numbits_in_dd ;
2013-06-08 16:05:57 +04:00
2013-07-07 15:02:47 +04:00
integer_pack_loop_setup ( numwords , wordsize , nails , flags ,
& word_num_fullbytes , & word_num_partialbits ,
& word_start , & word_step , & word_last , & byte_start , & byte_step ) ;
2013-06-08 16:05:57 +04:00
2013-07-07 15:02:47 +04:00
wordp = buf + word_start ;
last_wordp = buf + word_last ;
dd = 0 ;
numbits_in_dd = 0 ;
# define PUSH_BITS(data, numbits) \
integer_unpack_push_bits ( data , numbits , & dd , & numbits_in_dd , & dp )
while ( 1 ) {
size_t index_in_word = 0 ;
const unsigned char * bytep = wordp + byte_start ;
while ( index_in_word < word_num_fullbytes ) {
PUSH_BITS ( * bytep , CHAR_BIT ) ;
bytep + = byte_step ;
index_in_word + + ;
}
if ( word_num_partialbits ) {
PUSH_BITS ( * bytep & ( ( 1 < < word_num_partialbits ) - 1 ) , word_num_partialbits ) ;
bytep + = byte_step ;
index_in_word + + ;
2013-06-08 16:05:57 +04:00
}
2013-07-07 15:02:47 +04:00
if ( wordp = = last_wordp )
break ;
wordp + = word_step ;
2013-06-08 16:05:57 +04:00
}
2013-07-07 15:02:47 +04:00
if ( dd )
* dp + + = ( BDIGIT ) dd ;
assert ( dp < = de ) ;
while ( dp < de )
* dp + + = 0 ;
# undef PUSH_BITS
}
if ( ! ( flags & INTEGER_PACK_2COMP ) ) {
sign = ( flags & INTEGER_PACK_NEGATIVE ) ? - 1 : 1 ;
2013-06-08 16:05:57 +04:00
}
else {
2013-07-07 15:02:47 +04:00
if ( nlp_bits ) {
if ( ( flags & INTEGER_PACK_NEGATIVE ) | |
( bdigits [ num_bdigits - 1 ] > > ( BITSPERDIG - nlp_bits - 1 ) ) ) {
bdigits [ num_bdigits - 1 ] | = BIGLO ( BDIGMAX < < ( BITSPERDIG - nlp_bits ) ) ;
sign = - 1 ;
}
else {
sign = 1 ;
}
}
else {
if ( flags & INTEGER_PACK_NEGATIVE ) {
sign = bary_zero_p ( bdigits , num_bdigits ) ? - 2 : - 1 ;
}
else {
if ( num_bdigits ! = 0 & & BDIGIT_MSB ( bdigits [ num_bdigits - 1 ] ) )
sign = - 1 ;
else
sign = 1 ;
}
}
if ( sign = = - 1 & & num_bdigits ! = 0 ) {
bary_2comp ( bdigits , num_bdigits ) ;
}
2013-06-08 16:05:57 +04:00
}
2013-07-07 15:02:47 +04:00
return sign ;
2013-06-08 16:05:57 +04:00
}
2013-06-22 18:51:48 +04:00
static void
2013-07-07 15:02:47 +04:00
bary_unpack ( BDIGIT * bdigits , size_t num_bdigits , const void * words , size_t numwords , size_t wordsize , size_t nails , int flags )
2013-06-22 18:51:48 +04:00
{
2013-07-07 15:02:47 +04:00
size_t num_bdigits0 ;
int nlp_bits ;
int sign ;
2013-06-22 18:51:48 +04:00
2013-07-07 15:02:47 +04:00
validate_integer_pack_format ( numwords , wordsize , nails , flags ,
INTEGER_PACK_MSWORD_FIRST |
INTEGER_PACK_LSWORD_FIRST |
INTEGER_PACK_MSBYTE_FIRST |
INTEGER_PACK_LSBYTE_FIRST |
INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP |
INTEGER_PACK_FORCE_BIGNUM |
INTEGER_PACK_NEGATIVE |
INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ) ;
2013-06-07 19:02:39 +04:00
2013-07-07 15:02:47 +04:00
num_bdigits0 = integer_unpack_num_bdigits ( numwords , wordsize , nails , & nlp_bits ) ;
2013-06-12 13:21:11 +04:00
2013-07-07 15:02:47 +04:00
assert ( num_bdigits0 < = num_bdigits ) ;
sign = bary_unpack_internal ( bdigits , num_bdigits0 , words , numwords , wordsize , nails , flags , nlp_bits ) ;
if ( num_bdigits0 < num_bdigits ) {
2013-07-18 08:00:49 +04:00
BDIGITS_ZERO ( bdigits + num_bdigits0 , num_bdigits - num_bdigits0 ) ;
2013-07-07 15:02:47 +04:00
if ( sign = = - 2 ) {
bdigits [ num_bdigits0 ] = 1 ;
}
2013-06-11 18:02:46 +04:00
}
2013-06-07 14:49:12 +04:00
}
2013-07-07 15:02:47 +04:00
static int
2013-07-28 07:12:36 +04:00
bary_subb ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , int borrow )
2013-06-07 16:06:09 +04:00
{
2013-07-07 15:02:47 +04:00
BDIGIT_DBL_SIGNED num ;
size_t i ;
2013-07-14 17:24:44 +04:00
size_t sn ;
2013-06-07 16:06:09 +04:00
2013-07-07 15:02:47 +04:00
assert ( xn < = zn ) ;
2013-07-14 17:24:44 +04:00
assert ( yn < = zn ) ;
sn = xn < yn ? xn : yn ;
2013-06-07 16:06:09 +04:00
2013-07-07 15:02:47 +04:00
num = borrow ? - 1 : 0 ;
2013-07-14 17:24:44 +04:00
for ( i = 0 ; i < sn ; i + + ) {
2013-07-07 15:02:47 +04:00
num + = ( BDIGIT_DBL_SIGNED ) xds [ i ] - yds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
2013-06-07 16:06:09 +04:00
}
2013-07-14 17:24:44 +04:00
if ( yn < = xn ) {
for ( ; i < xn ; i + + ) {
if ( num = = 0 ) goto num_is_zero ;
num + = xds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
}
else {
for ( ; i < yn ; i + + ) {
num - = yds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
2013-07-07 15:02:47 +04:00
}
if ( num = = 0 ) goto num_is_zero ;
for ( ; i < zn ; i + + ) {
zds [ i ] = BDIGMAX ;
2013-06-07 16:06:09 +04:00
}
2013-07-07 15:02:47 +04:00
return 1 ;
2013-06-07 16:06:09 +04:00
2013-07-07 15:02:47 +04:00
num_is_zero :
if ( xds = = zds & & xn = = zn )
return 0 ;
for ( ; i < xn ; i + + ) {
zds [ i ] = xds [ i ] ;
}
for ( ; i < zn ; i + + ) {
zds [ i ] = 0 ;
}
return 0 ;
2013-06-07 16:06:09 +04:00
}
2013-07-07 15:02:47 +04:00
static int
2013-07-28 07:12:36 +04:00
bary_sub ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-06-06 15:57:35 +04:00
{
2013-07-07 15:02:47 +04:00
return bary_subb ( zds , zn , xds , xn , yds , yn , 0 ) ;
2013-06-06 15:57:35 +04:00
}
2013-07-07 15:02:47 +04:00
static int
bary_sub_one ( BDIGIT * zds , size_t zn )
2013-06-06 15:57:35 +04:00
{
2013-07-07 15:02:47 +04:00
return bary_subb ( zds , zn , zds , zn , NULL , 0 , 1 ) ;
2013-06-06 15:57:35 +04:00
}
2013-06-11 16:06:40 +04:00
static int
2013-07-28 07:12:36 +04:00
bary_addc ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , int carry )
2013-06-06 15:57:35 +04:00
{
2013-07-07 15:02:47 +04:00
BDIGIT_DBL num ;
size_t i ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
assert ( xn < = zn ) ;
assert ( yn < = zn ) ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
if ( xn > yn ) {
2013-07-28 07:12:36 +04:00
const BDIGIT * tds ;
2013-07-07 15:02:47 +04:00
tds = xds ; xds = yds ; yds = tds ;
i = xn ; xn = yn ; yn = i ;
}
2013-06-16 09:33:39 +04:00
2013-07-07 15:02:47 +04:00
num = carry ? 1 : 0 ;
for ( i = 0 ; i < xn ; i + + ) {
num + = ( BDIGIT_DBL ) xds [ i ] + yds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
for ( ; i < yn ; i + + ) {
if ( num = = 0 ) goto num_is_zero ;
num + = yds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
for ( ; i < zn ; i + + ) {
if ( num = = 0 ) goto num_is_zero ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
2013-06-06 15:57:35 +04:00
}
2013-07-07 15:02:47 +04:00
return num ! = 0 ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
num_is_zero :
if ( yds = = zds & & yn = = zn )
return 0 ;
for ( ; i < yn ; i + + ) {
zds [ i ] = yds [ i ] ;
2013-06-21 21:22:14 +04:00
}
2013-07-07 15:02:47 +04:00
for ( ; i < zn ; i + + ) {
zds [ i ] = 0 ;
}
return 0 ;
}
static int
2013-07-28 07:12:36 +04:00
bary_add ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-07-07 15:02:47 +04:00
{
return bary_addc ( zds , zn , xds , xn , yds , yn , 0 ) ;
}
2013-06-21 21:22:14 +04:00
2013-07-07 15:02:47 +04:00
static int
2013-07-10 17:06:33 +04:00
bary_add_one ( BDIGIT * ds , size_t n )
2013-07-07 15:02:47 +04:00
{
2013-07-10 17:06:33 +04:00
size_t i ;
for ( i = 0 ; i < n ; i + + ) {
ds [ i ] = BIGLO ( ds [ i ] + 1 ) ;
if ( ds [ i ] ! = 0 )
return 0 ;
}
return 1 ;
2013-07-07 15:02:47 +04:00
}
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
static void
2013-08-05 18:50:07 +04:00
bary_mul_single ( BDIGIT * zds , size_t zn , BDIGIT x , BDIGIT y )
2013-07-07 15:02:47 +04:00
{
BDIGIT_DBL n ;
2013-08-05 18:50:07 +04:00
assert ( 2 < = zn ) ;
2013-07-07 15:02:47 +04:00
n = ( BDIGIT_DBL ) x * y ;
2013-08-03 19:26:04 +04:00
bdigitdbl2bary ( zds , 2 , n ) ;
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds + 2 , zn - 2 ) ;
2013-07-07 15:02:47 +04:00
}
static int
2013-08-05 18:50:07 +04:00
bary_muladd_1xN ( BDIGIT * zds , size_t zn , BDIGIT x , const BDIGIT * yds , size_t yn )
2013-07-07 15:02:47 +04:00
{
BDIGIT_DBL n ;
BDIGIT_DBL dd ;
size_t j ;
2013-08-05 18:50:07 +04:00
assert ( zn > yn ) ;
2013-07-07 15:02:47 +04:00
if ( x = = 0 )
return 0 ;
dd = x ;
n = 0 ;
2013-08-05 18:50:07 +04:00
for ( j = 0 ; j < yn ; j + + ) {
2013-07-07 15:02:47 +04:00
BDIGIT_DBL ee = n + dd * yds [ j ] ;
if ( ee ) {
n = zds [ j ] + ee ;
zds [ j ] = BIGLO ( n ) ;
n = BIGDN ( n ) ;
}
2013-06-11 16:06:40 +04:00
else {
2013-07-07 15:02:47 +04:00
n = 0 ;
2013-06-11 16:06:40 +04:00
}
2013-07-07 15:02:47 +04:00
2013-06-06 15:57:35 +04:00
}
2013-08-05 18:50:07 +04:00
for ( ; j < zn ; j + + ) {
2013-07-07 15:02:47 +04:00
if ( n = = 0 )
break ;
n + = zds [ j ] ;
zds [ j ] = BIGLO ( n ) ;
n = BIGDN ( n ) ;
2013-06-06 15:57:35 +04:00
}
2013-07-07 15:02:47 +04:00
return n ! = 0 ;
}
2013-06-06 15:57:35 +04:00
2013-07-23 02:16:45 +04:00
static BDIGIT_DBL_SIGNED
2013-07-28 07:12:36 +04:00
bigdivrem_mulsub ( BDIGIT * zds , size_t zn , BDIGIT x , const BDIGIT * yds , size_t yn )
2013-07-23 02:16:45 +04:00
{
size_t i ;
BDIGIT_DBL t2 ;
BDIGIT_DBL_SIGNED num ;
assert ( zn = = yn + 1 ) ;
num = 0 ;
t2 = 0 ;
i = 0 ;
do {
BDIGIT_DBL ee ;
t2 + = ( BDIGIT_DBL ) yds [ i ] * x ;
ee = num - BIGLO ( t2 ) ;
num = ( BDIGIT_DBL ) zds [ i ] + ee ;
if ( ee ) zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
t2 = BIGDN ( t2 ) ;
} while ( + + i < yn ) ;
num + = zds [ i ] - t2 ; /* borrow from high digit; don't update */
return num ;
}
static int
2013-07-28 07:12:36 +04:00
bary_mulsub_1xN ( BDIGIT * zds , size_t zn , BDIGIT x , const BDIGIT * yds , size_t yn )
2013-07-23 02:16:45 +04:00
{
BDIGIT_DBL_SIGNED num ;
assert ( zn = = yn + 1 ) ;
num = bigdivrem_mulsub ( zds , zn , x , yds , yn ) ;
zds [ yn ] = BIGLO ( num ) ;
if ( BIGDN ( num ) )
return 1 ;
return 0 ;
}
2013-07-07 15:02:47 +04:00
static void
2013-08-05 18:50:07 +04:00
bary_mul_normal ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-07-07 15:02:47 +04:00
{
size_t i ;
2013-06-06 15:57:35 +04:00
2013-08-05 18:50:07 +04:00
assert ( xn + yn < = zn ) ;
2013-06-06 15:57:35 +04:00
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds , zn ) ;
for ( i = 0 ; i < xn ; i + + ) {
bary_muladd_1xN ( zds + i , zn - i , xds [ i ] , yds , yn ) ;
2013-07-07 15:02:47 +04:00
}
}
2013-06-06 15:57:35 +04:00
2013-07-07 18:01:40 +04:00
VALUE
rb_big_mul_normal ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , zn = xn + yn ;
VALUE z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
bary_mul_normal ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn , BDIGITS ( y ) , yn ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
}
2013-07-07 15:02:47 +04:00
/* efficient squaring (2 times faster than normal multiplication)
* ref : Handbook of Applied Cryptography , Algorithm 14.16
* http : //www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
*/
static void
2013-07-28 07:12:36 +04:00
bary_sq_fast ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn )
2013-07-07 15:02:47 +04:00
{
size_t i , j ;
BDIGIT_DBL c , v , w ;
2013-07-21 19:17:09 +04:00
BDIGIT vl ;
int vh ;
2013-06-06 15:57:35 +04:00
2013-07-07 15:02:47 +04:00
assert ( xn * 2 < = zn ) ;
2013-06-06 15:57:35 +04:00
2013-07-18 08:00:49 +04:00
BDIGITS_ZERO ( zds , zn ) ;
2013-07-18 16:58:46 +04:00
if ( xn = = 0 )
return ;
for ( i = 0 ; i < xn - 1 ; i + + ) {
2013-07-07 15:02:47 +04:00
v = ( BDIGIT_DBL ) xds [ i ] ;
2013-07-08 17:05:57 +04:00
if ( ! v )
continue ;
2013-07-07 15:02:47 +04:00
c = ( BDIGIT_DBL ) zds [ i + i ] + v * v ;
zds [ i + i ] = BIGLO ( c ) ;
c = BIGDN ( c ) ;
v * = 2 ;
2013-07-21 19:17:09 +04:00
vl = BIGLO ( v ) ;
vh = ( int ) BIGDN ( v ) ;
2013-07-07 15:02:47 +04:00
for ( j = i + 1 ; j < xn ; j + + ) {
w = ( BDIGIT_DBL ) xds [ j ] ;
2013-07-21 19:17:09 +04:00
c + = ( BDIGIT_DBL ) zds [ i + j ] + vl * w ;
2013-07-07 15:02:47 +04:00
zds [ i + j ] = BIGLO ( c ) ;
c = BIGDN ( c ) ;
2013-07-21 19:17:09 +04:00
if ( vh )
2013-07-08 17:05:57 +04:00
c + = w ;
2013-07-07 15:02:47 +04:00
}
if ( c ) {
c + = ( BDIGIT_DBL ) zds [ i + xn ] ;
zds [ i + xn ] = BIGLO ( c ) ;
c = BIGDN ( c ) ;
2013-07-18 16:58:46 +04:00
if ( c )
2013-07-08 17:05:57 +04:00
zds [ i + xn + 1 ] + = ( BDIGIT ) c ;
2013-07-07 15:02:47 +04:00
}
}
2013-07-18 16:58:46 +04:00
/* i == xn-1 */
v = ( BDIGIT_DBL ) xds [ i ] ;
if ( ! v )
return ;
c = ( BDIGIT_DBL ) zds [ i + i ] + v * v ;
zds [ i + i ] = BIGLO ( c ) ;
c = BIGDN ( c ) ;
if ( c ) {
2013-07-21 19:17:09 +04:00
zds [ i + xn ] + = BIGLO ( c ) ;
2013-07-18 16:58:46 +04:00
}
2013-07-07 15:02:47 +04:00
}
2013-06-06 15:57:35 +04:00
2013-07-08 17:05:57 +04:00
VALUE
rb_big_sq_fast ( VALUE x )
{
size_t xn = RBIGNUM_LEN ( x ) , zn = 2 * xn ;
VALUE z = bignew ( zn , 1 ) ;
bary_sq_fast ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn ) ;
RB_GC_GUARD ( x ) ;
return z ;
}
2013-07-07 15:02:47 +04:00
/* balancing multiplication by slicing larger argument */
static void
2013-08-05 18:50:07 +04:00
bary_mul_balance_with_mulfunc ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn , mulfunc_t * mulfunc )
2013-07-07 15:02:47 +04:00
{
VALUE work = 0 ;
2013-08-05 18:50:07 +04:00
size_t yn0 = yn ;
2013-07-08 15:56:55 +04:00
size_t r , n ;
2013-06-06 15:57:35 +04:00
2013-08-05 18:50:07 +04:00
assert ( xn + yn < = zn ) ;
assert ( xn < = yn ) ;
assert ( ! KARATSUBA_BALANCED ( xn , yn ) | | ! TOOM3_BALANCED ( xn , yn ) ) ;
2013-06-06 15:57:35 +04:00
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds , xn ) ;
2013-07-07 15:02:47 +04:00
n = 0 ;
2013-08-05 18:50:07 +04:00
while ( yn > 0 ) {
2013-07-08 15:56:55 +04:00
BDIGIT * tds ;
2013-08-05 18:50:07 +04:00
size_t tn ;
r = xn > yn ? yn : xn ;
tn = xn + r ;
if ( 2 * ( xn + r ) < = zn - n ) {
tds = zds + n + xn + r ;
mulfunc ( tds , tn , xds , xn , yds + n , r , wds , wn ) ;
BDIGITS_ZERO ( zds + n + xn , r ) ;
bary_add ( zds + n , tn ,
zds + n , tn ,
tds , tn ) ;
2013-07-08 15:56:55 +04:00
}
else {
2013-08-05 18:50:07 +04:00
if ( wn < xn ) {
wn = xn ;
wds = ALLOCV_N ( BDIGIT , work , wn ) ;
2013-07-08 15:56:55 +04:00
}
tds = zds + n ;
2013-08-05 18:50:07 +04:00
MEMCPY ( wds , zds + n , BDIGIT , xn ) ;
mulfunc ( tds , tn , xds , xn , yds + n , r , wds - xn , wn - xn ) ;
bary_add ( zds + n , tn ,
zds + n , tn ,
wds , xn ) ;
2013-07-08 15:56:55 +04:00
}
2013-08-05 18:50:07 +04:00
yn - = r ;
2013-07-07 15:02:47 +04:00
n + = r ;
}
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds + xn + yn0 , zn - ( xn + yn0 ) ) ;
2013-07-07 15:02:47 +04:00
if ( work )
ALLOCV_END ( work ) ;
}
2013-07-07 18:01:40 +04:00
VALUE
rb_big_mul_balance ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , zn = xn + yn ;
VALUE z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
2013-07-11 07:06:02 +04:00
bary_mul_balance_with_mulfunc ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn , BDIGITS ( y ) , yn , NULL , 0 , bary_mul_toom3_start ) ;
2013-07-07 18:01:40 +04:00
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
}
2013-07-07 15:02:47 +04:00
/* multiplication by karatsuba method */
static void
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-07 15:02:47 +04:00
{
VALUE work = 0 ;
size_t n ;
int sub_p , borrow , carry1 , carry2 , carry3 ;
int odd_y = 0 ;
2013-07-07 19:21:26 +04:00
int odd_xy = 0 ;
2013-07-16 13:37:42 +04:00
int sq ;
2013-07-07 15:02:47 +04:00
2013-07-28 07:12:36 +04:00
const BDIGIT * xds0 , * xds1 , * yds0 , * yds1 ;
BDIGIT * zds0 , * zds1 , * zds2 , * zds3 ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
assert ( xn + yn < = zn ) ;
assert ( xn < = yn ) ;
assert ( yn < 2 * xn ) ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
sq = xds = = yds & & xn = = yn ;
2013-07-16 13:37:42 +04:00
2013-08-05 18:50:07 +04:00
if ( yn & 1 ) {
2013-07-07 15:02:47 +04:00
odd_y = 1 ;
2013-08-05 18:50:07 +04:00
yn - - ;
if ( yn < xn ) {
2013-07-07 19:21:26 +04:00
odd_xy = 1 ;
2013-08-05 18:50:07 +04:00
xn - - ;
2013-06-11 16:06:40 +04:00
}
2013-06-06 15:57:35 +04:00
}
2013-08-05 18:50:07 +04:00
n = yn / 2 ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
assert ( n < xn ) ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
if ( wn < n ) {
2013-07-08 17:44:34 +04:00
/* This function itself needs only n BDIGITs for work area.
* However this function calls bary_mul_karatsuba and
* bary_mul_balance recursively .
* 2 n BDIGITs are enough to avoid allocations in
* the recursively called functions .
*/
2013-08-05 18:50:07 +04:00
wn = 2 * n ;
wds = ALLOCV_N ( BDIGIT , work , wn ) ;
2013-07-08 17:44:34 +04:00
}
2013-07-07 15:02:47 +04:00
/* Karatsuba algorithm:
*
* x = x0 + r * x1
* y = y0 + r * y1
* z = x * y
* = ( x0 + r * x1 ) * ( y0 + r * y1 )
* = x0 * y0 + r * ( x1 * y0 + x0 * y1 ) + r * r * x1 * y1
* = x0 * y0 + r * ( x0 * y0 + x1 * y1 - ( x1 - x0 ) * ( y1 - y0 ) ) + r * r * x1 * y1
* = x0 * y0 + r * ( x0 * y0 + x1 * y1 - ( x0 - x1 ) * ( y0 - y1 ) ) + r * r * x1 * y1
*/
xds0 = xds ;
xds1 = xds + n ;
yds0 = yds ;
yds1 = yds + n ;
zds0 = zds ;
zds1 = zds + n ;
zds2 = zds + 2 * n ;
zds3 = zds + 3 * n ;
sub_p = 1 ;
/* zds0:? zds1:? zds2:? zds3:? wds:? */
2013-08-05 18:50:07 +04:00
if ( bary_sub ( zds0 , n , xds , n , xds + n , xn - n ) ) {
2013-07-07 15:02:47 +04:00
bary_2comp ( zds0 , n ) ;
sub_p = ! sub_p ;
}
/* zds0:|x1-x0| zds1:? zds2:? zds3:? wds:? */
2013-06-11 16:06:40 +04:00
2013-07-16 13:37:42 +04:00
if ( sq ) {
sub_p = 1 ;
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_start ( zds1 , 2 * n , zds0 , n , zds0 , n , wds , wn ) ;
2013-07-07 15:02:47 +04:00
}
2013-07-16 13:37:42 +04:00
else {
if ( bary_sub ( wds , n , yds , n , yds + n , n ) ) {
bary_2comp ( wds , n ) ;
sub_p = ! sub_p ;
}
2013-06-11 16:06:40 +04:00
2013-07-16 13:37:42 +04:00
/* zds0:|x1-x0| zds1:? zds2:? zds3:? wds:|y1-y0| */
2013-06-11 16:06:40 +04:00
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_start ( zds1 , 2 * n , zds0 , n , wds , n , wds + n , wn - n ) ;
2013-07-16 13:37:42 +04:00
}
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:|x1-x0| zds1,zds2:|x1-x0|*|y1-y0| zds3:? wds:|y1-y0| */
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
borrow = 0 ;
if ( sub_p ) {
borrow = ! bary_2comp ( zds1 , 2 * n ) ;
}
/* zds0:|x1-x0| zds1,zds2:-?|x1-x0|*|y1-y0| zds3:? wds:|y1-y0| */
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
MEMCPY ( wds , zds1 , BDIGIT , n ) ;
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:|x1-x0| zds1,zds2:-?|x1-x0|*|y1-y0| zds3:? wds:lo(-?|x1-x0|*|y1-y0|) */
2013-06-11 16:06:40 +04:00
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_start ( zds0 , 2 * n , xds0 , n , yds0 , n , wds + n , wn - n ) ;
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
/* zds0,zds1:x0*y0 zds2:hi(-?|x1-x0|*|y1-y0|) zds3:? wds:lo(-?|x1-x0|*|y1-y0|) */
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
carry1 = bary_add ( wds , n , wds , n , zds0 , n ) ;
carry1 = bary_addc ( zds2 , n , zds2 , n , zds1 , n , carry1 ) ;
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
/* zds0,zds1:x0*y0 zds2:hi(x0*y0-?|x1-x0|*|y1-y0|) zds3:? wds:lo(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-16 13:53:45 +04:00
2013-07-07 15:02:47 +04:00
carry2 = bary_add ( zds1 , n , zds1 , n , wds , n ) ;
2013-06-16 13:53:45 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|) zds2:hi(x0*y0-?|x1-x0|*|y1-y0|) zds3:? wds:lo(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-16 13:53:45 +04:00
2013-07-07 15:02:47 +04:00
MEMCPY ( wds , zds2 , BDIGIT , n ) ;
2013-06-16 13:53:45 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|) zds2:_ zds3:? wds:hi(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-16 13:53:45 +04:00
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_start ( zds2 , zn - 2 * n , xds1 , xn - n , yds1 , n , wds + n , wn - n ) ;
2013-06-11 16:06:40 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|) zds2,zds3:x1*y1 wds:hi(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-10 07:12:44 +04:00
2013-07-07 15:02:47 +04:00
carry3 = bary_add ( zds1 , n , zds1 , n , zds2 , n ) ;
2013-06-10 07:12:44 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|)+lo(x1*y1) zds2,zds3:x1*y1 wds:hi(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-12 17:25:00 +04:00
2013-08-05 18:50:07 +04:00
carry3 = bary_addc ( zds2 , n , zds2 , n , zds3 , ( 4 * n < zn ? n : zn - 3 * n ) , carry3 ) ;
2013-06-12 17:25:00 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|)+lo(x1*y1) zds2,zds3:x1*y1+hi(x1*y1) wds:hi(x0*y0-?|x1-x0|*|y1-y0|) */
2013-06-12 17:25:00 +04:00
2013-08-05 18:50:07 +04:00
bary_add ( zds2 , zn - 2 * n , zds2 , zn - 2 * n , wds , n ) ;
2013-06-12 17:25:00 +04:00
2013-07-07 15:02:47 +04:00
/* zds0:lo(x0*y0) zds1:hi(x0*y0)+lo(x0*y0-?|x1-x0|*|y1-y0|)+lo(x1*y1) zds2,zds3:x1*y1+hi(x1*y1)+hi(x0*y0-?|x1-x0|*|y1-y0|) wds:_ */
2013-06-10 07:12:44 +04:00
2013-07-07 15:02:47 +04:00
if ( carry2 )
2013-08-05 18:50:07 +04:00
bary_add_one ( zds2 , zn - 2 * n ) ;
2013-06-10 07:12:44 +04:00
2013-07-07 19:21:26 +04:00
if ( carry1 + carry3 - borrow < 0 )
2013-08-05 18:50:07 +04:00
bary_sub_one ( zds3 , zn - 3 * n ) ;
2013-07-07 19:21:26 +04:00
else if ( carry1 + carry3 - borrow > 0 ) {
BDIGIT c = carry1 + carry3 - borrow ;
2013-08-05 18:50:07 +04:00
bary_add ( zds3 , zn - 3 * n , zds3 , zn - 3 * n , & c , 1 ) ;
2013-07-07 15:02:47 +04:00
}
2013-06-12 17:25:00 +04:00
2013-07-07 15:02:47 +04:00
/*
2013-08-05 18:50:07 +04:00
if ( SIZEOF_BDIGITS * zn < = 16 ) {
2013-07-07 15:02:47 +04:00
uint128_t z , x , y ;
ssize_t i ;
2013-08-05 18:50:07 +04:00
for ( x = 0 , i = xn - 1 ; 0 < = i ; i - - ) { x < < = SIZEOF_BDIGITS * CHAR_BIT ; x | = xds [ i ] ; }
for ( y = 0 , i = yn - 1 ; 0 < = i ; i - - ) { y < < = SIZEOF_BDIGITS * CHAR_BIT ; y | = yds [ i ] ; }
for ( z = 0 , i = zn - 1 ; 0 < = i ; i - - ) { z < < = SIZEOF_BDIGITS * CHAR_BIT ; z | = zds [ i ] ; }
2013-07-07 15:02:47 +04:00
assert ( z = = x * y ) ;
2013-06-12 17:25:00 +04:00
}
2013-07-07 15:02:47 +04:00
*/
2013-07-07 19:21:26 +04:00
if ( odd_xy ) {
2013-08-05 18:50:07 +04:00
bary_muladd_1xN ( zds + yn , zn - yn , yds [ yn ] , xds , xn ) ;
bary_muladd_1xN ( zds + xn , zn - xn , xds [ xn ] , yds , yn + 1 ) ;
2013-07-07 15:02:47 +04:00
}
else if ( odd_y ) {
2013-08-05 18:50:07 +04:00
bary_muladd_1xN ( zds + yn , zn - yn , yds [ yn ] , xds , xn ) ;
2013-06-12 17:25:00 +04:00
}
2013-07-07 15:02:47 +04:00
if ( work )
ALLOCV_END ( work ) ;
2013-06-10 07:12:44 +04:00
}
2013-07-07 18:01:40 +04:00
VALUE
rb_big_mul_karatsuba ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , zn = xn + yn ;
VALUE z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
2013-08-09 17:41:23 +04:00
if ( ! ( ( xn < = yn & & yn < 2 ) | | KARATSUBA_BALANCED ( xn , yn ) ) )
2013-07-22 22:35:27 +04:00
rb_raise ( rb_eArgError , " unexpected bignum length for karatsuba " ) ;
2013-07-08 17:44:34 +04:00
bary_mul_karatsuba ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn , BDIGITS ( y ) , yn , NULL , 0 ) ;
2013-07-07 18:01:40 +04:00
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
}
2013-07-21 05:01:26 +04:00
static void
2013-07-28 07:12:36 +04:00
bary_mul_toom3 ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-21 05:01:26 +04:00
{
size_t n ;
size_t wnc ;
VALUE work = 0 ;
2013-08-15 21:24:41 +04:00
/* "p" stands for "positive". Actually it means "non-negative", though. */
2013-07-28 07:12:36 +04:00
size_t x0n ; const BDIGIT * x0ds ;
size_t x1n ; const BDIGIT * x1ds ;
size_t x2n ; const BDIGIT * x2ds ;
size_t y0n ; const BDIGIT * y0ds ;
size_t y1n ; const BDIGIT * y1ds ;
size_t y2n ; const BDIGIT * y2ds ;
2013-07-21 05:01:26 +04:00
size_t u1n ; BDIGIT * u1ds ; int u1p ;
size_t u2n ; BDIGIT * u2ds ; int u2p ;
size_t u3n ; BDIGIT * u3ds ; int u3p ;
size_t v1n ; BDIGIT * v1ds ; int v1p ;
size_t v2n ; BDIGIT * v2ds ; int v2p ;
size_t v3n ; BDIGIT * v3ds ; int v3p ;
size_t t0n ; BDIGIT * t0ds ; int t0p ;
size_t t1n ; BDIGIT * t1ds ; int t1p ;
size_t t2n ; BDIGIT * t2ds ; int t2p ;
size_t t3n ; BDIGIT * t3ds ; int t3p ;
size_t t4n ; BDIGIT * t4ds ; int t4p ;
size_t z0n ; BDIGIT * z0ds ;
size_t z1n ; BDIGIT * z1ds ; int z1p ;
size_t z2n ; BDIGIT * z2ds ; int z2p ;
size_t z3n ; BDIGIT * z3ds ; int z3p ;
2013-08-15 21:24:41 +04:00
size_t z4n ; BDIGIT * z4ds ;
2013-07-21 05:01:26 +04:00
size_t zzn ; BDIGIT * zzds ;
int sq = xds = = yds & & xn = = yn ;
assert ( xn < = yn ) ; /* assume y >= x */
assert ( xn + yn < = zn ) ;
n = ( yn + 2 ) / 3 ;
assert ( 2 * n < xn ) ;
wnc = 0 ;
wnc + = ( u1n = n + 1 ) ; /* BITSPERDIG*n+2 bits */
wnc + = ( u2n = n + 1 ) ; /* BITSPERDIG*n+1 bits */
wnc + = ( u3n = n + 1 ) ; /* BITSPERDIG*n+3 bits */
wnc + = ( v1n = n + 1 ) ; /* BITSPERDIG*n+2 bits */
wnc + = ( v2n = n + 1 ) ; /* BITSPERDIG*n+1 bits */
wnc + = ( v3n = n + 1 ) ; /* BITSPERDIG*n+3 bits */
wnc + = ( t0n = 2 * n ) ; /* BITSPERDIG*2*n bits */
wnc + = ( t1n = 2 * n + 2 ) ; /* BITSPERDIG*2*n+4 bits but bary_mul needs u1n+v1n */
wnc + = ( t2n = 2 * n + 2 ) ; /* BITSPERDIG*2*n+2 bits but bary_mul needs u2n+v2n */
wnc + = ( t3n = 2 * n + 2 ) ; /* BITSPERDIG*2*n+6 bits but bary_mul needs u3n+v3n */
wnc + = ( t4n = 2 * n ) ; /* BITSPERDIG*2*n bits */
wnc + = ( z1n = 2 * n + 1 ) ; /* BITSPERDIG*2*n+5 bits */
wnc + = ( z2n = 2 * n + 1 ) ; /* BITSPERDIG*2*n+6 bits */
wnc + = ( z3n = 2 * n + 1 ) ; /* BITSPERDIG*2*n+8 bits */
if ( wn < wnc ) {
wn = wnc * 3 / 2 ; /* Allocate working memory for whole recursion at once. */
wds = ALLOCV_N ( BDIGIT , work , wn ) ;
}
u1ds = wds ; wds + = u1n ;
u2ds = wds ; wds + = u2n ;
u3ds = wds ; wds + = u3n ;
v1ds = wds ; wds + = v1n ;
v2ds = wds ; wds + = v2n ;
v3ds = wds ; wds + = v3n ;
t0ds = wds ; wds + = t0n ;
t1ds = wds ; wds + = t1n ;
t2ds = wds ; wds + = t2n ;
t3ds = wds ; wds + = t3n ;
t4ds = wds ; wds + = t4n ;
z1ds = wds ; wds + = z1n ;
z2ds = wds ; wds + = z2n ;
z3ds = wds ; wds + = z3n ;
wn - = wnc ;
zzds = u1ds ;
zzn = 6 * n + 1 ;
x0n = n ;
x1n = n ;
x2n = xn - 2 * n ;
x0ds = xds ;
x1ds = xds + n ;
x2ds = xds + 2 * n ;
if ( sq ) {
y0n = x0n ;
y1n = x1n ;
y2n = x2n ;
y0ds = x0ds ;
y1ds = x1ds ;
y2ds = x2ds ;
}
else {
y0n = n ;
y1n = n ;
y2n = yn - 2 * n ;
y0ds = yds ;
y1ds = yds + n ;
y2ds = yds + 2 * n ;
}
/*
* ref . http : //en.wikipedia.org/wiki/Toom%E2%80%93Cook_multiplication
*
* x ( b ) = x0 * b ^ 0 + x1 * b ^ 1 + x2 * b ^ 2
* y ( b ) = y0 * b ^ 0 + y1 * b ^ 1 + y2 * b ^ 2
*
* z ( b ) = x ( b ) * y ( b )
* z ( b ) = z0 * b ^ 0 + z1 * b ^ 1 + z2 * b ^ 2 + z3 * b ^ 3 + z4 * b ^ 4
* where :
* z0 = x0 * y0
* z1 = x0 * y1 + x1 * y0
* z2 = x0 * y2 + x1 * y1 + x2 * y0
* z3 = x1 * y2 + x2 * y1
* z4 = x2 * y2
*
* Toom3 method ( a . k . a . Toom - Cook method ) :
* ( Step1 ) calculating 5 points z ( b0 ) , z ( b1 ) , z ( b2 ) , z ( b3 ) , z ( b4 ) ,
* where :
* b0 = 0 , b1 = 1 , b2 = - 1 , b3 = - 2 , b4 = inf ,
* z ( 0 ) = x ( 0 ) * y ( 0 ) = x0 * y0
* z ( 1 ) = x ( 1 ) * y ( 1 ) = ( x0 + x1 + x2 ) * ( y0 + y1 + y2 )
* z ( - 1 ) = x ( - 1 ) * y ( - 1 ) = ( x0 - x1 + x2 ) * ( y0 - y1 + y2 )
* z ( - 2 ) = x ( - 2 ) * y ( - 2 ) = ( x0 - 2 * ( x1 - 2 * x2 ) ) * ( y0 - 2 * ( y1 - 2 * y2 ) )
* z ( inf ) = x ( inf ) * y ( inf ) = x2 * y2
*
* ( Step2 ) interpolating z0 , z1 , z2 , z3 and z4 .
*
* ( Step3 ) Substituting base value into b of the polynomial z ( b ) ,
*/
/*
* [ Step1 ] calculating 5 points z ( b0 ) , z ( b1 ) , z ( b2 ) , z ( b3 ) , z ( b4 )
*/
/* u1 <- x0 + x2 */
bary_add ( u1ds , u1n , x0ds , x0n , x2ds , x2n ) ;
u1p = 1 ;
/* x(-1) : u2 <- u1 - x1 = x0 - x1 + x2 */
if ( bary_sub ( u2ds , u2n , u1ds , u1n , x1ds , x1n ) ) {
bary_2comp ( u2ds , u2n ) ;
u2p = 0 ;
}
else {
u2p = 1 ;
}
/* x(1) : u1 <- u1 + x1 = x0 + x1 + x2 */
bary_add ( u1ds , u1n , u1ds , u1n , x1ds , x1n ) ;
/* x(-2) : u3 <- 2 * (u2 + x2) - x0 = x0 - 2 * (x1 - 2 * x2) */
u3p = 1 ;
if ( u2p ) {
bary_add ( u3ds , u3n , u2ds , u2n , x2ds , x2n ) ;
}
else if ( bary_sub ( u3ds , u3n , x2ds , x2n , u2ds , u2n ) ) {
bary_2comp ( u3ds , u3n ) ;
u3p = 0 ;
}
bary_small_lshift ( u3ds , u3ds , u3n , 1 ) ;
if ( ! u3p ) {
bary_add ( u3ds , u3n , u3ds , u3n , x0ds , x0n ) ;
}
else if ( bary_sub ( u3ds , u3n , u3ds , u3n , x0ds , x0n ) ) {
bary_2comp ( u3ds , u3n ) ;
u3p = 0 ;
}
if ( sq ) {
v1n = u1n ; v1ds = u1ds ; v1p = u1p ;
v2n = u2n ; v2ds = u2ds ; v2p = u2p ;
v3n = u3n ; v3ds = u3ds ; v3p = u3p ;
}
else {
/* v1 <- y0 + y2 */
bary_add ( v1ds , v1n , y0ds , y0n , y2ds , y2n ) ;
v1p = 1 ;
/* y(-1) : v2 <- v1 - y1 = y0 - y1 + y2 */
v2p = 1 ;
if ( bary_sub ( v2ds , v2n , v1ds , v1n , y1ds , y1n ) ) {
bary_2comp ( v2ds , v2n ) ;
v2p = 0 ;
}
/* y(1) : v1 <- v1 + y1 = y0 + y1 + y2 */
bary_add ( v1ds , v1n , v1ds , v1n , y1ds , y1n ) ;
/* y(-2) : v3 <- 2 * (v2 + y2) - y0 = y0 - 2 * (y1 - 2 * y2) */
v3p = 1 ;
if ( v2p ) {
bary_add ( v3ds , v3n , v2ds , v2n , y2ds , y2n ) ;
}
else if ( bary_sub ( v3ds , v3n , y2ds , y2n , v2ds , v2n ) ) {
bary_2comp ( v3ds , v3n ) ;
v3p = 0 ;
}
bary_small_lshift ( v3ds , v3ds , v3n , 1 ) ;
if ( ! v3p ) {
bary_add ( v3ds , v3n , v3ds , v3n , y0ds , y0n ) ;
}
else if ( bary_sub ( v3ds , v3n , v3ds , v3n , y0ds , y0n ) ) {
bary_2comp ( v3ds , v3n ) ;
v3p = 0 ;
}
}
/* z(0) : t0 <- x0 * y0 */
bary_mul_toom3_start ( t0ds , t0n , x0ds , x0n , y0ds , y0n , wds , wn ) ;
t0p = 1 ;
/* z(1) : t1 <- u1 * v1 */
bary_mul_toom3_start ( t1ds , t1n , u1ds , u1n , v1ds , v1n , wds , wn ) ;
t1p = u1p = = v1p ;
assert ( t1ds [ t1n - 1 ] = = 0 ) ;
t1n - - ;
/* z(-1) : t2 <- u2 * v2 */
bary_mul_toom3_start ( t2ds , t2n , u2ds , u2n , v2ds , v2n , wds , wn ) ;
t2p = u2p = = v2p ;
assert ( t2ds [ t2n - 1 ] = = 0 ) ;
t2n - - ;
/* z(-2) : t3 <- u3 * v3 */
bary_mul_toom3_start ( t3ds , t3n , u3ds , u3n , v3ds , v3n , wds , wn ) ;
t3p = u3p = = v3p ;
assert ( t3ds [ t3n - 1 ] = = 0 ) ;
t3n - - ;
/* z(inf) : t4 <- x2 * y2 */
bary_mul_toom3_start ( t4ds , t4n , x2ds , x2n , y2ds , y2n , wds , wn ) ;
t4p = 1 ;
/*
* [ Step2 ] interpolating z0 , z1 , z2 , z3 and z4 .
*/
/* z0 <- z(0) == t0 */
z0n = t0n ; z0ds = t0ds ;
/* z4 <- z(inf) == t4 */
2013-08-15 21:24:41 +04:00
z4n = t4n ; z4ds = t4ds ;
2013-07-21 05:01:26 +04:00
/* z3 <- (z(-2) - z(1)) / 3 == (t3 - t1) / 3 */
if ( t3p = = t1p ) {
z3p = t3p ;
if ( bary_sub ( z3ds , z3n , t3ds , t3n , t1ds , t1n ) ) {
bary_2comp ( z3ds , z3n ) ;
z3p = ! z3p ;
}
}
else {
z3p = t3p ;
bary_add ( z3ds , z3n , t3ds , t3n , t1ds , t1n ) ;
}
bigdivrem_single ( z3ds , z3ds , z3n , 3 ) ;
/* z1 <- (z(1) - z(-1)) / 2 == (t1 - t2) / 2 */
if ( t1p = = t2p ) {
z1p = t1p ;
if ( bary_sub ( z1ds , z1n , t1ds , t1n , t2ds , t2n ) ) {
bary_2comp ( z1ds , z1n ) ;
z1p = ! z1p ;
}
}
else {
z1p = t1p ;
bary_add ( z1ds , z1n , t1ds , t1n , t2ds , t2n ) ;
}
bary_small_rshift ( z1ds , z1ds , z1n , 1 , 0 ) ;
/* z2 <- z(-1) - z(0) == t2 - t0 */
if ( t2p = = t0p ) {
z2p = t2p ;
if ( bary_sub ( z2ds , z2n , t2ds , t2n , t0ds , t0n ) ) {
bary_2comp ( z2ds , z2n ) ;
z2p = ! z2p ;
}
}
else {
z2p = t2p ;
bary_add ( z2ds , z2n , t2ds , t2n , t0ds , t0n ) ;
}
/* z3 <- (z2 - z3) / 2 + 2 * z(inf) == (z2 - z3) / 2 + 2 * t4 */
if ( z2p = = z3p ) {
z3p = z2p ;
if ( bary_sub ( z3ds , z3n , z2ds , z2n , z3ds , z3n ) ) {
bary_2comp ( z3ds , z3n ) ;
z3p = ! z3p ;
}
}
else {
z3p = z2p ;
bary_add ( z3ds , z3n , z2ds , z2n , z3ds , z3n ) ;
}
bary_small_rshift ( z3ds , z3ds , z3n , 1 , 0 ) ;
if ( z3p = = t4p ) {
bary_muladd_1xN ( z3ds , z3n , 2 , t4ds , t4n ) ;
}
else {
2013-07-23 02:16:45 +04:00
if ( bary_mulsub_1xN ( z3ds , z3n , 2 , t4ds , t4n ) ) {
2013-07-21 05:01:26 +04:00
bary_2comp ( z3ds , z3n ) ;
z3p = ! z3p ;
}
}
/* z2 <- z2 + z1 - z(inf) == z2 + z1 - t4 */
if ( z2p = = z1p ) {
bary_add ( z2ds , z2n , z2ds , z2n , z1ds , z1n ) ;
}
else {
if ( bary_sub ( z2ds , z2n , z2ds , z2n , z1ds , z1n ) ) {
bary_2comp ( z2ds , z2n ) ;
z2p = ! z2p ;
}
}
if ( z2p = = t4p ) {
if ( bary_sub ( z2ds , z2n , z2ds , z2n , t4ds , t4n ) ) {
bary_2comp ( z2ds , z2n ) ;
z2p = ! z2p ;
}
}
else {
bary_add ( z2ds , z2n , z2ds , z2n , t4ds , t4n ) ;
}
/* z1 <- z1 - z3 */
if ( z1p = = z3p ) {
if ( bary_sub ( z1ds , z1n , z1ds , z1n , z3ds , z3n ) ) {
bary_2comp ( z1ds , z1n ) ;
z1p = ! z1p ;
}
}
else {
bary_add ( z1ds , z1n , z1ds , z1n , z3ds , z3n ) ;
}
/*
* [ Step3 ] Substituting base value into b of the polynomial z ( b ) ,
*/
MEMCPY ( zzds , z0ds , BDIGIT , z0n ) ;
2013-08-15 21:24:41 +04:00
BDIGITS_ZERO ( zzds + z0n , 4 * n - z0n ) ;
MEMCPY ( zzds + 4 * n , z4ds , BDIGIT , z4n ) ;
BDIGITS_ZERO ( zzds + 4 * n + z4n , zzn - ( 4 * n + z4n ) ) ;
2013-07-21 05:01:26 +04:00
if ( z1p )
bary_add ( zzds + n , zzn - n , zzds + n , zzn - n , z1ds , z1n ) ;
else
bary_sub ( zzds + n , zzn - n , zzds + n , zzn - n , z1ds , z1n ) ;
if ( z2p )
bary_add ( zzds + 2 * n , zzn - 2 * n , zzds + 2 * n , zzn - 2 * n , z2ds , z2n ) ;
else
bary_sub ( zzds + 2 * n , zzn - 2 * n , zzds + 2 * n , zzn - 2 * n , z2ds , z2n ) ;
if ( z3p )
bary_add ( zzds + 3 * n , zzn - 3 * n , zzds + 3 * n , zzn - 3 * n , z3ds , z3n ) ;
else
bary_sub ( zzds + 3 * n , zzn - 3 * n , zzds + 3 * n , zzn - 3 * n , z3ds , z3n ) ;
2013-08-03 20:58:30 +04:00
BARY_TRUNC ( zzds , zzn ) ;
2013-07-21 05:01:26 +04:00
MEMCPY ( zds , zzds , BDIGIT , zzn ) ;
BDIGITS_ZERO ( zds + zzn , zn - zzn ) ;
if ( work )
ALLOCV_END ( work ) ;
}
VALUE
rb_big_mul_toom3 ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , zn = xn + yn ;
VALUE z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
2013-07-22 22:35:27 +04:00
if ( xn > yn | | yn < 3 | | ! TOOM3_BALANCED ( xn , yn ) )
rb_raise ( rb_eArgError , " unexpected bignum length for toom3 " ) ;
2013-07-21 05:01:26 +04:00
bary_mul_toom3 ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn , BDIGITS ( y ) , yn , NULL , 0 ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
}
2013-08-31 16:17:18 +04:00
# ifdef USE_GMP
static void
bary_mul_gmp ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
{
const size_t nails = ( sizeof ( BDIGIT ) - SIZEOF_BDIGITS ) * CHAR_BIT ;
mpz_t x , y , z ;
size_t count ;
assert ( xn + yn < = zn ) ;
2013-09-01 17:38:49 +04:00
mpz_init ( x ) ;
mpz_init ( y ) ;
mpz_init ( z ) ;
2013-08-31 16:17:18 +04:00
mpz_import ( x , xn , - 1 , sizeof ( BDIGIT ) , 0 , nails , xds ) ;
if ( xds = = yds & & xn = = yn ) {
mpz_mul ( z , x , x ) ;
}
else {
mpz_import ( y , yn , - 1 , sizeof ( BDIGIT ) , 0 , nails , yds ) ;
mpz_mul ( z , x , y ) ;
}
2013-09-05 03:22:27 +04:00
mpz_export ( zds , & count , - 1 , sizeof ( BDIGIT ) , 0 , nails , z ) ;
2013-08-31 16:17:18 +04:00
BDIGITS_ZERO ( zds + count , zn - count ) ;
2013-09-01 17:38:49 +04:00
mpz_clear ( x ) ;
mpz_clear ( y ) ;
mpz_clear ( z ) ;
2013-08-31 16:17:18 +04:00
}
VALUE
rb_big_mul_gmp ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , zn = xn + yn ;
VALUE z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
bary_mul_gmp ( BDIGITS ( z ) , zn , BDIGITS ( x ) , xn , BDIGITS ( y ) , yn ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
}
# endif
2013-07-07 15:02:47 +04:00
static void
2013-08-24 20:51:23 +04:00
bary_short_mul ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-06-16 16:59:26 +04:00
{
2013-08-05 18:50:07 +04:00
assert ( xn + yn < = zn ) ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
if ( xn = = 1 & & yn = = 1 ) {
bary_mul_single ( zds , zn , xds [ 0 ] , yds [ 0 ] ) ;
2013-06-16 16:59:26 +04:00
}
else {
2013-08-05 18:50:07 +04:00
bary_mul_normal ( zds , zn , xds , xn , yds , yn ) ;
2013-07-07 15:02:47 +04:00
rb_thread_check_ints ( ) ;
2013-06-16 16:59:26 +04:00
}
}
2013-07-07 15:02:47 +04:00
/* determine whether a bignum is sparse or not by random sampling */
static inline int
2013-07-28 07:12:36 +04:00
bary_sparse_p ( const BDIGIT * ds , size_t n )
2013-06-07 01:20:04 +04:00
{
2013-07-07 15:02:47 +04:00
long c = 0 ;
2013-06-07 01:20:04 +04:00
2013-07-07 15:02:47 +04:00
if ( ds [ rb_genrand_ulong_limited ( n / 2 ) + n / 4 ] ) c + + ;
if ( c < = 1 & & ds [ rb_genrand_ulong_limited ( n / 2 ) + n / 4 ] ) c + + ;
if ( c < = 1 & & ds [ rb_genrand_ulong_limited ( n / 2 ) + n / 4 ] ) c + + ;
return ( c < = 1 ) ? 1 : 0 ;
2013-06-23 03:20:22 +04:00
}
2013-07-11 07:06:02 +04:00
static int
2013-08-05 18:50:07 +04:00
bary_mul_precheck ( BDIGIT * * zdsp , size_t * znp , const BDIGIT * * xdsp , size_t * xnp , const BDIGIT * * ydsp , size_t * ynp )
2013-06-07 01:20:04 +04:00
{
2013-07-07 15:02:47 +04:00
size_t nlsz ; /* number of least significant zero BDIGITs */
2013-06-07 01:20:04 +04:00
2013-07-11 07:06:02 +04:00
BDIGIT * zds = * zdsp ;
2013-08-05 18:50:07 +04:00
size_t zn = * znp ;
2013-07-28 07:12:36 +04:00
const BDIGIT * xds = * xdsp ;
2013-08-05 18:50:07 +04:00
size_t xn = * xnp ;
2013-07-28 07:12:36 +04:00
const BDIGIT * yds = * ydsp ;
2013-08-05 18:50:07 +04:00
size_t yn = * ynp ;
2013-07-11 07:06:02 +04:00
2013-08-05 18:50:07 +04:00
assert ( xn + yn < = zn ) ;
2013-06-07 01:20:04 +04:00
2013-07-07 15:02:47 +04:00
nlsz = 0 ;
2013-07-17 17:53:24 +04:00
2013-08-05 18:50:07 +04:00
while ( 0 < xn ) {
if ( xds [ xn - 1 ] = = 0 ) {
xn - - ;
2013-07-17 17:53:24 +04:00
}
else {
do {
if ( xds [ 0 ] ! = 0 )
break ;
xds + + ;
2013-08-05 18:50:07 +04:00
xn - - ;
2013-07-17 17:53:24 +04:00
nlsz + + ;
2013-08-05 18:50:07 +04:00
} while ( 0 < xn ) ;
2013-07-17 17:53:24 +04:00
break ;
}
2013-07-07 15:02:47 +04:00
}
2013-07-17 17:53:24 +04:00
2013-08-05 18:50:07 +04:00
while ( 0 < yn ) {
if ( yds [ yn - 1 ] = = 0 ) {
yn - - ;
2013-07-17 17:53:24 +04:00
}
else {
do {
if ( xds [ 0 ] ! = 0 )
break ;
yds + + ;
2013-08-05 18:50:07 +04:00
yn - - ;
2013-07-17 17:53:24 +04:00
nlsz + + ;
2013-08-05 18:50:07 +04:00
} while ( 0 < yn ) ;
2013-07-17 17:53:24 +04:00
break ;
}
2013-07-07 15:02:47 +04:00
}
2013-07-17 17:53:24 +04:00
2013-07-07 15:02:47 +04:00
if ( nlsz ) {
2013-07-18 08:00:49 +04:00
BDIGITS_ZERO ( zds , nlsz ) ;
2013-07-07 15:02:47 +04:00
zds + = nlsz ;
2013-08-05 18:50:07 +04:00
zn - = nlsz ;
2013-07-07 15:02:47 +04:00
}
2013-06-07 01:20:04 +04:00
2013-07-07 15:02:47 +04:00
/* make sure that y is longer than x */
2013-08-05 18:50:07 +04:00
if ( xn > yn ) {
2013-07-28 07:12:36 +04:00
const BDIGIT * tds ;
2013-08-05 18:50:07 +04:00
size_t tn ;
2013-07-07 15:02:47 +04:00
tds = xds ; xds = yds ; yds = tds ;
2013-08-05 18:50:07 +04:00
tn = xn ; xn = yn ; yn = tn ;
2013-07-07 15:02:47 +04:00
}
2013-08-05 18:50:07 +04:00
assert ( xn < = yn ) ;
2013-06-07 01:20:04 +04:00
2013-08-05 18:50:07 +04:00
if ( xn < = 1 ) {
if ( xn = = 0 ) {
BDIGITS_ZERO ( zds , zn ) ;
2013-07-17 17:53:24 +04:00
return 1 ;
}
2013-06-15 15:15:23 +04:00
2013-07-13 19:16:23 +04:00
if ( xds [ 0 ] = = 1 ) {
2013-08-05 18:50:07 +04:00
MEMCPY ( zds , yds , BDIGIT , yn ) ;
BDIGITS_ZERO ( zds + yn , zn - yn ) ;
2013-07-13 19:16:23 +04:00
return 1 ;
}
if ( POW2_P ( xds [ 0 ] ) ) {
2013-08-31 22:34:42 +04:00
zds [ yn ] = bary_small_lshift ( zds , yds , yn , bit_length ( xds [ 0 ] ) - 1 ) ;
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds + yn + 1 , zn - yn - 1 ) ;
2013-07-13 19:16:23 +04:00
return 1 ;
}
2013-08-05 18:50:07 +04:00
if ( yn = = 1 & & yds [ 0 ] = = 1 ) {
2013-07-13 19:16:23 +04:00
zds [ 0 ] = xds [ 0 ] ;
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( zds + 1 , zn - 1 ) ;
2013-07-13 19:16:23 +04:00
return 1 ;
}
2013-08-05 18:50:07 +04:00
bary_mul_normal ( zds , zn , xds , xn , yds , yn ) ;
2013-07-11 07:06:02 +04:00
return 1 ;
2013-07-09 19:43:48 +04:00
}
2013-07-11 07:06:02 +04:00
* zdsp = zds ;
2013-08-05 18:50:07 +04:00
* znp = zn ;
2013-07-11 07:06:02 +04:00
* xdsp = xds ;
2013-08-05 18:50:07 +04:00
* xnp = xn ;
2013-07-11 07:06:02 +04:00
* ydsp = yds ;
2013-08-05 18:50:07 +04:00
* ynp = yn ;
2013-07-11 07:06:02 +04:00
return 0 ;
}
static void
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_branch ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-11 07:06:02 +04:00
{
2013-07-07 15:02:47 +04:00
/* normal multiplication when x is small */
2013-08-05 18:50:07 +04:00
if ( xn < KARATSUBA_MUL_DIGITS ) {
2013-07-07 15:02:47 +04:00
normal :
2013-08-05 18:50:07 +04:00
if ( xds = = yds & & xn = = yn )
bary_sq_fast ( zds , zn , xds , xn ) ;
2013-07-07 15:02:47 +04:00
else
2013-08-24 20:51:23 +04:00
bary_short_mul ( zds , zn , xds , xn , yds , yn ) ;
2013-07-07 15:02:47 +04:00
return ;
}
2013-06-15 15:15:23 +04:00
2013-07-07 15:02:47 +04:00
/* normal multiplication when x or y is a sparse bignum */
2013-08-05 18:50:07 +04:00
if ( bary_sparse_p ( xds , xn ) ) goto normal ;
if ( bary_sparse_p ( yds , yn ) ) {
2013-08-24 20:51:23 +04:00
bary_short_mul ( zds , zn , yds , yn , xds , xn ) ;
2013-07-07 15:02:47 +04:00
return ;
2013-06-15 15:15:23 +04:00
}
2013-07-07 15:02:47 +04:00
/* balance multiplication by slicing y when x is much smaller than y */
2013-08-05 18:50:07 +04:00
if ( ! KARATSUBA_BALANCED ( xn , yn ) ) {
bary_mul_balance_with_mulfunc ( zds , zn , xds , xn , yds , yn , wds , wn , bary_mul_karatsuba_start ) ;
2013-07-07 15:02:47 +04:00
return ;
2013-06-20 17:05:27 +04:00
}
2013-07-07 15:02:47 +04:00
2013-07-11 07:06:02 +04:00
/* multiplication by karatsuba method */
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba ( zds , zn , xds , xn , yds , yn , wds , wn ) ;
2013-07-11 07:06:02 +04:00
}
static void
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_start ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-11 07:06:02 +04:00
{
2013-08-05 18:50:07 +04:00
if ( bary_mul_precheck ( & zds , & zn , & xds , & xn , & yds , & yn ) )
2013-07-11 07:06:02 +04:00
return ;
2013-08-05 18:50:07 +04:00
bary_mul_karatsuba_branch ( zds , zn , xds , xn , yds , yn , wds , wn ) ;
2013-07-11 07:06:02 +04:00
}
static void
2013-08-05 18:50:07 +04:00
bary_mul_toom3_branch ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-11 07:06:02 +04:00
{
2013-08-05 18:50:07 +04:00
if ( xn < TOOM3_MUL_DIGITS ) {
bary_mul_karatsuba_branch ( zds , zn , xds , xn , yds , yn , wds , wn ) ;
2013-07-07 15:02:47 +04:00
return ;
2013-06-16 16:59:26 +04:00
}
2013-06-07 01:20:04 +04:00
2013-08-05 18:50:07 +04:00
if ( ! TOOM3_BALANCED ( xn , yn ) ) {
bary_mul_balance_with_mulfunc ( zds , zn , xds , xn , yds , yn , wds , wn , bary_mul_toom3_start ) ;
2013-07-07 15:02:47 +04:00
return ;
}
2013-08-05 18:50:07 +04:00
bary_mul_toom3 ( zds , zn , xds , xn , yds , yn , wds , wn ) ;
2013-06-07 01:20:04 +04:00
}
2013-07-11 07:06:02 +04:00
static void
2013-08-05 18:50:07 +04:00
bary_mul_toom3_start ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn , BDIGIT * wds , size_t wn )
2013-07-11 07:06:02 +04:00
{
2013-08-05 18:50:07 +04:00
if ( bary_mul_precheck ( & zds , & zn , & xds , & xn , & yds , & yn ) )
2013-07-11 07:06:02 +04:00
return ;
2013-08-05 18:50:07 +04:00
bary_mul_toom3_branch ( zds , zn , xds , xn , yds , yn , wds , wn ) ;
2013-07-11 07:06:02 +04:00
}
static void
2013-08-05 18:50:07 +04:00
bary_mul ( BDIGIT * zds , size_t zn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-07-11 07:06:02 +04:00
{
2013-08-31 16:17:18 +04:00
# ifdef USE_GMP
const size_t naive_threshold = GMP_MUL_DIGITS ;
# else
const size_t naive_threshold = KARATSUBA_MUL_DIGITS ;
# endif
2013-08-05 18:50:07 +04:00
if ( xn < = yn ) {
2013-08-31 16:17:18 +04:00
if ( xn < naive_threshold ) {
2013-08-05 18:50:07 +04:00
if ( xds = = yds & & xn = = yn )
bary_sq_fast ( zds , zn , xds , xn ) ;
2013-08-02 07:28:33 +04:00
else
2013-08-24 20:51:23 +04:00
bary_short_mul ( zds , zn , xds , xn , yds , yn ) ;
2013-08-02 07:28:33 +04:00
return ;
}
}
else {
2013-08-31 16:17:18 +04:00
if ( yn < naive_threshold ) {
2013-08-24 20:51:23 +04:00
bary_short_mul ( zds , zn , yds , yn , xds , xn ) ;
2013-08-02 07:28:33 +04:00
return ;
}
2013-07-17 17:53:24 +04:00
}
2013-08-31 16:17:18 +04:00
# ifdef USE_GMP
bary_mul_gmp ( zds , zn , xds , xn , yds , yn ) ;
# else
2013-08-05 18:50:07 +04:00
bary_mul_toom3_start ( zds , zn , xds , xn , yds , yn , NULL , 0 ) ;
2013-08-31 16:17:18 +04:00
# endif
2013-07-11 07:06:02 +04:00
}
2013-07-23 15:49:25 +04:00
struct big_div_struct {
2013-08-13 19:21:42 +04:00
size_t yn , zn ;
2013-07-23 15:49:25 +04:00
BDIGIT * yds , * zds ;
volatile VALUE stop ;
} ;
static void *
bigdivrem1 ( void * ptr )
{
struct big_div_struct * bds = ( struct big_div_struct * ) ptr ;
2013-08-09 23:55:24 +04:00
size_t yn = bds - > yn ;
2013-08-13 19:21:42 +04:00
size_t zn = bds - > zn ;
2013-07-23 15:49:25 +04:00
BDIGIT * yds = bds - > yds , * zds = bds - > zds ;
BDIGIT_DBL_SIGNED num ;
BDIGIT q ;
do {
if ( bds - > stop ) {
2013-08-13 19:21:42 +04:00
bds - > zn = zn ;
2013-07-23 15:49:25 +04:00
return 0 ;
}
2013-08-13 19:21:42 +04:00
if ( zds [ zn - 1 ] = = yds [ yn - 1 ] ) q = BDIGMAX ;
else q = ( BDIGIT ) ( ( BIGUP ( zds [ zn - 1 ] ) + zds [ zn - 2 ] ) / yds [ yn - 1 ] ) ;
2013-07-23 15:49:25 +04:00
if ( q ) {
2013-08-13 19:21:42 +04:00
num = bigdivrem_mulsub ( zds + zn - ( yn + 1 ) , yn + 1 ,
2013-07-23 15:49:25 +04:00
q ,
2013-08-13 18:43:10 +04:00
yds , yn ) ;
2013-07-23 15:49:25 +04:00
while ( num ) { /* "add back" required */
q - - ;
2013-08-13 19:21:42 +04:00
num = bary_add ( zds + zn - ( yn + 1 ) , yn ,
zds + zn - ( yn + 1 ) , yn ,
2013-08-13 18:43:10 +04:00
yds , yn ) ;
2013-07-23 15:49:25 +04:00
num - - ;
}
}
2013-08-13 19:21:42 +04:00
zn - - ;
zds [ zn ] = q ;
} while ( zn > yn ) ;
2013-07-23 15:49:25 +04:00
return 0 ;
}
static void
rb_big_stop ( void * ptr )
{
struct big_div_struct * bds = ptr ;
bds - > stop = Qtrue ;
}
static BDIGIT
2013-08-16 05:11:18 +04:00
bigdivrem_single1 ( BDIGIT * qds , const BDIGIT * xds , size_t xn , BDIGIT x_higher_bdigit , BDIGIT y )
2013-07-23 15:49:25 +04:00
{
2013-08-15 20:47:08 +04:00
assert ( 0 < xn ) ;
2013-08-16 05:11:18 +04:00
assert ( x_higher_bdigit < y ) ;
2013-08-15 20:47:08 +04:00
if ( POW2_P ( y ) ) {
BDIGIT r ;
r = xds [ 0 ] & ( y - 1 ) ;
2013-08-31 22:34:42 +04:00
bary_small_rshift ( qds , xds , xn , bit_length ( y ) - 1 , x_higher_bdigit ) ;
2013-08-15 20:47:08 +04:00
return r ;
}
else {
size_t i ;
BDIGIT_DBL t2 ;
2013-08-16 05:11:18 +04:00
t2 = x_higher_bdigit ;
2013-08-15 20:47:08 +04:00
i = xn ;
while ( i - - ) {
t2 = BIGUP ( t2 ) + xds [ i ] ;
qds [ i ] = ( BDIGIT ) ( t2 / y ) ;
t2 % = y ;
}
return ( BDIGIT ) t2 ;
2013-07-23 15:49:25 +04:00
}
}
2013-08-16 05:11:18 +04:00
static BDIGIT
bigdivrem_single ( BDIGIT * qds , const BDIGIT * xds , size_t xn , BDIGIT y )
{
return bigdivrem_single1 ( qds , xds , xn , 0 , y ) ;
}
2013-07-23 15:49:25 +04:00
static void
2013-08-13 19:54:27 +04:00
bigdivrem_restoring ( BDIGIT * zds , size_t zn , BDIGIT * yds , size_t yn )
2013-07-23 15:49:25 +04:00
{
struct big_div_struct bds ;
2013-08-13 18:43:10 +04:00
size_t ynzero ;
2013-07-23 15:49:25 +04:00
2013-08-17 19:48:44 +04:00
assert ( yn < zn ) ;
2013-08-13 18:03:55 +04:00
assert ( BDIGIT_MSB ( yds [ yn - 1 ] ) ) ;
2013-08-16 05:11:18 +04:00
assert ( zds [ zn - 1 ] < yds [ yn - 1 ] ) ;
2013-07-23 15:49:25 +04:00
2013-08-13 18:43:10 +04:00
for ( ynzero = 0 ; ! yds [ ynzero ] ; ynzero + + ) ;
2013-08-15 20:16:08 +04:00
if ( ynzero + 1 = = yn ) {
BDIGIT r ;
2013-08-16 05:11:18 +04:00
r = bigdivrem_single1 ( zds + yn , zds + ynzero , zn - yn , zds [ zn - 1 ] , yds [ ynzero ] ) ;
zds [ ynzero ] = r ;
2013-08-15 20:16:08 +04:00
return ;
}
2013-08-13 18:43:10 +04:00
bds . yn = yn - ynzero ;
bds . zds = zds + ynzero ;
bds . yds = yds + ynzero ;
2013-07-23 15:49:25 +04:00
bds . stop = Qfalse ;
2013-08-13 19:21:42 +04:00
bds . zn = zn - ynzero ;
2013-08-13 19:54:27 +04:00
if ( bds . zn > 10000 | | bds . yn > 10000 ) {
2013-07-23 15:49:25 +04:00
retry :
bds . stop = Qfalse ;
rb_thread_call_without_gvl ( bigdivrem1 , & bds , rb_big_stop , & bds ) ;
if ( bds . stop = = Qtrue ) {
/* execute trap handler, but exception was not raised. */
goto retry ;
}
}
else {
bigdivrem1 ( & bds ) ;
}
2013-08-13 18:03:55 +04:00
}
static void
2013-09-04 19:10:48 +04:00
bary_divmod_normal ( BDIGIT * qds , size_t qn , BDIGIT * rds , size_t rn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-08-13 18:03:55 +04:00
{
int shift ;
2013-09-04 19:10:48 +04:00
BDIGIT * zds , * yyds ;
size_t zn ;
2013-09-05 01:23:21 +04:00
VALUE tmpyz = 0 ;
2013-08-13 18:03:55 +04:00
2013-09-04 20:10:06 +04:00
assert ( yn < xn | | ( xn = = yn & & yds [ yn - 1 ] < = xds [ xn - 1 ] ) ) ;
2013-09-04 19:10:48 +04:00
assert ( qds ? ( xn - yn + 1 ) < = qn : 1 ) ;
assert ( rds ? yn < = rn : 1 ) ;
zn = xn + BIGDIVREM_EXTRA_WORDS ;
2013-09-04 15:23:05 +04:00
2013-08-15 19:01:38 +04:00
shift = nlz ( yds [ yn - 1 ] ) ;
2013-08-13 18:03:55 +04:00
if ( shift ) {
2013-09-05 01:23:21 +04:00
int alloc_y = ! rds ;
int alloc_z = ! qds | | qn < zn ;
if ( alloc_y & & alloc_z ) {
yyds = ALLOCV_N ( BDIGIT , tmpyz , yn + zn ) ;
zds = yyds + yn ;
}
else {
yyds = alloc_y ? ALLOCV_N ( BDIGIT , tmpyz , yn ) : rds ;
zds = alloc_z ? ALLOCV_N ( BDIGIT , tmpyz , zn ) : qds ;
}
2013-08-13 18:03:55 +04:00
zds [ xn ] = bary_small_lshift ( zds , xds , xn , shift ) ;
2013-09-04 19:10:48 +04:00
bary_small_lshift ( yyds , yds , yn , shift ) ;
2013-08-13 18:03:55 +04:00
}
else {
2013-09-04 19:10:48 +04:00
if ( qds & & zn < = qn )
zds = qds ;
else
2013-09-05 01:23:21 +04:00
zds = ALLOCV_N ( BDIGIT , tmpyz , zn ) ;
2013-08-13 18:03:55 +04:00
MEMCPY ( zds , xds , BDIGIT , xn ) ;
2013-09-04 19:10:48 +04:00
zds [ xn ] = 0 ;
/* bigdivrem_restoring will not modify y.
* So use yds directly . */
yyds = ( BDIGIT * ) yds ;
2013-08-13 18:03:55 +04:00
}
2013-09-04 19:10:48 +04:00
bigdivrem_restoring ( zds , zn , yyds , yn ) ;
if ( rds ) {
if ( shift )
bary_small_rshift ( rds , zds , yn , shift , 0 ) ;
else
MEMCPY ( rds , zds , BDIGIT , yn ) ;
BDIGITS_ZERO ( rds + yn , rn - yn ) ;
}
2013-07-23 15:49:25 +04:00
2013-09-04 19:10:48 +04:00
if ( qds ) {
size_t j = zn - yn ;
MEMMOVE ( qds , zds + yn , BDIGIT , j ) ;
BDIGITS_ZERO ( qds + j , qn - j ) ;
2013-07-23 15:49:25 +04:00
}
2013-09-04 19:10:48 +04:00
2013-09-05 01:23:21 +04:00
if ( tmpyz )
ALLOCV_END ( tmpyz ) ;
2013-07-23 15:49:25 +04:00
}
2013-09-04 20:10:06 +04:00
VALUE
rb_big_divrem_normal ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , qn , rn ;
BDIGIT * xds = BDIGITS ( x ) , * yds = BDIGITS ( y ) , * qds , * rds ;
VALUE q , r ;
BARY_TRUNC ( yds , yn ) ;
if ( yn = = 0 )
rb_num_zerodiv ( ) ;
BARY_TRUNC ( xds , xn ) ;
if ( xn < yn | | ( xn = = yn & & xds [ xn - 1 ] < yds [ yn - 1 ] ) )
return rb_assoc_new ( LONG2FIX ( 0 ) , x ) ;
qn = xn + BIGDIVREM_EXTRA_WORDS ;
q = bignew ( qn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
qds = BDIGITS ( q ) ;
rn = yn ;
r = bignew ( rn , RBIGNUM_SIGN ( x ) ) ;
rds = BDIGITS ( r ) ;
bary_divmod_normal ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
bigtrunc ( q ) ;
bigtrunc ( r ) ;
2013-09-04 21:21:43 +04:00
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
2013-09-04 20:10:06 +04:00
return rb_assoc_new ( q , r ) ;
}
2013-09-05 03:22:27 +04:00
# ifdef USE_GMP
static void
bary_divmod_gmp ( BDIGIT * qds , size_t qn , BDIGIT * rds , size_t rn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
{
const size_t nails = ( sizeof ( BDIGIT ) - SIZEOF_BDIGITS ) * CHAR_BIT ;
mpz_t x , y , q , r ;
size_t count ;
assert ( yn < xn | | ( xn = = yn & & yds [ yn - 1 ] < = xds [ xn - 1 ] ) ) ;
assert ( qds ? ( xn - yn + 1 ) < = qn : 1 ) ;
assert ( rds ? yn < = rn : 1 ) ;
assert ( qds | | rds ) ;
mpz_init ( x ) ;
mpz_init ( y ) ;
if ( qds ) mpz_init ( q ) ;
if ( rds ) mpz_init ( r ) ;
mpz_import ( x , xn , - 1 , sizeof ( BDIGIT ) , 0 , nails , xds ) ;
mpz_import ( y , yn , - 1 , sizeof ( BDIGIT ) , 0 , nails , yds ) ;
if ( ! rds ) {
mpz_fdiv_q ( q , x , y ) ;
}
else if ( ! qds ) {
mpz_fdiv_r ( r , x , y ) ;
}
else {
mpz_fdiv_qr ( q , r , x , y ) ;
}
mpz_clear ( x ) ;
mpz_clear ( y ) ;
if ( qds ) {
mpz_export ( qds , & count , - 1 , sizeof ( BDIGIT ) , 0 , nails , q ) ;
BDIGITS_ZERO ( qds + count , qn - count ) ;
mpz_clear ( q ) ;
}
if ( rds ) {
mpz_export ( rds , & count , - 1 , sizeof ( BDIGIT ) , 0 , nails , r ) ;
BDIGITS_ZERO ( rds + count , rn - count ) ;
mpz_clear ( r ) ;
}
}
VALUE
rb_big_divrem_gmp ( VALUE x , VALUE y )
{
size_t xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) , qn , rn ;
BDIGIT * xds = BDIGITS ( x ) , * yds = BDIGITS ( y ) , * qds , * rds ;
VALUE q , r ;
BARY_TRUNC ( yds , yn ) ;
if ( yn = = 0 )
rb_num_zerodiv ( ) ;
BARY_TRUNC ( xds , xn ) ;
if ( xn < yn | | ( xn = = yn & & xds [ xn - 1 ] < yds [ yn - 1 ] ) )
return rb_assoc_new ( LONG2FIX ( 0 ) , x ) ;
qn = xn - yn + 1 ;
q = bignew ( qn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
qds = BDIGITS ( q ) ;
rn = yn ;
r = bignew ( rn , RBIGNUM_SIGN ( x ) ) ;
rds = BDIGITS ( r ) ;
bary_divmod_gmp ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
bigtrunc ( q ) ;
bigtrunc ( r ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return rb_assoc_new ( q , r ) ;
}
# endif
static void
bary_divmod_branch ( BDIGIT * qds , size_t qn , BDIGIT * rds , size_t rn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
{
# ifdef USE_GMP
if ( GMP_DIV_DIGITS < xn ) {
bary_divmod_gmp ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
return ;
}
# endif
bary_divmod_normal ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
}
2013-07-23 15:49:25 +04:00
static void
2013-08-05 18:50:07 +04:00
bary_divmod ( BDIGIT * qds , size_t qn , BDIGIT * rds , size_t rn , const BDIGIT * xds , size_t xn , const BDIGIT * yds , size_t yn )
2013-07-23 15:49:25 +04:00
{
2013-08-05 18:50:07 +04:00
assert ( xn < = qn ) ;
assert ( yn < = rn ) ;
2013-07-23 15:49:25 +04:00
2013-08-05 18:50:07 +04:00
BARY_TRUNC ( yds , yn ) ;
if ( yn = = 0 )
2013-07-23 15:49:25 +04:00
rb_num_zerodiv ( ) ;
2013-08-05 18:50:07 +04:00
BARY_TRUNC ( xds , xn ) ;
if ( xn = = 0 ) {
BDIGITS_ZERO ( qds , qn ) ;
BDIGITS_ZERO ( rds , rn ) ;
2013-07-23 15:49:25 +04:00
return ;
}
2013-08-05 18:50:07 +04:00
if ( xn < yn | | ( xn = = yn & & xds [ xn - 1 ] < yds [ yn - 1 ] ) ) {
MEMCPY ( rds , xds , BDIGIT , xn ) ;
BDIGITS_ZERO ( rds + xn , rn - xn ) ;
BDIGITS_ZERO ( qds , qn ) ;
2013-07-23 15:49:25 +04:00
}
2013-08-05 18:50:07 +04:00
else if ( yn = = 1 ) {
MEMCPY ( qds , xds , BDIGIT , xn ) ;
BDIGITS_ZERO ( qds + xn , qn - xn ) ;
rds [ 0 ] = bigdivrem_single ( qds , xds , xn , yds [ 0 ] ) ;
BDIGITS_ZERO ( rds + 1 , rn - 1 ) ;
2013-07-23 15:49:25 +04:00
}
2013-08-05 18:50:07 +04:00
else if ( xn = = 2 & & yn = = 2 ) {
2013-08-03 19:26:04 +04:00
BDIGIT_DBL x = bary2bdigitdbl ( xds , 2 ) ;
BDIGIT_DBL y = bary2bdigitdbl ( yds , 2 ) ;
2013-07-23 15:49:25 +04:00
BDIGIT_DBL q = x / y ;
BDIGIT_DBL r = x % y ;
qds [ 0 ] = BIGLO ( q ) ;
qds [ 1 ] = BIGLO ( BIGDN ( q ) ) ;
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( qds + 2 , qn - 2 ) ;
2013-07-23 15:49:25 +04:00
rds [ 0 ] = BIGLO ( r ) ;
rds [ 1 ] = BIGLO ( BIGDN ( r ) ) ;
2013-08-05 18:50:07 +04:00
BDIGITS_ZERO ( rds + 2 , rn - 2 ) ;
2013-07-23 15:49:25 +04:00
}
else {
2013-09-05 03:22:27 +04:00
bary_divmod_branch ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
2013-07-23 15:49:25 +04:00
}
}
2013-07-07 15:02:47 +04:00
# define BIGNUM_DEBUG 0
# if BIGNUM_DEBUG
# define ON_DEBUG(x) do { x; } while (0)
2013-06-16 16:59:26 +04:00
static void
2013-07-07 15:02:47 +04:00
dump_bignum ( VALUE x )
2013-06-12 19:18:00 +04:00
{
2013-07-07 15:02:47 +04:00
long i ;
printf ( " %c0x0 " , RBIGNUM_SIGN ( x ) ? ' + ' : ' - ' ) ;
for ( i = RBIGNUM_LEN ( x ) ; i - - ; ) {
printf ( " _%0* " PRIxBDIGIT , SIZEOF_BDIGITS * 2 , BDIGITS ( x ) [ i ] ) ;
}
printf ( " , len=%lu " , RBIGNUM_LEN ( x ) ) ;
puts ( " " ) ;
}
2013-06-12 19:18:00 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
rb_big_dump ( VALUE x )
{
dump_bignum ( x ) ;
return x ;
}
# else
# define ON_DEBUG(x)
# endif
2013-06-12 19:18:00 +04:00
2013-07-07 15:02:47 +04:00
static int
bigzero_p ( VALUE x )
{
return bary_zero_p ( BDIGITS ( x ) , RBIGNUM_LEN ( x ) ) ;
}
2013-06-16 16:59:26 +04:00
2013-07-07 15:02:47 +04:00
int
rb_bigzero_p ( VALUE x )
{
return BIGZEROP ( x ) ;
}
2013-06-20 17:05:27 +04:00
2013-07-07 15:02:47 +04:00
int
rb_cmpint ( VALUE val , VALUE a , VALUE b )
{
if ( NIL_P ( val ) ) {
rb_cmperr ( a , b ) ;
}
if ( FIXNUM_P ( val ) ) {
long l = FIX2LONG ( val ) ;
if ( l > 0 ) return 1 ;
if ( l < 0 ) return - 1 ;
return 0 ;
}
2013-09-07 23:04:23 +04:00
if ( RB_BIGNUM_TYPE_P ( val ) ) {
2013-07-07 15:02:47 +04:00
if ( BIGZEROP ( val ) ) return 0 ;
if ( RBIGNUM_SIGN ( val ) ) return 1 ;
return - 1 ;
2013-06-20 17:05:27 +04:00
}
2013-07-07 15:02:47 +04:00
if ( RTEST ( rb_funcall ( val , ' > ' , 1 , INT2FIX ( 0 ) ) ) ) return 1 ;
if ( RTEST ( rb_funcall ( val , ' < ' , 1 , INT2FIX ( 0 ) ) ) ) return - 1 ;
return 0 ;
2013-06-12 19:18:00 +04:00
}
2013-07-07 15:02:47 +04:00
# define RBIGNUM_SET_LEN(b,l) \
( ( RBASIC ( b ) - > flags & RBIGNUM_EMBED_FLAG ) ? \
( void ) ( RBASIC ( b ) - > flags = \
( RBASIC ( b ) - > flags & ~ RBIGNUM_EMBED_LEN_MASK ) | \
( ( l ) < < RBIGNUM_EMBED_LEN_SHIFT ) ) : \
( void ) ( RBIGNUM ( b ) - > as . heap . len = ( l ) ) )
2013-06-16 16:59:26 +04:00
2013-07-07 15:02:47 +04:00
static void
rb_big_realloc ( VALUE big , long len )
2013-06-12 19:18:00 +04:00
{
2013-06-16 16:59:26 +04:00
BDIGIT * ds ;
2013-07-07 15:02:47 +04:00
if ( RBASIC ( big ) - > flags & RBIGNUM_EMBED_FLAG ) {
if ( RBIGNUM_EMBED_LEN_MAX < len ) {
ds = ALLOC_N ( BDIGIT , len ) ;
MEMCPY ( ds , RBIGNUM ( big ) - > as . ary , BDIGIT , RBIGNUM_EMBED_LEN_MAX ) ;
RBIGNUM ( big ) - > as . heap . len = RBIGNUM_LEN ( big ) ;
RBIGNUM ( big ) - > as . heap . digits = ds ;
RBASIC ( big ) - > flags & = ~ RBIGNUM_EMBED_FLAG ;
}
}
else {
if ( len < = RBIGNUM_EMBED_LEN_MAX ) {
ds = RBIGNUM ( big ) - > as . heap . digits ;
RBASIC ( big ) - > flags | = RBIGNUM_EMBED_FLAG ;
RBIGNUM_SET_LEN ( big , len ) ;
2013-08-06 07:26:34 +04:00
( void ) VALGRIND_MAKE_MEM_UNDEFINED ( ( void * ) RBIGNUM ( big ) - > as . ary , sizeof ( RBIGNUM ( big ) - > as . ary ) ) ;
2013-07-07 15:02:47 +04:00
if ( ds ) {
MEMCPY ( RBIGNUM ( big ) - > as . ary , ds , BDIGIT , len ) ;
xfree ( ds ) ;
}
}
else {
if ( RBIGNUM_LEN ( big ) = = 0 ) {
RBIGNUM ( big ) - > as . heap . digits = ALLOC_N ( BDIGIT , len ) ;
}
else {
REALLOC_N ( RBIGNUM ( big ) - > as . heap . digits , BDIGIT , len ) ;
}
}
}
}
2013-06-12 19:18:00 +04:00
2013-07-07 15:02:47 +04:00
void
rb_big_resize ( VALUE big , long len )
{
rb_big_realloc ( big , len ) ;
RBIGNUM_SET_LEN ( big , len ) ;
}
2013-06-12 19:18:00 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
bignew_1 ( VALUE klass , long len , int sign )
{
NEWOBJ_OF ( big , struct RBignum , klass , T_BIGNUM | ( RGENGC_WB_PROTECTED_BIGNUM ? FL_WB_PROTECTED : 0 ) ) ;
RBIGNUM_SET_SIGN ( big , sign ? 1 : 0 ) ;
if ( len < = RBIGNUM_EMBED_LEN_MAX ) {
RBASIC ( big ) - > flags | = RBIGNUM_EMBED_FLAG ;
RBIGNUM_SET_LEN ( big , len ) ;
2013-08-06 07:26:34 +04:00
( void ) VALGRIND_MAKE_MEM_UNDEFINED ( ( void * ) RBIGNUM ( big ) - > as . ary , sizeof ( RBIGNUM ( big ) - > as . ary ) ) ;
2013-06-22 16:48:45 +04:00
}
else {
2013-07-07 15:02:47 +04:00
RBIGNUM ( big ) - > as . heap . digits = ALLOC_N ( BDIGIT , len ) ;
RBIGNUM ( big ) - > as . heap . len = len ;
2013-06-12 19:18:00 +04:00
}
2013-07-07 15:02:47 +04:00
OBJ_FREEZE ( big ) ;
return ( VALUE ) big ;
}
2013-06-22 16:48:45 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big_new ( long len , int sign )
{
return bignew ( len , sign ! = 0 ) ;
}
2013-06-22 16:48:45 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big_clone ( VALUE x )
{
long len = RBIGNUM_LEN ( x ) ;
VALUE z = bignew_1 ( CLASS_OF ( x ) , len , RBIGNUM_SIGN ( x ) ) ;
2013-06-12 19:18:00 +04:00
2013-07-07 15:02:47 +04:00
MEMCPY ( BDIGITS ( z ) , BDIGITS ( x ) , BDIGIT , len ) ;
return z ;
2013-06-12 19:18:00 +04:00
}
2013-07-07 15:02:47 +04:00
static void
big_extend_carry ( VALUE x )
2002-02-13 12:01:11 +03:00
{
2013-07-07 15:02:47 +04:00
rb_big_resize ( x , RBIGNUM_LEN ( x ) + 1 ) ;
BDIGITS ( x ) [ RBIGNUM_LEN ( x ) - 1 ] = 1 ;
2002-02-13 12:01:11 +03:00
}
2013-07-07 15:02:47 +04:00
/* modify a bignum by 2's complement */
static void
get2comp ( VALUE x )
2002-02-13 12:01:11 +03:00
{
2013-07-07 15:02:47 +04:00
long i = RBIGNUM_LEN ( x ) ;
BDIGIT * ds = BDIGITS ( x ) ;
if ( bary_2comp ( ds , i ) ) {
big_extend_carry ( x ) ;
}
2002-02-13 12:01:11 +03:00
}
2013-07-07 15:02:47 +04:00
void
rb_big_2comp ( VALUE x ) /* get 2's complement */
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
get2comp ( x ) ;
}
2013-07-04 13:38:11 +04:00
2013-07-07 15:02:47 +04:00
static BDIGIT
abs2twocomp ( VALUE * xp , long * n_ret )
{
VALUE x = * xp ;
long n = RBIGNUM_LEN ( x ) ;
BDIGIT * ds = BDIGITS ( x ) ;
BDIGIT hibits = 0 ;
2013-06-30 17:16:08 +04:00
2013-08-03 20:58:30 +04:00
BARY_TRUNC ( ds , n ) ;
2007-07-15 14:05:37 +04:00
2013-07-07 15:02:47 +04:00
if ( n ! = 0 & & RBIGNUM_NEGATIVE_P ( x ) ) {
VALUE z = bignew_1 ( CLASS_OF ( x ) , n , 0 ) ;
MEMCPY ( BDIGITS ( z ) , ds , BDIGIT , n ) ;
bary_2comp ( BDIGITS ( z ) , n ) ;
hibits = BDIGMAX ;
* xp = z ;
2002-10-17 11:27:00 +04:00
}
2013-07-07 15:02:47 +04:00
* n_ret = n ;
return hibits ;
}
1999-01-20 07:59:39 +03:00
2013-07-07 15:02:47 +04:00
static void
twocomp2abs_bang ( VALUE x , int hibits )
{
RBIGNUM_SET_SIGN ( x , ! hibits ) ;
if ( hibits ) {
get2comp ( x ) ;
2013-06-30 17:16:08 +04:00
}
2013-07-07 15:02:47 +04:00
}
static inline VALUE
bigtrunc ( VALUE x )
{
long len = RBIGNUM_LEN ( x ) ;
BDIGIT * ds = BDIGITS ( x ) ;
if ( len = = 0 ) return x ;
while ( - - len & & ! ds [ len ] ) ;
if ( RBIGNUM_LEN ( x ) > len + 1 ) {
rb_big_resize ( x , len + 1 ) ;
2013-06-30 17:16:08 +04:00
}
2013-07-07 15:02:47 +04:00
return x ;
}
static inline VALUE
bigfixize ( VALUE x )
{
2013-08-05 18:50:07 +04:00
size_t n = RBIGNUM_LEN ( x ) ;
2013-07-07 15:02:47 +04:00
BDIGIT * ds = BDIGITS ( x ) ;
2013-07-17 17:53:24 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
unsigned long u ;
# else
BDIGIT u ;
# endif
2013-08-05 18:50:07 +04:00
BARY_TRUNC ( ds , n ) ;
2013-07-07 15:02:47 +04:00
2013-08-05 18:50:07 +04:00
if ( n = = 0 ) return INT2FIX ( 0 ) ;
2013-07-17 17:53:24 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
2013-08-05 18:50:07 +04:00
if ( sizeof ( long ) / SIZEOF_BDIGITS < n )
2013-07-17 17:53:24 +04:00
goto return_big ;
else {
2013-08-05 18:50:07 +04:00
int i = ( int ) n ;
2013-07-17 17:53:24 +04:00
u = 0 ;
while ( i - - ) {
2013-07-18 16:58:46 +04:00
u = ( unsigned long ) ( BIGUP ( u ) + ds [ i ] ) ;
2013-07-17 17:53:24 +04:00
}
}
# else /* SIZEOF_BDIGITS >= SIZEOF_LONG */
2013-08-05 18:50:07 +04:00
if ( 1 < n )
2013-07-17 17:53:24 +04:00
goto return_big ;
else
u = ds [ 0 ] ;
2013-07-07 15:02:47 +04:00
# endif
2013-07-17 17:53:24 +04:00
if ( RBIGNUM_POSITIVE_P ( x ) ) {
if ( POSFIXABLE ( u ) ) return LONG2FIX ( ( long ) u ) ;
2007-07-15 14:05:37 +04:00
}
2013-07-17 17:53:24 +04:00
else {
if ( u < = - FIXNUM_MIN ) return LONG2FIX ( - ( long ) u ) ;
}
return_big :
2013-08-05 18:50:07 +04:00
rb_big_resize ( x , n ) ;
2013-07-07 15:02:47 +04:00
return x ;
}
static VALUE
bignorm ( VALUE x )
{
2013-09-07 23:04:23 +04:00
if ( RB_BIGNUM_TYPE_P ( x ) ) {
2013-07-07 15:02:47 +04:00
x = bigfixize ( x ) ;
2003-01-18 08:53:53 +03:00
}
2013-07-07 15:02:47 +04:00
return x ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big_norm ( VALUE x )
{
return bignorm ( x ) ;
}
2000-01-05 07:41:21 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_uint2big ( VALUE n )
{
long i ;
VALUE big = bignew ( bdigit_roomof ( SIZEOF_VALUE ) , 1 ) ;
BDIGIT * digits = BDIGITS ( big ) ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_VALUE
digits [ 0 ] = n ;
# else
for ( i = 0 ; i < bdigit_roomof ( SIZEOF_VALUE ) ; i + + ) {
digits [ i ] = BIGLO ( n ) ;
n = BIGDN ( n ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
# endif
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
i = bdigit_roomof ( SIZEOF_VALUE ) ;
while ( - - i & & ! digits [ i ] ) ;
RBIGNUM_SET_LEN ( big , i + 1 ) ;
return big ;
}
VALUE
rb_int2big ( SIGNED_VALUE n )
{
long neg = 0 ;
VALUE u ;
VALUE big ;
if ( n < 0 ) {
u = 1 + ( VALUE ) ( - ( n + 1 ) ) ; /* u = -n avoiding overflow */
neg = 1 ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
else {
u = n ;
}
big = rb_uint2big ( u ) ;
if ( neg ) {
RBIGNUM_SET_SIGN ( big , 0 ) ;
2000-12-25 09:29:27 +03:00
}
2013-07-07 15:02:47 +04:00
return big ;
}
2000-01-05 07:41:21 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_uint2inum ( VALUE n )
{
if ( POSFIXABLE ( n ) ) return LONG2FIX ( n ) ;
return rb_uint2big ( n ) ;
}
VALUE
rb_int2inum ( SIGNED_VALUE n )
{
if ( FIXABLE ( n ) ) return LONG2FIX ( n ) ;
return rb_int2big ( n ) ;
}
void
rb_big_pack ( VALUE val , unsigned long * buf , long num_longs )
{
rb_integer_pack ( val , buf , num_longs , sizeof ( long ) , 0 ,
INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP ) ;
}
VALUE
rb_big_unpack ( unsigned long * buf , long num_longs )
{
return rb_integer_unpack ( buf , num_longs , sizeof ( long ) , 0 ,
INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP ) ;
}
/*
* Calculate the number of bytes to be required to represent
* the absolute value of the integer given as _val_ .
*
* [ val ] an integer .
* [ nlz_bits_ret ] number of leading zero bits in the most significant byte is returned if not NULL .
*
* This function returns ( ( val_numbits * CHAR_BIT + CHAR_BIT - 1 ) / CHAR_BIT )
* where val_numbits is the number of bits of abs ( val ) .
* This function should not overflow .
*
* If nlz_bits_ret is not NULL ,
* ( return_value * CHAR_BIT - val_numbits ) is stored in * nlz_bits_ret .
* In this case , 0 < = * nlz_bits_ret < CHAR_BIT .
*
*/
size_t
rb_absint_size ( VALUE val , int * nlz_bits_ret )
{
BDIGIT * dp ;
BDIGIT * de ;
BDIGIT fixbuf [ bdigit_roomof ( sizeof ( long ) ) ] ;
int num_leading_zeros ;
val = rb_to_int ( val ) ;
if ( FIXNUM_P ( val ) ) {
long v = FIX2LONG ( val ) ;
if ( v < 0 ) {
v = - v ;
2013-07-04 13:38:11 +04:00
}
2013-07-07 15:02:47 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
fixbuf [ 0 ] = v ;
# else
{
int i ;
for ( i = 0 ; i < numberof ( fixbuf ) ; i + + ) {
fixbuf [ i ] = BIGLO ( v ) ;
v = BIGDN ( v ) ;
}
2013-07-04 13:38:11 +04:00
}
2013-07-07 15:02:47 +04:00
# endif
dp = fixbuf ;
de = fixbuf + numberof ( fixbuf ) ;
}
else {
dp = BDIGITS ( val ) ;
de = dp + RBIGNUM_LEN ( val ) ;
}
while ( dp < de & & de [ - 1 ] = = 0 )
de - - ;
if ( dp = = de ) {
if ( nlz_bits_ret )
* nlz_bits_ret = 0 ;
return 0 ;
}
num_leading_zeros = nlz ( de [ - 1 ] ) ;
if ( nlz_bits_ret )
* nlz_bits_ret = num_leading_zeros % CHAR_BIT ;
return ( de - dp ) * SIZEOF_BDIGITS - num_leading_zeros / CHAR_BIT ;
}
static size_t
absint_numwords_small ( size_t numbytes , int nlz_bits_in_msbyte , size_t word_numbits , size_t * nlz_bits_ret )
{
size_t val_numbits = numbytes * CHAR_BIT - nlz_bits_in_msbyte ;
size_t div = val_numbits / word_numbits ;
size_t mod = val_numbits % word_numbits ;
size_t numwords ;
size_t nlz_bits ;
numwords = mod = = 0 ? div : div + 1 ;
nlz_bits = mod = = 0 ? 0 : word_numbits - mod ;
* nlz_bits_ret = nlz_bits ;
return numwords ;
}
static size_t
absint_numwords_generic ( size_t numbytes , int nlz_bits_in_msbyte , size_t word_numbits , size_t * nlz_bits_ret )
{
2013-07-28 07:51:13 +04:00
static const BDIGIT char_bit [ 1 ] = { CHAR_BIT } ;
2013-07-07 15:02:47 +04:00
BDIGIT numbytes_bary [ bdigit_roomof ( sizeof ( numbytes ) ) ] ;
BDIGIT val_numbits_bary [ bdigit_roomof ( sizeof ( numbytes ) + 1 ) ] ;
BDIGIT nlz_bits_in_msbyte_bary [ 1 ] = { nlz_bits_in_msbyte } ;
BDIGIT word_numbits_bary [ bdigit_roomof ( sizeof ( word_numbits ) ) ] ;
BDIGIT div_bary [ numberof ( val_numbits_bary ) + BIGDIVREM_EXTRA_WORDS ] ;
BDIGIT mod_bary [ numberof ( word_numbits_bary ) ] ;
BDIGIT one [ 1 ] = { 1 } ;
size_t nlz_bits ;
size_t mod ;
int sign ;
size_t numwords ;
/*
* val_numbits = numbytes * CHAR_BIT - nlz_bits_in_msbyte
* div , mod = val_numbits . divmod ( word_numbits )
* numwords = mod = = 0 ? div : div + 1
* nlz_bits = mod = = 0 ? 0 : word_numbits - mod
*/
bary_unpack ( BARY_ARGS ( numbytes_bary ) , & numbytes , 1 , sizeof ( numbytes ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
2013-08-24 20:51:23 +04:00
BARY_SHORT_MUL ( val_numbits_bary , numbytes_bary , char_bit ) ;
2013-07-07 15:02:47 +04:00
if ( nlz_bits_in_msbyte )
BARY_SUB ( val_numbits_bary , val_numbits_bary , nlz_bits_in_msbyte_bary ) ;
bary_unpack ( BARY_ARGS ( word_numbits_bary ) , & word_numbits , 1 , sizeof ( word_numbits ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
BARY_DIVMOD ( div_bary , mod_bary , val_numbits_bary , word_numbits_bary ) ;
if ( BARY_ZERO_P ( mod_bary ) ) {
nlz_bits = 0 ;
2013-06-30 17:16:08 +04:00
}
else {
2013-07-07 15:02:47 +04:00
BARY_ADD ( div_bary , div_bary , one ) ;
bary_pack ( + 1 , BARY_ARGS ( mod_bary ) , & mod , 1 , sizeof ( mod ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
nlz_bits = word_numbits - mod ;
}
sign = bary_pack ( + 1 , BARY_ARGS ( div_bary ) , & numwords , 1 , sizeof ( numwords ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
2013-07-01 17:59:50 +04:00
2013-11-19 18:00:26 +04:00
if ( sign = = 2 ) {
# if defined __GNUC__ && (__GNUC__ == 4 && __GNUC_MINOR__ == 4)
* nlz_bits_ret = 0 ;
# endif
2013-07-07 15:02:47 +04:00
return ( size_t ) - 1 ;
2013-11-19 18:00:26 +04:00
}
2013-07-07 15:02:47 +04:00
* nlz_bits_ret = nlz_bits ;
return numwords ;
}
2013-07-01 17:59:50 +04:00
2013-07-07 15:02:47 +04:00
/*
* Calculate the number of words to be required to represent
* the absolute value of the integer given as _val_ .
*
* [ val ] an integer .
* [ word_numbits ] number of bits in a word .
* [ nlz_bits_ret ] number of leading zero bits in the most significant word is returned if not NULL .
*
* This function returns ( ( val_numbits * CHAR_BIT + word_numbits - 1 ) / word_numbits )
* where val_numbits is the number of bits of abs ( val ) .
*
* This function can overflow .
* When overflow occur , ( size_t ) - 1 is returned .
*
* If nlz_bits_ret is not NULL and overflow is not occur ,
* ( return_value * word_numbits - val_numbits ) is stored in * nlz_bits_ret .
* In this case , 0 < = * nlz_bits_ret < word_numbits .
*
*/
size_t
rb_absint_numwords ( VALUE val , size_t word_numbits , size_t * nlz_bits_ret )
{
size_t numbytes ;
int nlz_bits_in_msbyte ;
size_t numwords ;
size_t nlz_bits ;
2013-07-01 17:59:50 +04:00
2013-07-07 15:02:47 +04:00
if ( word_numbits = = 0 )
return ( size_t ) - 1 ;
2013-06-30 17:16:08 +04:00
2013-07-07 15:02:47 +04:00
numbytes = rb_absint_size ( val , & nlz_bits_in_msbyte ) ;
2013-07-01 17:59:50 +04:00
2013-07-07 15:02:47 +04:00
if ( numbytes < = SIZE_MAX / CHAR_BIT ) {
numwords = absint_numwords_small ( numbytes , nlz_bits_in_msbyte , word_numbits , & nlz_bits ) ;
# ifdef DEBUG_INTEGER_PACK
{
size_t numwords0 , nlz_bits0 ;
numwords0 = absint_numwords_generic ( numbytes , nlz_bits_in_msbyte , word_numbits , & nlz_bits0 ) ;
assert ( numwords0 = = numwords ) ;
assert ( nlz_bits0 = = nlz_bits ) ;
2013-06-30 17:16:08 +04:00
}
2013-07-07 15:02:47 +04:00
# endif
}
else {
numwords = absint_numwords_generic ( numbytes , nlz_bits_in_msbyte , word_numbits , & nlz_bits ) ;
2013-06-30 17:16:08 +04:00
}
2013-07-07 15:02:47 +04:00
if ( numwords = = ( size_t ) - 1 )
return numwords ;
2013-06-30 17:16:08 +04:00
2013-07-07 15:02:47 +04:00
if ( nlz_bits_ret )
* nlz_bits_ret = nlz_bits ;
return numwords ;
1998-01-16 15:13:05 +03:00
}
2013-07-28 06:14:58 +04:00
/* Test abs(val) consists only a bit or not.
*
* Returns 1 if abs ( val ) = = 1 < < n for some n > = 0.
* Returns 0 otherwise .
*
* rb_absint_singlebit_p can be used to determine required buffer size
* for rb_integer_pack used with INTEGER_PACK_2COMP ( two ' s complement ) .
*
* Following example calculates number of bits required to
* represent val in two ' s complement number , without sign bit .
*
* size_t size ;
* int neg = FIXNUM_P ( val ) ? FIX2LONG ( val ) < 0 : RBIGNUM_NEGATIVE_P ( val ) ;
* size = rb_absint_numwords ( val , 1 , NULL )
* if ( size = = ( size_t ) - 1 ) . . . overflow . . .
* if ( neg & & rb_absint_singlebit_p ( val ) )
* size - - ;
*
* Following example calculates number of bytes required to
* represent val in two ' s complement number , with sign bit .
*
* size_t size ;
* int neg = FIXNUM_P ( val ) ? FIX2LONG ( val ) < 0 : RBIGNUM_NEGATIVE_P ( val ) ;
* int nlz_bits ;
* size = rb_absint_size ( val , & nlz_bits ) ;
* if ( nlz_bits = = 0 & & ! ( neg & & rb_absint_singlebit_p ( val ) ) )
* size + + ;
*/
2013-07-07 15:02:47 +04:00
int
rb_absint_singlebit_p ( VALUE val )
2000-01-05 07:41:21 +03:00
{
2013-07-07 15:02:47 +04:00
BDIGIT * dp ;
BDIGIT * de ;
BDIGIT fixbuf [ bdigit_roomof ( sizeof ( long ) ) ] ;
BDIGIT d ;
2000-01-05 07:41:21 +03:00
2013-07-07 15:02:47 +04:00
val = rb_to_int ( val ) ;
if ( FIXNUM_P ( val ) ) {
long v = FIX2LONG ( val ) ;
if ( v < 0 ) {
v = - v ;
}
# if SIZEOF_BDIGITS >= SIZEOF_LONG
fixbuf [ 0 ] = v ;
# else
{
int i ;
for ( i = 0 ; i < numberof ( fixbuf ) ; i + + ) {
fixbuf [ i ] = BIGLO ( v ) ;
v = BIGDN ( v ) ;
}
}
# endif
dp = fixbuf ;
de = fixbuf + numberof ( fixbuf ) ;
2003-07-20 21:17:52 +04:00
}
else {
2013-07-07 15:02:47 +04:00
dp = BDIGITS ( val ) ;
de = dp + RBIGNUM_LEN ( val ) ;
2000-01-05 07:41:21 +03:00
}
2013-07-07 15:02:47 +04:00
while ( dp < de & & de [ - 1 ] = = 0 )
de - - ;
while ( dp < de & & dp [ 0 ] = = 0 )
dp + + ;
if ( dp = = de ) /* no bit set. */
return 0 ;
if ( dp ! = de - 1 ) /* two non-zero words. two bits set, at least. */
return 0 ;
d = * dp ;
return POW2_P ( d ) ;
2002-02-01 13:23:22 +03:00
}
2002-03-14 09:23:46 +03:00
2013-07-07 15:02:47 +04:00
/*
* Export an integer into a buffer .
*
* This function fills the buffer specified by _words_ and _numwords_ as
* val in the format specified by _wordsize_ , _nails_ and _flags_ .
*
* [ val ] Fixnum , Bignum or another integer like object which has to_int method .
* [ words ] buffer to export abs ( val ) .
* [ numwords ] the size of given buffer as number of words .
* [ wordsize ] the size of word as number of bytes .
* [ nails ] number of padding bits in a word .
* Most significant nails bits of each word are filled by zero .
* [ flags ] bitwise or of constants which name starts " INTEGER_PACK_ " .
*
* flags :
* [ INTEGER_PACK_MSWORD_FIRST ] Store the most significant word as the first word .
* [ INTEGER_PACK_LSWORD_FIRST ] Store the least significant word as the first word .
* [ INTEGER_PACK_MSBYTE_FIRST ] Store the most significant byte in a word as the first byte in the word .
* [ INTEGER_PACK_LSBYTE_FIRST ] Store the least significant byte in a word as the first byte in the word .
* [ INTEGER_PACK_NATIVE_BYTE_ORDER ] INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST corresponding to the host ' s endian .
* [ INTEGER_PACK_2COMP ] Use 2 ' s complement representation .
* [ INTEGER_PACK_LITTLE_ENDIAN ] Same as INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_LSBYTE_FIRST
* [ INTEGER_PACK_BIG_ENDIAN ] Same as INTEGER_PACK_MSWORD_FIRST | INTEGER_PACK_MSBYTE_FIRST
* [ INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ] Use generic implementation ( for test and debug ) .
*
* This function fills the buffer specified by _words_
* as abs ( val ) if INTEGER_PACK_2COMP is not specified in _flags_ .
* If INTEGER_PACK_2COMP is specified , 2 ' s complement representation of val is
* filled in the buffer .
*
* This function returns the signedness and overflow condition .
* The overflow condition depends on INTEGER_PACK_2COMP .
*
* INTEGER_PACK_2COMP is not specified :
* - 2 : negative overflow . val < = - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) )
* - 1 : negative without overflow . - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < val < 0
* 0 : zero . val = = 0
* 1 : positive without overflow . 0 < val < 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) )
* 2 : positive overflow . 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < = val
*
* INTEGER_PACK_2COMP is specified :
* - 2 : negative overflow . val < - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) )
* - 1 : negative without overflow . - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < = val < 0
* 0 : zero . val = = 0
* 1 : positive without overflow . 0 < val < 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) )
* 2 : positive overflow . 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < = val
*
* The value , - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) , is representable
* in 2 ' s complement representation but not representable in absolute value .
* So - 1 is returned for the value if INTEGER_PACK_2COMP is specified
* but returns - 2 if INTEGER_PACK_2COMP is not specified .
*
* The least significant words are filled in the buffer when overflow occur .
*/
int
rb_integer_pack ( VALUE val , void * words , size_t numwords , size_t wordsize , size_t nails , int flags )
2002-03-14 09:23:46 +03:00
{
2013-07-07 15:02:47 +04:00
int sign ;
BDIGIT * ds ;
size_t num_bdigits ;
BDIGIT fixbuf [ bdigit_roomof ( sizeof ( long ) ) ] ;
2002-03-14 09:23:46 +03:00
2013-07-07 15:02:47 +04:00
RB_GC_GUARD ( val ) = rb_to_int ( val ) ;
if ( FIXNUM_P ( val ) ) {
long v = FIX2LONG ( val ) ;
if ( v < 0 ) {
sign = - 1 ;
v = - v ;
}
else {
sign = 1 ;
}
# if SIZEOF_BDIGITS >= SIZEOF_LONG
fixbuf [ 0 ] = v ;
2013-06-21 01:45:11 +04:00
# else
2013-07-07 15:02:47 +04:00
{
int i ;
for ( i = 0 ; i < numberof ( fixbuf ) ; i + + ) {
fixbuf [ i ] = BIGLO ( v ) ;
v = BIGDN ( v ) ;
}
}
2013-06-21 01:45:11 +04:00
# endif
2013-07-07 15:02:47 +04:00
ds = fixbuf ;
num_bdigits = numberof ( fixbuf ) ;
2002-03-14 09:23:46 +03:00
}
2013-04-10 07:34:38 +04:00
else {
2013-07-07 15:02:47 +04:00
sign = RBIGNUM_POSITIVE_P ( val ) ? 1 : - 1 ;
ds = BDIGITS ( val ) ;
num_bdigits = RBIGNUM_LEN ( val ) ;
2002-03-14 09:23:46 +03:00
}
2013-07-07 15:02:47 +04:00
return bary_pack ( sign , ds , num_bdigits , words , numwords , wordsize , nails , flags ) ;
2002-03-14 09:23:46 +03:00
}
2013-07-07 15:02:47 +04:00
/*
* Import an integer into a buffer .
*
* [ words ] buffer to import .
* [ numwords ] the size of given buffer as number of words .
* [ wordsize ] the size of word as number of bytes .
* [ nails ] number of padding bits in a word .
* Most significant nails bits of each word are ignored .
* [ flags ] bitwise or of constants which name starts " INTEGER_PACK_ " .
*
* flags :
* [ INTEGER_PACK_MSWORD_FIRST ] Interpret the first word as the most significant word .
* [ INTEGER_PACK_LSWORD_FIRST ] Interpret the first word as the least significant word .
* [ INTEGER_PACK_MSBYTE_FIRST ] Interpret the first byte in a word as the most significant byte in the word .
* [ INTEGER_PACK_LSBYTE_FIRST ] Interpret the first byte in a word as the least significant byte in the word .
* [ INTEGER_PACK_NATIVE_BYTE_ORDER ] INTEGER_PACK_MSBYTE_FIRST or INTEGER_PACK_LSBYTE_FIRST corresponding to the host ' s endian .
* [ INTEGER_PACK_2COMP ] Use 2 ' s complement representation .
* [ INTEGER_PACK_LITTLE_ENDIAN ] Same as INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_LSBYTE_FIRST
* [ INTEGER_PACK_BIG_ENDIAN ] Same as INTEGER_PACK_MSWORD_FIRST | INTEGER_PACK_MSBYTE_FIRST
* [ INTEGER_PACK_FORCE_BIGNUM ] the result will be a Bignum
* even if it is representable as a Fixnum .
* [ INTEGER_PACK_NEGATIVE ] Returns non - positive value .
* ( Returns non - negative value if not specified . )
* [ INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ] Use generic implementation ( for test and debug ) .
*
* This function returns the imported integer as Fixnum or Bignum .
*
* The range of the result value depends on INTEGER_PACK_2COMP and INTEGER_PACK_NEGATIVE .
*
* INTEGER_PACK_2COMP is not set :
* 0 < = val < 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) if ! INTEGER_PACK_NEGATIVE
* - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < val < = 0 if INTEGER_PACK_NEGATIVE
*
* INTEGER_PACK_2COMP is set :
* - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) - 1 ) < = val < = 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) - 1 ) - 1 if ! INTEGER_PACK_NEGATIVE
* - 2 * * ( numwords * ( wordsize * CHAR_BIT - nails ) ) < = val < = - 1 if INTEGER_PACK_NEGATIVE
*
* INTEGER_PACK_2COMP without INTEGER_PACK_NEGATIVE means sign extension .
* INTEGER_PACK_2COMP with INTEGER_PACK_NEGATIVE mean assuming the higher bits are 1.
*
* Note that this function returns 0 when numwords is zero and
* INTEGER_PACK_2COMP is set but INTEGER_PACK_NEGATIVE is not set .
*/
2002-02-01 13:23:22 +03:00
VALUE
2013-07-07 15:02:47 +04:00
rb_integer_unpack ( const void * words , size_t numwords , size_t wordsize , size_t nails , int flags )
2002-02-01 13:23:22 +03:00
{
2013-07-07 15:02:47 +04:00
VALUE val ;
size_t num_bdigits ;
int sign ;
int nlp_bits ;
BDIGIT * ds ;
BDIGIT fixbuf [ 2 ] = { 0 , 0 } ;
2000-01-05 07:41:21 +03:00
2013-07-07 15:02:47 +04:00
validate_integer_pack_format ( numwords , wordsize , nails , flags ,
INTEGER_PACK_MSWORD_FIRST |
INTEGER_PACK_LSWORD_FIRST |
INTEGER_PACK_MSBYTE_FIRST |
INTEGER_PACK_LSBYTE_FIRST |
INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP |
INTEGER_PACK_FORCE_BIGNUM |
INTEGER_PACK_NEGATIVE |
INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION ) ;
2007-08-02 19:00:22 +04:00
2013-07-07 15:02:47 +04:00
num_bdigits = integer_unpack_num_bdigits ( numwords , wordsize , nails , & nlp_bits ) ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
if ( LONG_MAX - 1 < num_bdigits )
rb_raise ( rb_eArgError , " too big to unpack as an integer " ) ;
if ( num_bdigits < = numberof ( fixbuf ) & & ! ( flags & INTEGER_PACK_FORCE_BIGNUM ) ) {
val = Qfalse ;
ds = fixbuf ;
}
else {
val = bignew ( ( long ) num_bdigits , 0 ) ;
ds = BDIGITS ( val ) ;
}
sign = bary_unpack_internal ( ds , num_bdigits , words , numwords , wordsize , nails , flags , nlp_bits ) ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
if ( sign = = - 2 ) {
if ( val ) {
big_extend_carry ( val ) ;
}
else if ( num_bdigits = = numberof ( fixbuf ) ) {
val = bignew ( ( long ) num_bdigits + 1 , 0 ) ;
MEMCPY ( BDIGITS ( val ) , fixbuf , BDIGIT , num_bdigits ) ;
BDIGITS ( val ) [ num_bdigits + + ] = 1 ;
}
else {
ds [ num_bdigits + + ] = 1 ;
}
}
2007-08-02 18:45:34 +04:00
2013-07-07 15:02:47 +04:00
if ( ! val ) {
BDIGIT_DBL u = fixbuf [ 0 ] + BIGUP ( fixbuf [ 1 ] ) ;
if ( u = = 0 )
return LONG2FIX ( 0 ) ;
if ( 0 < sign & & POSFIXABLE ( u ) )
return LONG2FIX ( u ) ;
if ( sign < 0 & & BDIGIT_MSB ( fixbuf [ 1 ] ) = = 0 & &
NEGFIXABLE ( - ( BDIGIT_DBL_SIGNED ) u ) )
return LONG2FIX ( - ( BDIGIT_DBL_SIGNED ) u ) ;
val = bignew ( ( long ) num_bdigits , 0 < = sign ) ;
MEMCPY ( BDIGITS ( val ) , fixbuf , BDIGIT , num_bdigits ) ;
}
2007-08-02 18:45:34 +04:00
2013-07-07 15:02:47 +04:00
if ( ( flags & INTEGER_PACK_FORCE_BIGNUM ) & & sign ! = 0 & &
bary_zero_p ( BDIGITS ( val ) , RBIGNUM_LEN ( val ) ) )
sign = 0 ;
RBIGNUM_SET_SIGN ( val , 0 < = sign ) ;
2007-08-02 18:45:34 +04:00
2013-07-07 15:02:47 +04:00
if ( flags & INTEGER_PACK_FORCE_BIGNUM )
return bigtrunc ( val ) ;
return bignorm ( val ) ;
}
2007-08-02 18:45:34 +04:00
2013-07-07 15:02:47 +04:00
# define QUAD_SIZE 8
2007-08-02 18:45:34 +04:00
2013-07-07 15:02:47 +04:00
void
rb_quad_pack ( char * buf , VALUE val )
2007-08-06 22:03:11 +04:00
{
2013-07-07 15:02:47 +04:00
rb_integer_pack ( val , buf , 1 , QUAD_SIZE , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER |
INTEGER_PACK_2COMP ) ;
2007-08-02 18:45:34 +04:00
}
2013-07-07 15:02:47 +04:00
VALUE
rb_quad_unpack ( const char * buf , int signed_p )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
return rb_integer_unpack ( buf , 1 , QUAD_SIZE , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER |
( signed_p ? INTEGER_PACK_2COMP : 0 ) ) ;
2007-08-06 22:03:11 +04:00
}
2013-09-02 17:52:05 +04:00
# define conv_digit(c) (ruby_digit36_to_number_table[(unsigned char)(c)])
2013-09-03 07:03:32 +04:00
static void
str2big_scan_digits ( const char * s , const char * str , int base , int badcheck , size_t * num_digits_p , size_t * len_p )
{
char nondigit = 0 ;
size_t num_digits = 0 ;
const char * digits_start = str ;
const char * digits_end = str ;
int c ;
if ( badcheck & & * str = = ' _ ' ) goto bad ;
while ( ( c = * str + + ) ! = 0 ) {
if ( c = = ' _ ' ) {
if ( nondigit ) {
if ( badcheck ) goto bad ;
break ;
}
nondigit = ( char ) c ;
continue ;
}
else if ( ( c = conv_digit ( c ) ) < 0 ) {
break ;
}
if ( c > = base ) break ;
nondigit = 0 ;
num_digits + + ;
digits_end = str ;
}
if ( badcheck ) {
str - - ;
if ( s + 1 < str & & str [ - 1 ] = = ' _ ' ) goto bad ;
while ( * str & & ISSPACE ( * str ) ) str + + ;
if ( * str ) {
bad :
rb_invalid_str ( s , " Integer() " ) ;
}
}
* num_digits_p = num_digits ;
* len_p = digits_end - digits_start ;
}
2013-09-02 17:52:05 +04:00
static VALUE
str2big_poweroftwo (
int sign ,
const char * digits_start ,
const char * digits_end ,
size_t num_digits ,
int bits_per_digit )
{
BDIGIT * dp ;
BDIGIT_DBL dd ;
int numbits ;
size_t num_bdigits ;
const char * p ;
int c ;
VALUE z ;
num_bdigits = ( num_digits / BITSPERDIG ) * bits_per_digit + roomof ( ( num_digits % BITSPERDIG ) * bits_per_digit , BITSPERDIG ) ;
z = bignew ( num_bdigits , sign ) ;
dp = BDIGITS ( z ) ;
dd = 0 ;
numbits = 0 ;
for ( p = digits_end ; digits_start < p ; p - - ) {
if ( ( c = conv_digit ( p [ - 1 ] ) ) < 0 )
continue ;
dd | = ( BDIGIT_DBL ) c < < numbits ;
numbits + = bits_per_digit ;
if ( BITSPERDIG < = numbits ) {
* dp + + = BIGLO ( dd ) ;
dd = BIGDN ( dd ) ;
numbits - = BITSPERDIG ;
}
}
if ( numbits ) {
* dp + + = BIGLO ( dd ) ;
}
assert ( ( size_t ) ( dp - BDIGITS ( z ) ) = = num_bdigits ) ;
return z ;
}
static VALUE
str2big_normal (
int sign ,
const char * digits_start ,
const char * digits_end ,
size_t num_bdigits ,
int base )
{
size_t blen = 1 ;
BDIGIT * zds ;
BDIGIT_DBL num ;
size_t i ;
const char * p ;
int c ;
VALUE z ;
z = bignew ( num_bdigits , sign ) ;
zds = BDIGITS ( z ) ;
BDIGITS_ZERO ( zds , num_bdigits ) ;
for ( p = digits_start ; p < digits_end ; p + + ) {
if ( ( c = conv_digit ( * p ) ) < 0 )
continue ;
num = c ;
i = 0 ;
for ( ; ; ) {
while ( i < blen ) {
num + = ( BDIGIT_DBL ) zds [ i ] * base ;
zds [ i + + ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
if ( num ) {
blen + + ;
continue ;
}
break ;
}
assert ( blen < = num_bdigits ) ;
}
return z ;
}
static VALUE
str2big_karatsuba (
int sign ,
const char * digits_start ,
const char * digits_end ,
size_t num_digits ,
size_t num_bdigits ,
int digits_per_bdigits_dbl ,
int base )
{
VALUE powerv ;
size_t unit ;
VALUE tmpuv = 0 ;
BDIGIT * uds , * vds , * tds ;
BDIGIT_DBL dd ;
BDIGIT_DBL current_base ;
int m ;
int power_level = 0 ;
size_t i ;
const char * p ;
int c ;
VALUE z ;
uds = ALLOCV_N ( BDIGIT , tmpuv , 2 * num_bdigits ) ;
vds = uds + num_bdigits ;
powerv = power_cache_get_power ( base , power_level , NULL ) ;
i = 0 ;
dd = 0 ;
current_base = 1 ;
m = digits_per_bdigits_dbl ;
if ( num_digits < ( size_t ) m )
m = ( int ) num_digits ;
for ( p = digits_end ; digits_start < p ; p - - ) {
if ( ( c = conv_digit ( p [ - 1 ] ) ) < 0 )
continue ;
dd = dd + c * current_base ;
current_base * = base ;
num_digits - - ;
m - - ;
if ( m = = 0 ) {
uds [ i + + ] = BIGLO ( dd ) ;
uds [ i + + ] = ( BDIGIT ) BIGDN ( dd ) ;
dd = 0 ;
m = digits_per_bdigits_dbl ;
if ( num_digits < ( size_t ) m )
m = ( int ) num_digits ;
current_base = 1 ;
}
}
assert ( i = = num_bdigits ) ;
for ( unit = 2 ; unit < num_bdigits ; unit * = 2 ) {
for ( i = 0 ; i < num_bdigits ; i + = unit * 2 ) {
if ( 2 * unit < = num_bdigits - i ) {
bary_mul ( vds + i , unit * 2 , BDIGITS ( powerv ) , RBIGNUM_LEN ( powerv ) , uds + i + unit , unit ) ;
bary_add ( vds + i , unit * 2 , vds + i , unit * 2 , uds + i , unit ) ;
}
else if ( unit < = num_bdigits - i ) {
bary_mul ( vds + i , num_bdigits - i , BDIGITS ( powerv ) , RBIGNUM_LEN ( powerv ) , uds + i + unit , num_bdigits - ( i + unit ) ) ;
bary_add ( vds + i , num_bdigits - i , vds + i , num_bdigits - i , uds + i , unit ) ;
}
else {
MEMCPY ( vds + i , uds + i , BDIGIT , num_bdigits - i ) ;
}
}
power_level + + ;
powerv = power_cache_get_power ( base , power_level , NULL ) ;
tds = vds ;
vds = uds ;
uds = tds ;
}
BARY_TRUNC ( uds , num_bdigits ) ;
z = bignew ( num_bdigits , sign ) ;
MEMCPY ( BDIGITS ( z ) , uds , BDIGIT , num_bdigits ) ;
if ( tmpuv )
ALLOCV_END ( tmpuv ) ;
return z ;
}
2013-09-03 15:20:02 +04:00
# ifdef USE_GMP
static VALUE
str2big_gmp (
int sign ,
const char * digits_start ,
const char * digits_end ,
size_t num_digits ,
size_t num_bdigits ,
int base )
{
const size_t nails = ( sizeof ( BDIGIT ) - SIZEOF_BDIGITS ) * CHAR_BIT ;
char * buf , * p ;
const char * q ;
VALUE tmps ;
mpz_t mz ;
VALUE z ;
BDIGIT * zds ;
size_t zn , count ;
buf = ALLOCV_N ( char , tmps , num_digits + 1 ) ;
p = buf ;
for ( q = digits_start ; q < digits_end ; q + + ) {
if ( conv_digit ( * q ) < 0 )
continue ;
* p + + = * q ;
}
* p = ' \0 ' ;
mpz_init ( mz ) ;
mpz_set_str ( mz , buf , base ) ;
zn = num_bdigits ;
z = bignew ( zn , sign ) ;
zds = BDIGITS ( z ) ;
mpz_export ( BDIGITS ( z ) , & count , - 1 , sizeof ( BDIGIT ) , 0 , nails , mz ) ;
BDIGITS_ZERO ( zds + count , zn - count ) ;
mpz_clear ( mz ) ;
if ( tmps )
ALLOCV_END ( tmps ) ;
return z ;
}
# endif
2013-07-07 15:02:47 +04:00
VALUE
rb_cstr_to_inum ( const char * str , int base , int badcheck )
2007-08-06 22:03:11 +04:00
{
2013-07-07 15:02:47 +04:00
const char * s = str ;
2013-09-03 07:03:32 +04:00
char sign = 1 ;
2013-07-07 15:02:47 +04:00
int c ;
VALUE z ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
int bits_per_digit ;
2007-08-06 22:03:11 +04:00
2013-09-02 17:52:05 +04:00
const char * digits_start , * digits_end ;
2013-07-07 15:02:47 +04:00
size_t num_digits ;
size_t num_bdigits ;
2013-09-03 07:03:32 +04:00
size_t len ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
if ( ! str ) {
2013-09-03 07:03:32 +04:00
if ( badcheck ) {
bad :
rb_invalid_str ( s , " Integer() " ) ;
}
2013-07-07 15:02:47 +04:00
return INT2FIX ( 0 ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
while ( ISSPACE ( * str ) ) str + + ;
if ( str [ 0 ] = = ' + ' ) {
str + + ;
2002-08-19 09:56:09 +04:00
}
2013-07-07 15:02:47 +04:00
else if ( str [ 0 ] = = ' - ' ) {
str + + ;
sign = 0 ;
2008-02-29 20:35:11 +03:00
}
2013-07-07 15:02:47 +04:00
if ( str [ 0 ] = = ' + ' | | str [ 0 ] = = ' - ' ) {
if ( badcheck ) goto bad ;
return INT2FIX ( 0 ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
if ( base < = 0 ) {
if ( str [ 0 ] = = ' 0 ' ) {
switch ( str [ 1 ] ) {
case ' x ' : case ' X ' :
base = 16 ;
str + = 2 ;
break ;
case ' b ' : case ' B ' :
base = 2 ;
str + = 2 ;
break ;
case ' o ' : case ' O ' :
base = 8 ;
str + = 2 ;
break ;
case ' d ' : case ' D ' :
base = 10 ;
str + = 2 ;
break ;
default :
base = 8 ;
}
2008-03-07 15:28:57 +03:00
}
2013-07-07 15:02:47 +04:00
else if ( base < - 1 ) {
base = - base ;
2008-03-07 15:28:57 +03:00
}
else {
2013-07-07 15:02:47 +04:00
base = 10 ;
2008-03-07 15:28:57 +03:00
}
2006-10-30 06:39:44 +03:00
}
2013-07-07 15:02:47 +04:00
else if ( base = = 2 ) {
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' b ' | | str [ 1 ] = = ' B ' ) ) {
str + = 2 ;
}
2007-08-06 22:03:11 +04:00
}
2013-07-07 15:02:47 +04:00
else if ( base = = 8 ) {
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' o ' | | str [ 1 ] = = ' O ' ) ) {
str + = 2 ;
}
2013-06-09 04:36:58 +04:00
}
2013-07-07 15:02:47 +04:00
else if ( base = = 10 ) {
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' d ' | | str [ 1 ] = = ' D ' ) ) {
str + = 2 ;
}
2013-06-09 04:36:58 +04:00
}
2013-07-07 15:02:47 +04:00
else if ( base = = 16 ) {
if ( str [ 0 ] = = ' 0 ' & & ( str [ 1 ] = = ' x ' | | str [ 1 ] = = ' X ' ) ) {
str + = 2 ;
}
2013-06-09 04:36:58 +04:00
}
2013-07-07 15:02:47 +04:00
if ( base < 2 | | 36 < base ) {
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
2007-08-02 18:45:34 +04:00
}
2013-07-07 15:02:47 +04:00
if ( * str = = ' 0 ' ) { /* squeeze preceding 0s */
int us = 0 ;
while ( ( c = * + + str ) = = ' 0 ' | | c = = ' _ ' ) {
if ( c = = ' _ ' ) {
if ( + + us > = 2 )
break ;
} else
us = 0 ;
}
if ( ! ( c = * str ) | | ISSPACE ( c ) ) - - str ;
}
c = * str ;
c = conv_digit ( c ) ;
if ( c < 0 | | c > = base ) {
if ( badcheck ) goto bad ;
return INT2FIX ( 0 ) ;
2007-08-06 22:03:11 +04:00
}
2013-08-31 22:34:42 +04:00
bits_per_digit = bit_length ( base - 1 ) ;
2013-07-07 15:02:47 +04:00
if ( bits_per_digit * strlen ( str ) < = sizeof ( long ) * CHAR_BIT ) {
char * end ;
unsigned long val = STRTOUL ( str , & end , base ) ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
if ( str < end & & * end = = ' _ ' ) goto bigparse ;
if ( badcheck ) {
if ( end = = str ) goto bad ; /* no number */
while ( * end & & ISSPACE ( * end ) ) end + + ;
if ( * end ) goto bad ; /* trailing garbage */
}
2013-06-09 04:36:58 +04:00
2013-07-07 15:02:47 +04:00
if ( POSFIXABLE ( val ) ) {
if ( sign ) return LONG2FIX ( val ) ;
else {
long result = - ( long ) val ;
return LONG2FIX ( result ) ;
}
}
else {
VALUE big = rb_uint2big ( val ) ;
RBIGNUM_SET_SIGN ( big , sign ) ;
return bignorm ( big ) ;
}
2013-06-09 04:36:58 +04:00
}
2013-09-02 17:52:05 +04:00
2013-07-07 15:02:47 +04:00
bigparse :
2013-09-03 07:03:32 +04:00
digits_start = str ;
str2big_scan_digits ( s , str , base , badcheck , & num_digits , & len ) ;
digits_end = digits_start + len ;
2007-08-06 22:03:11 +04:00
2013-07-07 15:02:47 +04:00
if ( POW2_P ( base ) ) {
2013-09-02 17:52:05 +04:00
z = str2big_poweroftwo ( sign , digits_start , digits_end , num_digits ,
bits_per_digit ) ;
2013-07-07 15:02:47 +04:00
}
else {
int digits_per_bdigits_dbl ;
2013-08-02 18:10:51 +04:00
maxpow_in_bdigit_dbl ( base , & digits_per_bdigits_dbl ) ;
2013-07-07 15:02:47 +04:00
num_bdigits = roomof ( num_digits , digits_per_bdigits_dbl ) * 2 ;
2007-08-02 18:45:34 +04:00
2013-09-03 15:20:02 +04:00
# ifdef USE_GMP
if ( GMP_STR2BIG_DIGITS < num_bdigits ) {
z = str2big_gmp ( sign , digits_start , digits_end , num_digits ,
num_bdigits , base ) ;
}
else
# endif
2013-07-07 15:02:47 +04:00
if ( num_bdigits < KARATSUBA_MUL_DIGITS ) {
2013-09-02 17:52:05 +04:00
z = str2big_normal ( sign , digits_start , digits_end ,
num_bdigits , base ) ;
2013-07-07 15:02:47 +04:00
}
else {
2013-09-02 17:52:05 +04:00
z = str2big_karatsuba ( sign , digits_start , digits_end , num_digits ,
num_bdigits , digits_per_bdigits_dbl , base ) ;
2013-07-07 15:02:47 +04:00
}
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
return bignorm ( z ) ;
2004-01-22 21:06:38 +03:00
}
2006-07-11 10:47:09 +04:00
VALUE
2013-07-07 15:02:47 +04:00
rb_str_to_inum ( VALUE str , int base , int badcheck )
2000-01-05 07:41:21 +03:00
{
2013-07-07 15:02:47 +04:00
char * s ;
long len ;
VALUE v = 0 ;
VALUE ret ;
2000-01-05 07:41:21 +03:00
2013-07-07 15:02:47 +04:00
StringValue ( str ) ;
rb_must_asciicompat ( str ) ;
if ( badcheck ) {
s = StringValueCStr ( str ) ;
2013-04-09 15:39:53 +04:00
}
else {
2013-07-07 15:02:47 +04:00
s = RSTRING_PTR ( str ) ;
2003-10-09 21:45:53 +04:00
}
2013-07-07 15:02:47 +04:00
if ( s ) {
len = RSTRING_LEN ( str ) ;
if ( s [ len ] ) { /* no sentinel somehow */
char * p = ALLOCV ( v , len + 1 ) ;
1999-01-20 07:59:39 +03:00
2013-07-07 15:02:47 +04:00
MEMCPY ( p , s , char , len ) ;
p [ len ] = ' \0 ' ;
s = p ;
}
1999-01-20 07:59:39 +03:00
}
2013-07-07 15:02:47 +04:00
ret = rb_cstr_to_inum ( s , base , badcheck ) ;
if ( v )
ALLOCV_END ( v ) ;
return ret ;
1999-01-20 07:59:39 +03:00
}
2013-09-03 07:50:15 +04:00
VALUE
rb_str2big_poweroftwo ( VALUE arg , int base , int badcheck )
{
int positive_p = 1 ;
const char * s , * str ;
const char * digits_start , * digits_end ;
size_t num_digits ;
size_t len ;
VALUE z ;
if ( base < 2 | | 36 < base | | ! POW2_P ( base ) ) {
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
}
rb_must_asciicompat ( arg ) ;
s = str = StringValueCStr ( arg ) ;
if ( * str = = ' - ' ) {
str + + ;
positive_p = 0 ;
}
digits_start = str ;
str2big_scan_digits ( s , str , base , badcheck , & num_digits , & len ) ;
digits_end = digits_start + len ;
z = str2big_poweroftwo ( positive_p , digits_start , digits_end , num_digits ,
bit_length ( base - 1 ) ) ;
RB_GC_GUARD ( arg ) ;
return bignorm ( z ) ;
}
VALUE
rb_str2big_normal ( VALUE arg , int base , int badcheck )
{
int positive_p = 1 ;
const char * s , * str ;
const char * digits_start , * digits_end ;
size_t num_digits ;
size_t len ;
VALUE z ;
int digits_per_bdigits_dbl ;
size_t num_bdigits ;
if ( base < 2 | | 36 < base ) {
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
}
rb_must_asciicompat ( arg ) ;
s = str = StringValueCStr ( arg ) ;
if ( * str = = ' - ' ) {
str + + ;
positive_p = 0 ;
}
digits_start = str ;
str2big_scan_digits ( s , str , base , badcheck , & num_digits , & len ) ;
digits_end = digits_start + len ;
maxpow_in_bdigit_dbl ( base , & digits_per_bdigits_dbl ) ;
num_bdigits = roomof ( num_digits , digits_per_bdigits_dbl ) * 2 ;
z = str2big_normal ( positive_p , digits_start , digits_end ,
num_bdigits , base ) ;
RB_GC_GUARD ( arg ) ;
return bignorm ( z ) ;
}
VALUE
rb_str2big_karatsuba ( VALUE arg , int base , int badcheck )
{
int positive_p = 1 ;
const char * s , * str ;
const char * digits_start , * digits_end ;
size_t num_digits ;
size_t len ;
VALUE z ;
int digits_per_bdigits_dbl ;
size_t num_bdigits ;
if ( base < 2 | | 36 < base ) {
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
}
rb_must_asciicompat ( arg ) ;
s = str = StringValueCStr ( arg ) ;
if ( * str = = ' - ' ) {
str + + ;
positive_p = 0 ;
}
digits_start = str ;
str2big_scan_digits ( s , str , base , badcheck , & num_digits , & len ) ;
digits_end = digits_start + len ;
maxpow_in_bdigit_dbl ( base , & digits_per_bdigits_dbl ) ;
num_bdigits = roomof ( num_digits , digits_per_bdigits_dbl ) * 2 ;
z = str2big_karatsuba ( positive_p , digits_start , digits_end , num_digits ,
num_bdigits , digits_per_bdigits_dbl , base ) ;
RB_GC_GUARD ( arg ) ;
return bignorm ( z ) ;
}
2013-09-03 15:20:02 +04:00
# ifdef USE_GMP
VALUE
rb_str2big_gmp ( VALUE arg , int base , int badcheck )
{
int positive_p = 1 ;
const char * s , * str ;
const char * digits_start , * digits_end ;
size_t num_digits ;
size_t len ;
VALUE z ;
int digits_per_bdigits_dbl ;
size_t num_bdigits ;
if ( base < 2 | | 36 < base ) {
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
}
rb_must_asciicompat ( arg ) ;
s = str = StringValueCStr ( arg ) ;
if ( * str = = ' - ' ) {
str + + ;
positive_p = 0 ;
}
digits_start = str ;
str2big_scan_digits ( s , str , base , badcheck , & num_digits , & len ) ;
digits_end = digits_start + len ;
maxpow_in_bdigit_dbl ( base , & digits_per_bdigits_dbl ) ;
num_bdigits = roomof ( num_digits , digits_per_bdigits_dbl ) * 2 ;
z = str2big_gmp ( positive_p , digits_start , digits_end , num_digits , num_bdigits , base ) ;
RB_GC_GUARD ( arg ) ;
return bignorm ( z ) ;
}
# endif
2002-03-14 09:23:46 +03:00
# if HAVE_LONG_LONG
2013-07-07 15:02:47 +04:00
static VALUE
rb_ull2big ( unsigned LONG_LONG n )
2002-03-14 09:23:46 +03:00
{
2013-07-07 15:02:47 +04:00
long i ;
VALUE big = bignew ( bdigit_roomof ( SIZEOF_LONG_LONG ) , 1 ) ;
BDIGIT * digits = BDIGITS ( big ) ;
2002-03-14 09:23:46 +03:00
2013-07-07 15:02:47 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG_LONG
digits [ 0 ] = n ;
2013-06-25 14:04:37 +04:00
# else
2013-07-07 15:02:47 +04:00
for ( i = 0 ; i < bdigit_roomof ( SIZEOF_LONG_LONG ) ; i + + ) {
digits [ i ] = BIGLO ( n ) ;
n = BIGDN ( n ) ;
2002-03-14 09:23:46 +03:00
}
2013-06-25 14:04:37 +04:00
# endif
2013-07-07 15:02:47 +04:00
i = bdigit_roomof ( SIZEOF_LONG_LONG ) ;
while ( i - - & & ! digits [ i ] ) ;
RBIGNUM_SET_LEN ( big , i + 1 ) ;
return big ;
2002-03-14 09:23:46 +03:00
}
2013-07-07 15:02:47 +04:00
static VALUE
rb_ll2big ( LONG_LONG n )
2002-03-14 09:23:46 +03:00
{
2013-07-07 15:02:47 +04:00
long neg = 0 ;
unsigned LONG_LONG u ;
VALUE big ;
2002-03-14 09:23:46 +03:00
2013-07-07 15:02:47 +04:00
if ( n < 0 ) {
u = 1 + ( unsigned LONG_LONG ) ( - ( n + 1 ) ) ; /* u = -n avoiding overflow */
neg = 1 ;
2013-04-09 15:39:53 +04:00
}
else {
2013-07-07 15:02:47 +04:00
u = n ;
2011-11-14 07:51:56 +04:00
}
2013-07-07 15:02:47 +04:00
big = rb_ull2big ( u ) ;
if ( neg ) {
RBIGNUM_SET_SIGN ( big , 0 ) ;
}
return big ;
2002-03-14 09:23:46 +03:00
}
2013-07-07 15:02:47 +04:00
VALUE
rb_ull2inum ( unsigned LONG_LONG n )
2002-03-14 09:23:46 +03:00
{
2013-07-07 15:02:47 +04:00
if ( POSFIXABLE ( n ) ) return LONG2FIX ( n ) ;
return rb_ull2big ( n ) ;
}
2002-03-14 09:23:46 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_ll2inum ( LONG_LONG n )
{
if ( FIXABLE ( n ) ) return LONG2FIX ( n ) ;
return rb_ll2big ( n ) ;
2002-03-14 09:23:46 +03:00
}
# endif /* HAVE_LONG_LONG */
2013-07-07 15:02:47 +04:00
VALUE
rb_cstr2inum ( const char * str , int base )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
return rb_cstr_to_inum ( str , base , base = = 0 ) ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_str2inum ( VALUE str , int base )
{
return rb_str_to_inum ( str , base , base = = 0 ) ;
}
1999-08-13 09:45:20 +04:00
2013-07-13 18:03:13 +04:00
static VALUE
big_shift3 ( VALUE x , int lshift_p , size_t shift_numdigits , int shift_numbits )
{
BDIGIT * xds , * zds ;
long s1 ;
int s2 ;
VALUE z ;
long xn ;
if ( lshift_p ) {
2013-07-16 14:08:25 +04:00
if ( LONG_MAX < shift_numdigits ) {
rb_raise ( rb_eArgError , " too big number " ) ;
}
s1 = shift_numdigits ;
s2 = shift_numbits ;
2013-07-13 18:03:13 +04:00
xn = RBIGNUM_LEN ( x ) ;
z = bignew ( xn + s1 + 1 , RBIGNUM_SIGN ( x ) ) ;
zds = BDIGITS ( z ) ;
2013-07-18 08:00:49 +04:00
BDIGITS_ZERO ( zds , s1 ) ;
2013-07-13 18:03:13 +04:00
xds = BDIGITS ( x ) ;
zds [ xn + s1 ] = bary_small_lshift ( zds + s1 , xds , xn , s2 ) ;
}
else {
long zn ;
BDIGIT hibitsx ;
2013-07-16 14:08:25 +04:00
if ( LONG_MAX < shift_numdigits | | ( size_t ) RBIGNUM_LEN ( x ) < = shift_numdigits ) {
2013-07-13 18:03:13 +04:00
if ( RBIGNUM_POSITIVE_P ( x ) | |
bary_zero_p ( BDIGITS ( x ) , RBIGNUM_LEN ( x ) ) )
return INT2FIX ( 0 ) ;
else
return INT2FIX ( - 1 ) ;
}
2013-07-16 14:08:25 +04:00
s1 = shift_numdigits ;
s2 = shift_numbits ;
2013-07-13 18:03:13 +04:00
hibitsx = abs2twocomp ( & x , & xn ) ;
xds = BDIGITS ( x ) ;
if ( xn < = s1 ) {
return hibitsx ? INT2FIX ( - 1 ) : INT2FIX ( 0 ) ;
}
zn = xn - s1 ;
z = bignew ( zn , 0 ) ;
zds = BDIGITS ( z ) ;
2013-08-16 04:19:51 +04:00
bary_small_rshift ( zds , xds + s1 , zn , s2 , hibitsx ! = 0 ? BDIGMAX : 0 ) ;
2013-07-13 18:03:13 +04:00
twocomp2abs_bang ( z , hibitsx ! = 0 ) ;
}
RB_GC_GUARD ( x ) ;
return z ;
}
static VALUE
big_shift2 ( VALUE x , int lshift_p , VALUE y )
{
int sign ;
size_t lens [ 2 ] ;
size_t shift_numdigits ;
int shift_numbits ;
assert ( POW2_P ( CHAR_BIT ) ) ;
assert ( POW2_P ( BITSPERDIG ) ) ;
if ( BIGZEROP ( x ) )
return INT2FIX ( 0 ) ;
sign = rb_integer_pack ( y , lens , numberof ( lens ) , sizeof ( size_t ) , 0 ,
INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
if ( sign < 0 ) {
lshift_p = ! lshift_p ;
sign = - sign ;
}
if ( lshift_p ) {
if ( 1 < sign | | CHAR_BIT < = lens [ 1 ] )
rb_raise ( rb_eRangeError , " shift width too big " ) ;
}
else {
if ( 1 < sign | | CHAR_BIT < = lens [ 1 ] )
return RBIGNUM_POSITIVE_P ( x ) ? INT2FIX ( 0 ) : INT2FIX ( - 1 ) ;
}
2013-07-15 06:11:15 +04:00
shift_numbits = ( int ) ( lens [ 0 ] & ( BITSPERDIG - 1 ) ) ;
2013-08-31 22:34:42 +04:00
shift_numdigits = ( lens [ 0 ] > > bit_length ( BITSPERDIG - 1 ) ) |
( lens [ 1 ] < < ( CHAR_BIT * SIZEOF_SIZE_T - bit_length ( BITSPERDIG - 1 ) ) ) ;
2013-07-13 18:03:13 +04:00
return big_shift3 ( x , lshift_p , shift_numdigits , shift_numbits ) ;
}
static VALUE
big_lshift ( VALUE x , unsigned long shift )
{
long s1 = shift / BITSPERDIG ;
int s2 = ( int ) ( shift % BITSPERDIG ) ;
return big_shift3 ( x , 1 , s1 , s2 ) ;
}
static VALUE
big_rshift ( VALUE x , unsigned long shift )
{
long s1 = shift / BITSPERDIG ;
int s2 = ( int ) ( shift % BITSPERDIG ) ;
return big_shift3 ( x , 0 , s1 , s2 ) ;
}
2013-08-03 08:32:33 +04:00
# define MAX_BASE36_POWER_TABLE_ENTRIES (SIZEOF_SIZE_T * CHAR_BIT + 1)
2013-07-07 15:02:47 +04:00
2013-08-03 08:32:33 +04:00
static VALUE base36_power_cache [ 35 ] [ MAX_BASE36_POWER_TABLE_ENTRIES ] ;
static size_t base36_numdigits_cache [ 35 ] [ MAX_BASE36_POWER_TABLE_ENTRIES ] ;
2013-07-07 15:02:47 +04:00
static void
power_cache_init ( void )
{
int i , j ;
for ( i = 0 ; i < 35 ; + + i ) {
2013-08-03 08:32:33 +04:00
for ( j = 0 ; j < MAX_BASE36_POWER_TABLE_ENTRIES ; + + j ) {
base36_power_cache [ i ] [ j ] = Qnil ;
2008-04-01 11:40:23 +04:00
}
1998-01-16 15:13:05 +03:00
}
2007-05-02 12:12:31 +04:00
}
2013-07-07 15:02:47 +04:00
static inline VALUE
2013-07-31 20:20:26 +04:00
power_cache_get_power ( int base , int power_level , size_t * numdigits_ret )
2007-05-02 12:12:31 +04:00
{
2013-07-31 20:21:11 +04:00
/*
2013-08-03 08:32:33 +04:00
* MAX_BASE36_POWER_TABLE_ENTRIES is big enough to that
* base36_power_cache [ base ] [ MAX_BASE36_POWER_TABLE_ENTRIES - 1 ] fills whole memory .
* So MAX_BASE36_POWER_TABLE_ENTRIES < = power_level is not possible to calculate .
2013-07-31 14:58:58 +04:00
*
2013-07-31 20:20:26 +04:00
* number - of - bytes =
2013-08-03 08:32:33 +04:00
* log256 ( base36_power_cache [ base ] [ MAX_BASE36_POWER_TABLE_ENTRIES - 1 ] ) =
* log256 ( maxpow_in_bdigit_dbl ( base ) * * ( 2 * * ( MAX_BASE36_POWER_TABLE_ENTRIES - 1 ) ) ) =
2013-07-31 20:20:26 +04:00
* log256 ( maxpow_in_bdigit_dbl ( base ) * * ( 2 * * ( SIZEOF_SIZE_T * CHAR_BIT ) ) ) =
* ( 2 * * ( SIZEOF_SIZE_T * CHAR_BIT ) ) * log256 ( maxpow_in_bdigit_dbl ( base ) ) =
* ( 256 * * SIZEOF_SIZE_T ) * log256 ( maxpow_in_bdigit_dbl ( base ) ) >
* ( 256 * * SIZEOF_SIZE_T ) * ( sizeof ( BDIGIT_DBL ) - 1 ) >
* 256 * * SIZEOF_SIZE_T
2013-07-31 14:58:58 +04:00
*/
2013-08-03 08:32:33 +04:00
if ( MAX_BASE36_POWER_TABLE_ENTRIES < = power_level )
2013-07-31 20:20:26 +04:00
rb_bug ( " too big power number requested: maxpow_in_bdigit_dbl(%d)**(2**%d) " , base , power_level ) ;
2013-08-03 08:32:33 +04:00
if ( NIL_P ( base36_power_cache [ base - 2 ] [ power_level ] ) ) {
2013-07-31 20:20:26 +04:00
VALUE power ;
size_t numdigits ;
if ( power_level = = 0 ) {
int numdigits0 ;
BDIGIT_DBL dd = maxpow_in_bdigit_dbl ( base , & numdigits0 ) ;
power = bignew ( 2 , 1 ) ;
2013-08-03 19:26:04 +04:00
bdigitdbl2bary ( BDIGITS ( power ) , 2 , dd ) ;
2013-07-31 20:20:26 +04:00
numdigits = numdigits0 ;
}
else {
2013-08-02 18:53:22 +04:00
power = bigtrunc ( bigsq ( power_cache_get_power ( base , power_level - 1 , & numdigits ) ) ) ;
2013-07-31 20:20:26 +04:00
numdigits * = 2 ;
}
2013-08-01 15:48:42 +04:00
rb_obj_hide ( power ) ;
2013-08-03 08:32:33 +04:00
base36_power_cache [ base - 2 ] [ power_level ] = power ;
base36_numdigits_cache [ base - 2 ] [ power_level ] = numdigits ;
2013-07-31 20:20:26 +04:00
rb_gc_register_mark_object ( power ) ;
2003-07-10 02:28:42 +04:00
}
2013-07-31 17:42:22 +04:00
if ( numdigits_ret )
2013-08-03 08:32:33 +04:00
* numdigits_ret = base36_numdigits_cache [ base - 2 ] [ power_level ] ;
return base36_power_cache [ base - 2 ] [ power_level ] ;
2012-07-16 14:39:42 +04:00
}
2013-08-01 14:19:23 +04:00
/*
* deprecated . ( used only from deprecated rb_big2str0 )
*
* big2str_muraken_find_n1
2013-02-23 07:35:38 +04:00
*
2013-07-07 15:02:47 +04:00
* Let a natural number x is given by :
* x = 2 ^ 0 * x_0 + 2 ^ 1 * x_1 + . . . + 2 ^ ( B * n_0 - 1 ) * x_ { B * n_0 - 1 } ,
* where B is BITSPERDIG ( i . e . BDIGITS * CHAR_BIT ) and n_0 is
* RBIGNUM_LEN ( x ) .
2007-05-09 07:49:18 +04:00
*
2013-07-07 15:02:47 +04:00
* Now , we assume n_1 = min_n \ { n | 2 ^ ( B * n_0 / 2 ) < = b_1 ^ ( n_1 ) \ } , so
* it is realized that 2 ^ ( B * n_0 ) < = { b_1 } ^ { 2 * n_1 } , where b_1 is a
* given radix number . And then , we have n_1 < = ( B * n_0 ) /
* ( 2 * log_2 ( b_1 ) ) , therefore n_1 is given by ceil ( ( B * n_0 ) /
* ( 2 * log_2 ( b_1 ) ) ) .
2003-12-19 06:58:57 +03:00
*/
2013-08-01 14:19:23 +04:00
static long
2013-07-07 15:02:47 +04:00
big2str_find_n1 ( VALUE x , int base )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
static const double log_2 [ ] = {
1.0 , 1.58496250072116 , 2.0 ,
2.32192809488736 , 2.58496250072116 , 2.8073549220576 ,
3.0 , 3.16992500144231 , 3.32192809488736 ,
3.4594316186373 , 3.58496250072116 , 3.70043971814109 ,
3.8073549220576 , 3.90689059560852 , 4.0 ,
4.08746284125034 , 4.16992500144231 , 4.24792751344359 ,
4.32192809488736 , 4.39231742277876 , 4.4594316186373 ,
4.52356195605701 , 4.58496250072116 , 4.64385618977472 ,
4.70043971814109 , 4.75488750216347 , 4.8073549220576 ,
4.85798099512757 , 4.90689059560852 , 4.95419631038688 ,
5.0 , 5.04439411935845 , 5.08746284125034 ,
5.12928301694497 , 5.16992500144231
} ;
long bits ;
if ( base < 2 | | 36 < base )
rb_bug ( " invalid radix %d " , base ) ;
if ( FIXNUM_P ( x ) ) {
bits = ( SIZEOF_LONG * CHAR_BIT - 1 ) / 2 + 1 ;
}
else if ( BIGZEROP ( x ) ) {
return 0 ;
}
else if ( RBIGNUM_LEN ( x ) > = LONG_MAX / BITSPERDIG ) {
rb_raise ( rb_eRangeError , " bignum too big to convert into `string' " ) ;
}
else {
bits = BITSPERDIG * RBIGNUM_LEN ( x ) ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
/* @shyouhei note: vvvvvvvvvvvvv this cast is suspicious. But I believe it is OK, because if that cast loses data, this x value is too big, and should have raised RangeError. */
return ( long ) ceil ( ( ( double ) bits ) / log_2 [ base - 2 ] ) ;
}
1998-01-16 15:13:05 +03:00
2013-07-31 07:20:35 +04:00
struct big2str_struct {
2013-08-01 07:43:14 +04:00
int negative ;
2013-07-31 07:20:35 +04:00
int base ;
2013-08-01 01:33:14 +04:00
BDIGIT_DBL hbase2 ;
int hbase2_numdigits ;
2013-08-01 07:43:14 +04:00
VALUE result ;
char * ptr ;
2013-07-31 07:20:35 +04:00
} ;
2013-08-01 07:43:14 +04:00
static void
big2str_alloc ( struct big2str_struct * b2s , size_t len )
{
if ( LONG_MAX - 1 < len )
rb_raise ( rb_eArgError , " too big number " ) ;
b2s - > result = rb_usascii_str_new ( 0 , ( long ) ( len + 1 ) ) ; /* plus one for sign */
b2s - > ptr = RSTRING_PTR ( b2s - > result ) ;
if ( b2s - > negative )
* b2s - > ptr + + = ' - ' ;
}
static void
2013-09-01 10:21:52 +04:00
big2str_2bdigits ( struct big2str_struct * b2s , BDIGIT * xds , size_t xn , size_t taillen )
2013-07-07 15:02:47 +04:00
{
2013-08-01 02:38:53 +04:00
size_t j ;
2013-08-01 01:33:14 +04:00
BDIGIT_DBL num ;
2013-08-01 02:38:53 +04:00
char buf [ SIZEOF_BDIGIT_DBL * CHAR_BIT ] , * p ;
2013-08-02 20:42:40 +04:00
int beginning = ! b2s - > ptr ;
2013-08-02 02:49:12 +04:00
size_t len = 0 ;
1998-01-16 15:13:05 +03:00
2013-08-03 17:27:25 +04:00
assert ( xn < = 2 ) ;
2013-08-03 19:26:04 +04:00
num = bary2bdigitdbl ( xds , xn ) ;
2013-08-01 07:43:14 +04:00
2013-08-02 20:42:40 +04:00
if ( beginning ) {
2013-08-02 02:49:12 +04:00
if ( num = = 0 )
return ;
2013-08-01 02:38:53 +04:00
p = buf ;
j = sizeof ( buf ) ;
2013-08-02 21:24:19 +04:00
do {
p [ - - j ] = ruby_digitmap [ num % b2s - > base ] ;
num / = b2s - > base ;
} while ( num ) ;
2013-08-01 02:38:53 +04:00
len = sizeof ( buf ) - j ;
2013-08-01 07:43:14 +04:00
big2str_alloc ( b2s , len + taillen ) ;
MEMCPY ( b2s - > ptr , buf + j , char , len ) ;
2013-07-07 15:02:47 +04:00
}
2013-08-02 21:24:19 +04:00
else {
p = b2s - > ptr ;
j = b2s - > hbase2_numdigits ;
do {
p [ - - j ] = ruby_digitmap [ num % b2s - > base ] ;
num / = b2s - > base ;
} while ( j ) ;
len = b2s - > hbase2_numdigits ;
}
2013-08-01 07:43:14 +04:00
b2s - > ptr + = len ;
1998-01-16 15:13:05 +03:00
}
2013-08-01 07:43:14 +04:00
static void
2013-08-15 18:25:19 +04:00
big2str_karatsuba ( struct big2str_struct * b2s , BDIGIT * xds , size_t xn , size_t wn ,
int power_level , size_t taillen )
2010-02-04 18:36:29 +03:00
{
2013-08-03 17:27:25 +04:00
VALUE b ;
2013-08-02 13:36:23 +04:00
size_t half_numdigits , lower_numdigits ;
int lower_power_level ;
2013-08-03 17:27:25 +04:00
size_t bn ;
2013-08-15 18:25:19 +04:00
const BDIGIT * bds ;
2013-08-02 02:49:12 +04:00
size_t len ;
2010-02-04 18:36:29 +03:00
2013-08-02 13:36:23 +04:00
/*
* Precondition :
2013-08-02 19:55:07 +04:00
* abs ( x ) < maxpow * * ( 2 * * power_level )
* where
* maxpow = maxpow_in_bdigit_dbl ( base , & numdigits )
2013-08-02 13:36:23 +04:00
*
* This function generates sequence of zeros , and then stringized abs ( x ) into b2s - > ptr .
*
* b2s - > ptr can be NULL .
* It is allocated when the first character is generated via big2str_alloc .
*
* The prefix zeros should be generated if and only if b2s - > ptr is not NULL .
* When the zeros are generated , the zeros and abs ( x ) consists
* numdigits * ( 2 * * power_level ) characters at total .
*
* Note :
* power_cache_get_power ( base , power_level , & len ) may not be cached yet . It should not be called .
* power_cache_get_power ( base , power_level - 1 , & len ) should be cached already if 0 < = power_level - 1.
*/
2013-08-03 17:27:25 +04:00
if ( xn = = 0 | | bary_zero_p ( xds , xn ) ) {
2013-08-01 07:43:14 +04:00
if ( b2s - > ptr ) {
2013-08-02 13:36:23 +04:00
/* When x is zero, power_cache_get_power(base, power_level) should be cached already. */
power_cache_get_power ( b2s - > base , power_level , & len ) ;
2013-08-01 07:43:14 +04:00
memset ( b2s - > ptr , ' 0 ' , len ) ;
b2s - > ptr + = len ;
2010-02-04 18:36:29 +03:00
}
2013-08-01 07:43:14 +04:00
return ;
2010-02-04 18:36:29 +03:00
}
2013-08-02 13:36:23 +04:00
if ( power_level = = 0 ) {
2013-09-01 10:21:52 +04:00
big2str_2bdigits ( b2s , xds , xn , taillen ) ;
2013-08-01 07:43:14 +04:00
return ;
2010-02-04 18:36:29 +03:00
}
2013-08-02 13:36:23 +04:00
lower_power_level = power_level - 1 ;
b = power_cache_get_power ( b2s - > base , lower_power_level , & lower_numdigits ) ;
bn = RBIGNUM_LEN ( b ) ;
bds = BDIGITS ( b ) ;
half_numdigits = lower_numdigits ;
while ( 0 < lower_power_level & &
( xn < bn | |
( xn = = bn & & bary_cmp ( xds , xn , bds , bn ) < 0 ) ) ) {
lower_power_level - - ;
b = power_cache_get_power ( b2s - > base , lower_power_level , & lower_numdigits ) ;
bn = RBIGNUM_LEN ( b ) ;
bds = BDIGITS ( b ) ;
}
if ( lower_power_level = = 0 & &
( xn < bn | |
( xn = = bn & & bary_cmp ( xds , xn , bds , bn ) < 0 ) ) ) {
2013-08-02 18:53:22 +04:00
if ( b2s - > ptr ) {
len = half_numdigits * 2 - lower_numdigits ;
memset ( b2s - > ptr , ' 0 ' , len ) ;
b2s - > ptr + = len ;
}
2013-09-01 10:21:52 +04:00
big2str_2bdigits ( b2s , xds , xn , taillen ) ;
2013-08-02 13:36:23 +04:00
}
else {
2013-08-03 17:27:25 +04:00
BDIGIT * qds , * rds ;
size_t qn , rn ;
2013-08-15 18:25:19 +04:00
BDIGIT * tds ;
int shift ;
2013-08-02 18:53:22 +04:00
if ( lower_power_level ! = power_level - 1 & & b2s - > ptr ) {
len = ( half_numdigits - lower_numdigits ) * 2 ;
memset ( b2s - > ptr , ' 0 ' , len ) ;
b2s - > ptr + = len ;
}
2013-08-15 18:25:19 +04:00
shift = nlz ( bds [ bn - 1 ] ) ;
2013-08-17 19:48:44 +04:00
qn = xn + BIGDIVREM_EXTRA_WORDS ;
2013-08-15 18:25:19 +04:00
if ( shift = = 0 ) {
/* bigdivrem_restoring will not modify y.
* So use bds directly . */
tds = ( BDIGIT * ) bds ;
xds [ xn ] = 0 ;
}
else {
/* bigdivrem_restoring will modify y.
* So use temporary buffer . */
tds = xds + qn ;
assert ( qn + bn < = xn + wn ) ;
bary_small_lshift ( tds , bds , bn , shift ) ;
xds [ xn ] = bary_small_lshift ( xds , xds , xn , shift ) ;
}
bigdivrem_restoring ( xds , qn , tds , bn ) ;
rds = xds ;
2013-08-03 20:01:14 +04:00
rn = bn ;
2013-08-15 18:25:19 +04:00
qds = xds + bn ;
qn = qn - bn ;
if ( shift ) {
bary_small_rshift ( rds , rds , rn , shift , 0 ) ;
2013-08-03 17:27:25 +04:00
}
2013-08-15 18:25:19 +04:00
2013-08-03 20:58:30 +04:00
BARY_TRUNC ( qds , qn ) ;
2013-08-03 17:27:25 +04:00
assert ( qn < = bn ) ;
2013-08-15 18:25:19 +04:00
big2str_karatsuba ( b2s , qds , qn , xn + wn - ( rn + qn ) , lower_power_level , lower_numdigits + taillen ) ;
2013-08-03 20:58:30 +04:00
BARY_TRUNC ( rds , rn ) ;
2013-08-15 18:25:19 +04:00
big2str_karatsuba ( b2s , rds , rn , xn + wn - rn , lower_power_level , taillen ) ;
2013-08-02 13:36:23 +04:00
}
2010-02-04 18:36:29 +03:00
}
static VALUE
2013-09-01 15:35:57 +04:00
big2str_base_poweroftwo ( VALUE x , int base )
2010-02-04 18:36:29 +03:00
{
2013-07-07 15:02:47 +04:00
int word_numbits = ffs ( base ) - 1 ;
size_t numwords ;
VALUE result ;
char * ptr ;
2013-08-01 14:19:23 +04:00
numwords = rb_absint_numwords ( x , word_numbits , NULL ) ;
if ( RBIGNUM_NEGATIVE_P ( x ) ) {
2013-07-07 15:02:47 +04:00
if ( LONG_MAX - 1 < numwords )
rb_raise ( rb_eArgError , " too big number " ) ;
result = rb_usascii_str_new ( 0 , 1 + numwords ) ;
ptr = RSTRING_PTR ( result ) ;
* ptr + + = RBIGNUM_POSITIVE_P ( x ) ? ' + ' : ' - ' ;
}
else {
if ( LONG_MAX < numwords )
rb_raise ( rb_eArgError , " too big number " ) ;
result = rb_usascii_str_new ( 0 , numwords ) ;
ptr = RSTRING_PTR ( result ) ;
}
rb_integer_pack ( x , ptr , numwords , 1 , CHAR_BIT - word_numbits ,
INTEGER_PACK_BIG_ENDIAN ) ;
while ( 0 < numwords ) {
* ptr = ruby_digitmap [ * ( unsigned char * ) ptr ] ;
ptr + + ;
numwords - - ;
}
return result ;
2010-02-04 18:36:29 +03:00
}
2013-09-01 15:35:57 +04:00
VALUE
rb_big2str_poweroftwo ( VALUE x , int base )
{
return big2str_base_poweroftwo ( x , base ) ;
}
2013-07-15 09:42:22 +04:00
static VALUE
2013-09-01 20:47:20 +04:00
big2str_generic ( VALUE x , int base )
2010-02-04 18:36:29 +03:00
{
2013-09-01 20:47:20 +04:00
BDIGIT * xds ;
size_t xn ;
2013-07-31 07:20:35 +04:00
struct big2str_struct b2s_data ;
2013-07-31 17:42:22 +04:00
int power_level ;
VALUE power ;
1998-01-16 15:13:05 +03:00
2013-09-01 20:47:20 +04:00
xds = BDIGITS ( x ) ;
xn = RBIGNUM_LEN ( x ) ;
BARY_TRUNC ( xds , xn ) ;
if ( xn = = 0 ) {
return rb_usascii_str_new2 ( " 0 " ) ;
}
if ( base < 2 | | 36 < base )
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
if ( xn > = LONG_MAX / BITSPERDIG ) {
rb_raise ( rb_eRangeError , " bignum too big to convert into `string' " ) ;
}
2013-07-31 17:42:22 +04:00
power_level = 0 ;
2013-07-31 20:20:26 +04:00
power = power_cache_get_power ( base , power_level , NULL ) ;
2013-08-03 08:32:33 +04:00
while ( power_level < MAX_BASE36_POWER_TABLE_ENTRIES & &
2013-08-15 19:36:00 +04:00
( size_t ) RBIGNUM_LEN ( power ) < = ( xn + 1 ) / 2 ) {
2013-07-31 17:42:22 +04:00
power_level + + ;
2013-07-31 20:20:26 +04:00
power = power_cache_get_power ( base , power_level , NULL ) ;
2013-07-31 17:42:22 +04:00
}
2013-08-03 08:32:33 +04:00
assert ( power_level ! = MAX_BASE36_POWER_TABLE_ENTRIES ) ;
2013-08-02 13:36:23 +04:00
2013-08-15 19:36:00 +04:00
if ( ( size_t ) RBIGNUM_LEN ( power ) < = xn ) {
2013-08-02 18:53:22 +04:00
/*
2013-08-02 19:55:07 +04:00
* This increment guarantees x < power_cache_get_power ( base , power_level )
* without invoking it actually .
* ( power_cache_get_power ( base , power_level ) can be slow and not used
* in big2str_karatsuba . )
*
* Although it is possible that x < power_cache_get_power ( base , power_level - 1 ) ,
* it is no problem because big2str_karatsuba checks it and
* doesn ' t affect the result when b2s_data . ptr is NULL .
*/
power_level + + ;
2013-07-31 17:42:22 +04:00
}
2013-08-01 07:43:14 +04:00
b2s_data . negative = RBIGNUM_NEGATIVE_P ( x ) ;
2013-07-31 07:20:35 +04:00
b2s_data . base = base ;
2013-08-01 01:33:14 +04:00
b2s_data . hbase2 = maxpow_in_bdigit_dbl ( base , & b2s_data . hbase2_numdigits ) ;
2013-08-01 07:43:14 +04:00
2013-08-01 14:19:23 +04:00
b2s_data . result = Qnil ;
b2s_data . ptr = NULL ;
2013-08-01 07:43:14 +04:00
2013-08-02 13:36:23 +04:00
if ( power_level = = 0 ) {
2013-09-01 10:21:52 +04:00
big2str_2bdigits ( & b2s_data , xds , xn , 0 ) ;
2013-07-07 15:02:47 +04:00
}
else {
2013-08-15 19:36:00 +04:00
VALUE tmpw = 0 ;
BDIGIT * wds ;
size_t wn ;
2013-08-18 05:07:50 +04:00
wn = power_level * BIGDIVREM_EXTRA_WORDS + RBIGNUM_LEN ( power ) ;
2013-08-15 19:36:00 +04:00
wds = ALLOCV_N ( BDIGIT , tmpw , xn + wn ) ;
MEMCPY ( wds , xds , BDIGIT , xn ) ;
big2str_karatsuba ( & b2s_data , wds , xn , wn , power_level , 0 ) ;
if ( tmpw )
ALLOCV_END ( tmpw ) ;
2013-07-07 15:02:47 +04:00
}
2013-08-03 17:27:25 +04:00
RB_GC_GUARD ( x ) ;
2013-07-07 15:02:47 +04:00
2013-08-01 07:43:14 +04:00
* b2s_data . ptr = ' \0 ' ;
rb_str_resize ( b2s_data . result , ( long ) ( b2s_data . ptr - RSTRING_PTR ( b2s_data . result ) ) ) ;
2013-07-07 15:02:47 +04:00
2013-09-01 20:47:20 +04:00
RB_GC_GUARD ( x ) ;
2013-08-01 07:43:14 +04:00
return b2s_data . result ;
2013-07-07 15:02:47 +04:00
}
2003-12-19 06:58:57 +03:00
2013-09-01 15:35:57 +04:00
VALUE
rb_big2str_generic ( VALUE x , int base )
{
2013-09-01 20:47:20 +04:00
return big2str_generic ( x , base ) ;
2013-09-01 15:35:57 +04:00
}
2013-09-01 18:34:53 +04:00
# ifdef USE_GMP
VALUE
2013-09-01 20:47:20 +04:00
big2str_gmp ( VALUE x , int base )
2013-09-01 18:34:53 +04:00
{
const size_t nails = ( sizeof ( BDIGIT ) - SIZEOF_BDIGITS ) * CHAR_BIT ;
2013-09-01 20:47:20 +04:00
mpz_t mx ;
2013-09-01 18:34:53 +04:00
size_t size ;
VALUE str ;
2013-09-01 20:47:20 +04:00
BDIGIT * xds = BDIGITS ( x ) ;
size_t xn = RBIGNUM_LEN ( x ) ;
2013-09-01 18:34:53 +04:00
2013-09-01 20:47:20 +04:00
mpz_init ( mx ) ;
mpz_import ( mx , xn , - 1 , sizeof ( BDIGIT ) , 0 , nails , xds ) ;
2013-09-01 18:34:53 +04:00
2013-09-01 20:47:20 +04:00
size = mpz_sizeinbase ( mx , base ) ;
2013-09-01 18:34:53 +04:00
2013-09-01 20:47:20 +04:00
if ( RBIGNUM_NEGATIVE_P ( x ) ) {
mpz_neg ( mx , mx ) ;
2013-09-01 18:34:53 +04:00
str = rb_usascii_str_new ( 0 , size + 1 ) ;
}
else {
str = rb_usascii_str_new ( 0 , size ) ;
}
2013-09-01 20:47:20 +04:00
mpz_get_str ( RSTRING_PTR ( str ) , base , mx ) ;
mpz_clear ( mx ) ;
2013-09-01 18:34:53 +04:00
if ( RSTRING_PTR ( str ) [ RSTRING_LEN ( str ) - 1 ] = = ' \0 ' ) {
rb_str_set_len ( str , RSTRING_LEN ( str ) - 1 ) ;
}
2013-09-01 20:47:20 +04:00
RB_GC_GUARD ( x ) ;
2013-09-01 18:34:53 +04:00
return str ;
}
VALUE
rb_big2str_gmp ( VALUE x , int base )
{
2013-09-01 20:47:20 +04:00
return big2str_gmp ( x , base ) ;
2013-09-01 18:34:53 +04:00
}
# endif
2013-09-01 15:35:57 +04:00
static VALUE
rb_big2str1 ( VALUE x , int base )
{
BDIGIT * xds ;
size_t xn ;
if ( FIXNUM_P ( x ) ) {
return rb_fix2str ( x , base ) ;
}
2013-09-01 20:47:20 +04:00
bigtrunc ( x ) ;
2013-09-01 15:35:57 +04:00
xds = BDIGITS ( x ) ;
xn = RBIGNUM_LEN ( x ) ;
BARY_TRUNC ( xds , xn ) ;
if ( xn = = 0 ) {
return rb_usascii_str_new2 ( " 0 " ) ;
}
if ( base < 2 | | 36 < base )
rb_raise ( rb_eArgError , " invalid radix %d " , base ) ;
if ( xn > = LONG_MAX / BITSPERDIG ) {
rb_raise ( rb_eRangeError , " bignum too big to convert into `string' " ) ;
}
if ( POW2_P ( base ) ) {
/* base == 2 || base == 4 || base == 8 || base == 16 || base == 32 */
return big2str_base_poweroftwo ( x , base ) ;
}
2013-09-01 18:34:53 +04:00
# ifdef USE_GMP
if ( GMP_BIG2STR_DIGITS < xn ) {
2013-09-01 20:47:20 +04:00
return big2str_gmp ( x , base ) ;
2013-09-01 18:34:53 +04:00
}
# endif
2013-09-01 20:47:20 +04:00
return big2str_generic ( x , base ) ;
2013-09-01 15:35:57 +04:00
}
2013-07-15 09:42:22 +04:00
/* deprecated */
VALUE
rb_big2str0 ( VALUE x , int base , int trim )
{
2013-08-01 14:19:23 +04:00
VALUE str ;
long oldlen ;
long n2 ;
str = rb_big2str1 ( x , base ) ;
if ( trim | | FIXNUM_P ( x ) | | BIGZEROP ( x ) )
return str ;
oldlen = RSTRING_LEN ( str ) ;
if ( oldlen & & RSTRING_PTR ( str ) [ 0 ] ! = ' - ' ) {
rb_str_resize ( str , oldlen + 1 ) ;
MEMMOVE ( RSTRING_PTR ( str ) + 1 , RSTRING_PTR ( str ) , char , oldlen ) ;
RSTRING_PTR ( str ) [ 0 ] = ' + ' ;
}
n2 = big2str_find_n1 ( x , base ) ;
oldlen = RSTRING_LEN ( str ) ;
if ( oldlen - 1 < n2 ) {
long off = n2 - ( oldlen - 1 ) ;
rb_str_resize ( str , n2 + 1 ) ;
MEMMOVE ( RSTRING_PTR ( str ) + 1 + off , RSTRING_PTR ( str ) + 1 , char , oldlen - 1 ) ;
memset ( RSTRING_PTR ( str ) + 1 , ' 0 ' , off ) ;
}
RSTRING_PTR ( str ) [ RSTRING_LEN ( str ) ] = ' \0 ' ;
return str ;
2013-07-15 09:42:22 +04:00
}
2012-12-25 14:14:12 +04:00
VALUE
2013-07-07 15:02:47 +04:00
rb_big2str ( VALUE x , int base )
2001-11-08 09:43:14 +03:00
{
2013-08-01 14:19:23 +04:00
return rb_big2str1 ( x , base ) ;
2001-11-08 09:43:14 +03:00
}
2003-12-19 03:01:19 +03:00
/*
2013-07-07 15:02:47 +04:00
* call - seq :
* big . to_s ( base = 10 ) - > string
2003-12-19 03:01:19 +03:00
*
2013-07-07 15:02:47 +04:00
* Returns a string containing the representation of < i > big < / i > radix
* < i > base < / i > ( 2 through 36 ) .
*
* 12345654321. to_s # = > " 12345654321 "
* 12345654321. to_s ( 2 ) # = > " 1011011111110110111011110000110001 "
* 12345654321. to_s ( 8 ) # = > " 133766736061 "
* 12345654321. to_s ( 16 ) # = > " 2dfdbbc31 "
* 78546939656932. to_s ( 36 ) # = > " rubyrules "
2003-12-19 03:01:19 +03:00
*/
2013-07-07 15:02:47 +04:00
static VALUE
rb_big_to_s ( int argc , VALUE * argv , VALUE x )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
int base ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
if ( argc = = 0 ) base = 10 ;
else {
VALUE b ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
rb_scan_args ( argc , argv , " 01 " , & b ) ;
base = NUM2INT ( b ) ;
}
return rb_big2str ( x , base ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
static unsigned long
big2ulong ( VALUE x , const char * type )
{
long len = RBIGNUM_LEN ( x ) ;
unsigned long num ;
BDIGIT * ds ;
2003-12-19 06:58:57 +03:00
2013-07-07 15:02:47 +04:00
if ( len = = 0 )
return 0 ;
if ( BIGSIZE ( x ) > sizeof ( long ) ) {
rb_raise ( rb_eRangeError , " bignum too big to convert into `%s' " , type ) ;
}
ds = BDIGITS ( x ) ;
# if SIZEOF_LONG <= SIZEOF_BDIGITS
num = ( unsigned long ) ds [ 0 ] ;
# else
num = 0 ;
while ( len - - ) {
num < < = BITSPERDIG ;
num + = ( unsigned long ) ds [ len ] ; /* overflow is already checked */
}
# endif
return num ;
}
2013-08-02 13:36:23 +04:00
/* deprecated */
2013-07-07 15:02:47 +04:00
VALUE
rb_big2ulong_pack ( VALUE x )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
unsigned long num ;
rb_integer_pack ( x , & num , 1 , sizeof ( num ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER | INTEGER_PACK_2COMP ) ;
return num ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big2ulong ( VALUE x )
{
unsigned long num = big2ulong ( x , " unsigned long " ) ;
2013-06-29 19:57:07 +04:00
2013-07-07 15:02:47 +04:00
if ( RBIGNUM_POSITIVE_P ( x ) ) {
return num ;
2013-06-29 19:57:07 +04:00
}
else {
2013-07-07 15:02:47 +04:00
if ( num < = LONG_MAX )
return - ( long ) num ;
if ( num = = 1 + ( unsigned long ) ( - ( LONG_MIN + 1 ) ) )
return LONG_MIN ;
2013-06-29 19:57:07 +04:00
}
2013-07-07 15:02:47 +04:00
rb_raise ( rb_eRangeError , " bignum out of range of unsigned long " ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
SIGNED_VALUE
rb_big2long ( VALUE x )
2013-07-07 10:03:52 +04:00
{
2013-07-07 15:02:47 +04:00
unsigned long num = big2ulong ( x , " long " ) ;
if ( RBIGNUM_POSITIVE_P ( x ) ) {
if ( num < = LONG_MAX )
return num ;
}
else {
if ( num < = LONG_MAX )
return - ( long ) num ;
if ( num = = 1 + ( unsigned long ) ( - ( LONG_MIN + 1 ) ) )
return LONG_MIN ;
}
rb_raise ( rb_eRangeError , " bignum too big to convert into `long' " ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
# if HAVE_LONG_LONG
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static unsigned LONG_LONG
big2ull ( VALUE x , const char * type )
{
long len = RBIGNUM_LEN ( x ) ;
unsigned LONG_LONG num ;
BDIGIT * ds = BDIGITS ( x ) ;
2008-12-14 06:59:02 +03:00
2013-07-07 15:02:47 +04:00
if ( len = = 0 )
return 0 ;
if ( BIGSIZE ( x ) > SIZEOF_LONG_LONG )
rb_raise ( rb_eRangeError , " bignum too big to convert into `%s' " , type ) ;
# if SIZEOF_LONG_LONG <= SIZEOF_BDIGITS
num = ( unsigned LONG_LONG ) ds [ 0 ] ;
# else
num = 0 ;
while ( len - - ) {
num = BIGUP ( num ) ;
num + = ds [ len ] ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
# endif
return num ;
}
unsigned LONG_LONG
rb_big2ull ( VALUE x )
{
unsigned LONG_LONG num = big2ull ( x , " unsigned long long " ) ;
if ( RBIGNUM_POSITIVE_P ( x ) ) {
return num ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
else {
if ( num < = LLONG_MAX )
return - ( LONG_LONG ) num ;
if ( num = = 1 + ( unsigned LONG_LONG ) ( - ( LLONG_MIN + 1 ) ) )
return LLONG_MIN ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
rb_raise ( rb_eRangeError , " bignum out of range of unsigned long long " ) ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
LONG_LONG
rb_big2ll ( VALUE x )
{
unsigned LONG_LONG num = big2ull ( x , " long long " ) ;
if ( RBIGNUM_POSITIVE_P ( x ) ) {
if ( num < = LLONG_MAX )
return num ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
else {
if ( num < = LLONG_MAX )
return - ( LONG_LONG ) num ;
if ( num = = 1 + ( unsigned LONG_LONG ) ( - ( LLONG_MIN + 1 ) ) )
return LLONG_MIN ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
rb_raise ( rb_eRangeError , " bignum too big to convert into `long long' " ) ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
# endif /* HAVE_LONG_LONG */
static VALUE
dbl2big ( double d )
2013-06-15 18:52:02 +04:00
{
2013-07-07 15:02:47 +04:00
long i = 0 ;
BDIGIT c ;
BDIGIT * digits ;
VALUE z ;
double u = ( d < 0 ) ? - d : d ;
if ( isinf ( d ) ) {
rb_raise ( rb_eFloatDomainError , d < 0 ? " -Infinity " : " Infinity " ) ;
}
if ( isnan ( d ) ) {
rb_raise ( rb_eFloatDomainError , " NaN " ) ;
}
2013-08-07 14:31:35 +04:00
while ( 1.0 < = u ) {
2013-07-07 15:02:47 +04:00
u / = ( double ) ( BIGRAD ) ;
i + + ;
}
z = bignew ( i , d > = 0 ) ;
digits = BDIGITS ( z ) ;
while ( i - - ) {
u * = BIGRAD ;
c = ( BDIGIT ) u ;
u - = c ;
digits [ i ] = c ;
}
return z ;
2013-07-07 10:03:52 +04:00
}
2013-06-15 18:52:02 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_dbl2big ( double d )
2013-07-07 10:03:52 +04:00
{
2013-07-07 15:02:47 +04:00
return bignorm ( dbl2big ( d ) ) ;
2013-06-15 18:52:02 +04:00
}
2013-07-07 15:02:47 +04:00
static double
big2dbl ( VALUE x )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
double d = 0.0 ;
long i = ( bigtrunc ( x ) , RBIGNUM_LEN ( x ) ) , lo = 0 , bits ;
BDIGIT * ds = BDIGITS ( x ) , dl ;
2007-05-09 07:49:18 +04:00
2013-07-07 15:02:47 +04:00
if ( i ) {
bits = i * BITSPERDIG - nlz ( ds [ i - 1 ] ) ;
if ( bits > DBL_MANT_DIG + DBL_MAX_EXP ) {
d = HUGE_VAL ;
}
else {
if ( bits > DBL_MANT_DIG + 1 )
lo = ( bits - = DBL_MANT_DIG + 1 ) / BITSPERDIG ;
else
bits = 0 ;
while ( - - i > lo ) {
d = ds [ i ] + BIGRAD * d ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
dl = ds [ i ] ;
if ( bits & & ( dl & ( ( BDIGIT ) 1 < < ( bits % = BITSPERDIG ) ) ) ) {
int carry = ( dl & ~ ( BDIGMAX < < bits ) ) ! = 0 ;
if ( ! carry ) {
while ( i - - > 0 ) {
carry = ds [ i ] ! = 0 ;
if ( carry ) break ;
}
}
if ( carry ) {
dl & = BDIGMAX < < bits ;
dl = BIGLO ( dl + ( ( BDIGIT ) 1 < < bits ) ) ;
if ( ! dl ) d + = 1 ;
}
}
d = dl + BIGRAD * d ;
if ( lo ) {
if ( lo > INT_MAX / BITSPERDIG )
d = HUGE_VAL ;
else if ( lo < INT_MIN / BITSPERDIG )
d = 0.0 ;
else
d = ldexp ( d , ( int ) ( lo * BITSPERDIG ) ) ;
1998-01-16 15:13:05 +03:00
}
}
}
2013-07-07 15:02:47 +04:00
if ( ! RBIGNUM_SIGN ( x ) ) d = - d ;
return d ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
double
rb_big2dbl ( VALUE x )
{
double d = big2dbl ( x ) ;
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
if ( isinf ( d ) ) {
rb_warning ( " Bignum out of Float range " ) ;
if ( d < 0.0 )
d = - HUGE_VAL ;
else
d = HUGE_VAL ;
}
return d ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big . to_f - > float
*
* Converts < i > big < / i > to a < code > Float < / code > . If < i > big < / i > doesn ' t
* fit in a < code > Float < / code > , the result is infinity .
*
*/
2009-04-20 21:53:36 +04:00
static VALUE
2013-07-07 15:02:47 +04:00
rb_big_to_f ( VALUE x )
2009-04-20 21:53:36 +04:00
{
2013-07-07 15:02:47 +04:00
return DBL2NUM ( rb_big2dbl ( x ) ) ;
}
2013-06-25 20:18:32 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_integer_float_cmp ( VALUE x , VALUE y )
{
double yd = RFLOAT_VALUE ( y ) ;
double yi , yf ;
VALUE rel ;
2009-04-20 21:53:36 +04:00
2013-07-07 15:02:47 +04:00
if ( isnan ( yd ) )
return Qnil ;
if ( isinf ( yd ) ) {
if ( yd > 0.0 ) return INT2FIX ( - 1 ) ;
else return INT2FIX ( 1 ) ;
2009-04-20 21:53:36 +04:00
}
2013-07-07 15:02:47 +04:00
yf = modf ( yd , & yi ) ;
if ( FIXNUM_P ( x ) ) {
# if SIZEOF_LONG * CHAR_BIT < DBL_MANT_DIG /* assume FLT_RADIX == 2 */
double xd = ( double ) FIX2LONG ( x ) ;
if ( xd < yd )
return INT2FIX ( - 1 ) ;
if ( xd > yd )
return INT2FIX ( 1 ) ;
return INT2FIX ( 0 ) ;
2009-04-20 21:53:36 +04:00
# else
2013-08-05 18:50:07 +04:00
long xn , yn ;
2013-07-07 15:02:47 +04:00
if ( yi < FIXNUM_MIN )
return INT2FIX ( 1 ) ;
if ( FIXNUM_MAX + 1 < = yi )
return INT2FIX ( - 1 ) ;
2013-08-05 18:50:07 +04:00
xn = FIX2LONG ( x ) ;
yn = ( long ) yi ;
if ( xn < yn )
2013-07-07 15:02:47 +04:00
return INT2FIX ( - 1 ) ;
2013-08-05 18:50:07 +04:00
if ( xn > yn )
2013-07-07 15:02:47 +04:00
return INT2FIX ( 1 ) ;
if ( yf < 0.0 )
return INT2FIX ( 1 ) ;
if ( 0.0 < yf )
return INT2FIX ( - 1 ) ;
return INT2FIX ( 0 ) ;
2009-04-20 21:53:36 +04:00
# endif
2013-06-25 20:18:32 +04:00
}
2013-07-07 15:02:47 +04:00
y = rb_dbl2big ( yi ) ;
rel = rb_big_cmp ( x , y ) ;
if ( yf = = 0.0 | | rel ! = INT2FIX ( 0 ) )
return rel ;
if ( yf < 0.0 )
return INT2FIX ( 1 ) ;
return INT2FIX ( - 1 ) ;
}
2013-06-25 20:18:32 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_integer_float_eq ( VALUE x , VALUE y )
{
double yd = RFLOAT_VALUE ( y ) ;
double yi , yf ;
2013-06-25 20:18:32 +04:00
2013-07-07 15:02:47 +04:00
if ( isnan ( yd ) | | isinf ( yd ) )
return Qfalse ;
yf = modf ( yd , & yi ) ;
if ( yf ! = 0 )
return Qfalse ;
if ( FIXNUM_P ( x ) ) {
# if SIZEOF_LONG * CHAR_BIT < DBL_MANT_DIG /* assume FLT_RADIX == 2 */
double xd = ( double ) FIX2LONG ( x ) ;
if ( xd ! = yd )
return Qfalse ;
return Qtrue ;
# else
2013-08-05 18:50:07 +04:00
long xn , yn ;
2013-07-07 15:02:47 +04:00
if ( yi < LONG_MIN | | LONG_MAX < yi )
return Qfalse ;
2013-08-05 18:50:07 +04:00
xn = FIX2LONG ( x ) ;
yn = ( long ) yi ;
if ( xn ! = yn )
2013-07-07 15:02:47 +04:00
return Qfalse ;
return Qtrue ;
# endif
2009-04-20 21:53:36 +04:00
}
2013-07-07 15:02:47 +04:00
y = rb_dbl2big ( yi ) ;
return rb_big_eq ( x , y ) ;
2009-04-20 21:53:36 +04:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big < = > numeric - > - 1 , 0 , + 1 or nil
*
* Comparison - - - Returns - 1 , 0 , or + 1 depending on whether + big + is
* less than , equal to , or greater than + numeric + . This is the
* basis for the tests in Comparable .
*
* + nil + is returned if the two values are incomparable .
*
*/
VALUE
rb_big_cmp ( VALUE x , VALUE y )
2009-04-20 21:53:36 +04:00
{
2013-07-31 17:42:22 +04:00
int cmp ;
2009-04-20 21:53:36 +04:00
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2013-07-07 15:02:47 +04:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return rb_integer_float_cmp ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else {
2013-07-07 15:02:47 +04:00
return rb_num_coerce_cmp ( x , y , rb_intern ( " <=> " ) ) ;
2013-06-26 01:53:58 +04:00
}
2013-07-07 15:02:47 +04:00
if ( RBIGNUM_SIGN ( x ) > RBIGNUM_SIGN ( y ) ) return INT2FIX ( 1 ) ;
if ( RBIGNUM_SIGN ( x ) < RBIGNUM_SIGN ( y ) ) return INT2FIX ( - 1 ) ;
2013-07-31 17:42:22 +04:00
cmp = bary_cmp ( BDIGITS ( x ) , RBIGNUM_LEN ( x ) , BDIGITS ( y ) , RBIGNUM_LEN ( y ) ) ;
if ( RBIGNUM_SIGN ( x ) )
return INT2FIX ( cmp ) ;
else
return INT2FIX ( - cmp ) ;
2009-04-20 21:53:36 +04:00
}
2013-07-07 15:02:47 +04:00
enum big_op_t {
big_op_gt ,
big_op_ge ,
big_op_lt ,
big_op_le
} ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
big_op ( VALUE x , VALUE y , enum big_op_t op )
2013-07-07 10:03:52 +04:00
{
2013-07-07 15:02:47 +04:00
VALUE rel ;
int n ;
2013-07-07 10:03:52 +04:00
2013-09-07 23:04:23 +04:00
if ( FIXNUM_P ( y ) | | RB_BIGNUM_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
rel = rb_big_cmp ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
rel = rb_integer_float_cmp ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else {
ID id = 0 ;
switch ( op ) {
case big_op_gt : id = ' > ' ; break ;
case big_op_ge : id = rb_intern ( " >= " ) ; break ;
case big_op_lt : id = ' < ' ; break ;
case big_op_le : id = rb_intern ( " <= " ) ; break ;
2013-07-07 15:02:47 +04:00
}
2013-09-07 23:04:18 +04:00
return rb_num_coerce_relop ( x , y , id ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
if ( NIL_P ( rel ) ) return Qfalse ;
n = FIX2INT ( rel ) ;
switch ( op ) {
case big_op_gt : return n > 0 ? Qtrue : Qfalse ;
case big_op_ge : return n > = 0 ? Qtrue : Qfalse ;
case big_op_lt : return n < 0 ? Qtrue : Qfalse ;
case big_op_le : return n < = 0 ? Qtrue : Qfalse ;
2008-12-14 06:59:02 +03:00
}
2013-07-07 15:02:47 +04:00
return Qundef ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big > real - > true or false
*
* Returns < code > true < / code > if the value of < code > big < / code > is
* greater than that of < code > real < / code > .
*/
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
big_gt ( VALUE x , VALUE y )
2013-07-07 10:03:52 +04:00
{
2013-07-07 15:02:47 +04:00
return big_op ( x , y , big_op_gt ) ;
2013-06-16 05:41:58 +04:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big > = real - > true or false
*
* Returns < code > true < / code > if the value of < code > big < / code > is
* greater than or equal to that of < code > real < / code > .
*/
1998-01-16 15:13:05 +03:00
static VALUE
2013-07-07 15:02:47 +04:00
big_ge ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2013-07-07 15:02:47 +04:00
return big_op ( x , y , big_op_ge ) ;
}
1998-01-16 15:19:22 +03:00
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big < real - > true or false
*
* Returns < code > true < / code > if the value of < code > big < / code > is
* less than that of < code > real < / code > .
*/
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
static VALUE
big_lt ( VALUE x , VALUE y )
{
return big_op ( x , y , big_op_lt ) ;
}
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big < = real - > true or false
*
* Returns < code > true < / code > if the value of < code > big < / code > is
* less than or equal to that of < code > real < / code > .
*/
1998-01-16 15:13:05 +03:00
2013-07-07 15:02:47 +04:00
static VALUE
big_le ( VALUE x , VALUE y )
{
return big_op ( x , y , big_op_le ) ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2013-07-07 15:02:47 +04:00
* big = = obj - > true or false
2003-12-19 03:01:19 +03:00
*
2013-07-07 15:02:47 +04:00
* Returns < code > true < / code > only if < i > obj < / i > has the same value
* as < i > big < / i > . Contrast this with < code > Bignum # eql ? < / code > , which
* requires < i > obj < / i > to be a < code > Bignum < / code > .
*
* 68719476736 = = 68719476736.0 # = > true
2003-12-19 03:01:19 +03:00
*/
1998-01-16 15:13:05 +03:00
VALUE
2013-07-07 15:02:47 +04:00
rb_big_eq ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2013-07-07 15:02:47 +04:00
if ( bignorm ( x ) = = y ) return Qtrue ;
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return rb_integer_float_eq ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else {
2013-07-07 15:02:47 +04:00
return rb_equal ( y , x ) ;
1998-01-16 15:13:05 +03:00
}
2013-07-07 15:02:47 +04:00
if ( RBIGNUM_SIGN ( x ) ! = RBIGNUM_SIGN ( y ) ) return Qfalse ;
if ( RBIGNUM_LEN ( x ) ! = RBIGNUM_LEN ( y ) ) return Qfalse ;
if ( MEMCMP ( BDIGITS ( x ) , BDIGITS ( y ) , BDIGIT , RBIGNUM_LEN ( y ) ) ! = 0 ) return Qfalse ;
return Qtrue ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2013-07-07 15:02:47 +04:00
* big . eql ? ( obj ) - > true or false
2003-12-19 03:01:19 +03:00
*
2013-07-07 15:02:47 +04:00
* Returns < code > true < / code > only if < i > obj < / i > is a
* < code > Bignum < / code > with the same value as < i > big < / i > . Contrast this
* with < code > Bignum # = = < / code > , which performs type conversions .
*
* 68719476736. eql ? ( 68719476736.0 ) # = > false
2003-12-19 03:01:19 +03:00
*/
1998-01-16 15:13:05 +03:00
VALUE
2013-07-07 15:02:47 +04:00
rb_big_eql ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2013-09-07 23:04:23 +04:00
if ( ! RB_BIGNUM_TYPE_P ( y ) ) return Qfalse ;
2013-07-07 15:02:47 +04:00
if ( RBIGNUM_SIGN ( x ) ! = RBIGNUM_SIGN ( y ) ) return Qfalse ;
if ( RBIGNUM_LEN ( x ) ! = RBIGNUM_LEN ( y ) ) return Qfalse ;
if ( MEMCMP ( BDIGITS ( x ) , BDIGITS ( y ) , BDIGIT , RBIGNUM_LEN ( y ) ) ! = 0 ) return Qfalse ;
return Qtrue ;
2013-06-15 17:32:16 +04:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* - big - > integer
*
* Unary minus ( returns an integer whose value is 0 - big )
*/
2013-07-05 00:31:01 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big_uminus ( VALUE x )
2013-07-07 10:03:52 +04:00
{
2013-07-07 15:02:47 +04:00
VALUE z = rb_big_clone ( x ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
RBIGNUM_SET_SIGN ( z , ! RBIGNUM_SIGN ( x ) ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
return bignorm ( z ) ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* ~ big - > integer
*
* Inverts the bits in big . As Bignums are conceptually infinite
* length , the result acts as if it had an infinite number of one
* bits to the left . In hex representations , this is displayed
* as two periods to the left of the digits .
*
* sprintf ( " %X " , ~ 0x1122334455 ) # = > " ..FEEDDCCBBAA "
*/
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
rb_big_neg ( VALUE x )
{
VALUE z = rb_big_clone ( x ) ;
BDIGIT * ds = BDIGITS ( z ) ;
long n = RBIGNUM_LEN ( z ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
if ( ! n ) return INT2FIX ( - 1 ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
if ( RBIGNUM_POSITIVE_P ( z ) ) {
2013-07-10 17:06:33 +04:00
if ( bary_add_one ( ds , n ) ) {
2013-07-07 15:02:47 +04:00
big_extend_carry ( z ) ;
}
RBIGNUM_SET_NEGATIVE_SIGN ( z ) ;
}
else {
bary_neg ( ds , n ) ;
2013-07-10 17:06:33 +04:00
if ( bary_add_one ( ds , n ) )
2013-07-07 15:02:47 +04:00
return INT2FIX ( - 1 ) ;
bary_neg ( ds , n ) ;
RBIGNUM_SET_POSITIVE_SIGN ( z ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
return bignorm ( z ) ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
bigsub ( VALUE x , VALUE y )
{
2013-07-14 17:24:44 +04:00
VALUE z ;
BDIGIT * xds , * yds , * zds ;
long xn , yn , zn ;
2013-07-07 10:03:52 +04:00
2013-07-14 17:24:44 +04:00
xn = RBIGNUM_LEN ( x ) ;
yn = RBIGNUM_LEN ( y ) ;
zn = xn < yn ? yn : xn ;
z = bignew ( zn , 1 ) ;
xds = BDIGITS ( x ) ;
yds = BDIGITS ( y ) ;
zds = BDIGITS ( z ) ;
2013-07-07 10:03:52 +04:00
2013-07-14 17:24:44 +04:00
if ( bary_sub ( zds , zn , xds , xn , yds , yn ) ) {
bary_2comp ( zds , zn ) ;
RBIGNUM_SET_NEGATIVE_SIGN ( z ) ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
return z ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE bigadd_int ( VALUE x , long y ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
bigsub_int ( VALUE x , long y0 )
{
VALUE z ;
BDIGIT * xds , * zds ;
long xn , zn ;
BDIGIT_DBL_SIGNED num ;
long i , y ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
y = y0 ;
xds = BDIGITS ( x ) ;
xn = RBIGNUM_LEN ( x ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
if ( xn = = 0 )
return LONG2NUM ( - y0 ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
zn = xn ;
# if SIZEOF_BDIGITS < SIZEOF_LONG
if ( zn < bdigit_roomof ( SIZEOF_LONG ) )
zn = bdigit_roomof ( SIZEOF_LONG ) ;
# endif
z = bignew ( zn , RBIGNUM_SIGN ( x ) ) ;
zds = BDIGITS ( z ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
assert ( xn = = zn ) ;
num = ( BDIGIT_DBL_SIGNED ) xds [ 0 ] - y ;
if ( xn = = 1 & & num < 0 ) {
RBIGNUM_SET_SIGN ( z , ! RBIGNUM_SIGN ( x ) ) ;
zds [ 0 ] = ( BDIGIT ) - num ;
RB_GC_GUARD ( x ) ;
return bignorm ( z ) ;
}
zds [ 0 ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
i = 1 ;
if ( i < xn )
goto y_is_zero_x ;
goto finish ;
# else
num = 0 ;
for ( i = 0 ; i < xn ; i + + ) {
if ( y = = 0 ) goto y_is_zero_x ;
num + = ( BDIGIT_DBL_SIGNED ) xds [ i ] - BIGLO ( y ) ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
y = BIGDN ( y ) ;
}
for ( ; i < zn ; i + + ) {
if ( y = = 0 ) goto y_is_zero_z ;
num - = BIGLO ( y ) ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
y = BIGDN ( y ) ;
}
goto finish ;
# endif
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
for ( ; i < xn ; i + + ) {
y_is_zero_x :
if ( num = = 0 ) goto num_is_zero_x ;
num + = xds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
# if SIZEOF_BDIGITS < SIZEOF_LONG
for ( ; i < zn ; i + + ) {
y_is_zero_z :
if ( num = = 0 ) goto num_is_zero_z ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
}
# endif
goto finish ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
for ( ; i < xn ; i + + ) {
num_is_zero_x :
zds [ i ] = xds [ i ] ;
}
# if SIZEOF_BDIGITS < SIZEOF_LONG
for ( ; i < zn ; i + + ) {
num_is_zero_z :
zds [ i ] = 0 ;
}
# endif
goto finish ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
finish :
assert ( num = = 0 | | num = = - 1 ) ;
if ( num < 0 ) {
get2comp ( z ) ;
RBIGNUM_SET_SIGN ( z , ! RBIGNUM_SIGN ( x ) ) ;
}
RB_GC_GUARD ( x ) ;
return bignorm ( z ) ;
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
static VALUE
bigadd_int ( VALUE x , long y )
{
VALUE z ;
BDIGIT * xds , * zds ;
long xn , zn ;
BDIGIT_DBL num ;
long i ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
xds = BDIGITS ( x ) ;
xn = RBIGNUM_LEN ( x ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
if ( xn = = 0 )
return LONG2NUM ( y ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
zn = xn ;
# if SIZEOF_BDIGITS < SIZEOF_LONG
if ( zn < bdigit_roomof ( SIZEOF_LONG ) )
zn = bdigit_roomof ( SIZEOF_LONG ) ;
# endif
zn + + ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
z = bignew ( zn , RBIGNUM_SIGN ( x ) ) ;
zds = BDIGITS ( z ) ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
num = ( BDIGIT_DBL ) xds [ 0 ] + y ;
zds [ 0 ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
i = 1 ;
if ( i < xn )
goto y_is_zero_x ;
goto y_is_zero_z ;
# else
num = 0 ;
for ( i = 0 ; i < xn ; i + + ) {
if ( y = = 0 ) goto y_is_zero_x ;
num + = ( BDIGIT_DBL ) xds [ i ] + BIGLO ( y ) ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
y = BIGDN ( y ) ;
}
for ( ; i < zn ; i + + ) {
if ( y = = 0 ) goto y_is_zero_z ;
num + = BIGLO ( y ) ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
y = BIGDN ( y ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
goto finish ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
# endif
for ( ; i < xn ; i + + ) {
y_is_zero_x :
if ( num = = 0 ) goto num_is_zero_x ;
num + = ( BDIGIT_DBL ) xds [ i ] ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
for ( ; i < zn ; i + + ) {
y_is_zero_z :
if ( num = = 0 ) goto num_is_zero_z ;
zds [ i ] = BIGLO ( num ) ;
num = BIGDN ( num ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
goto finish ;
for ( ; i < xn ; i + + ) {
num_is_zero_x :
zds [ i ] = xds [ i ] ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
for ( ; i < zn ; i + + ) {
num_is_zero_z :
zds [ i ] = 0 ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
goto finish ;
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
finish :
RB_GC_GUARD ( x ) ;
return bignorm ( z ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
static VALUE
bigadd ( VALUE x , VALUE y , int sign )
{
VALUE z ;
long len ;
2013-07-01 17:59:50 +04:00
2013-07-07 15:02:47 +04:00
sign = ( sign = = RBIGNUM_SIGN ( y ) ) ;
if ( RBIGNUM_SIGN ( x ) ! = sign ) {
if ( sign ) return bigsub ( y , x ) ;
return bigsub ( x , y ) ;
}
if ( RBIGNUM_LEN ( x ) > RBIGNUM_LEN ( y ) ) {
len = RBIGNUM_LEN ( x ) + 1 ;
2013-06-15 17:32:16 +04:00
}
else {
2013-07-07 15:02:47 +04:00
len = RBIGNUM_LEN ( y ) + 1 ;
2013-06-15 17:32:16 +04:00
}
2013-07-07 15:02:47 +04:00
z = bignew ( len , sign ) ;
2013-08-02 20:22:47 +04:00
bary_add ( BDIGITS ( z ) , RBIGNUM_LEN ( z ) ,
BDIGITS ( x ) , RBIGNUM_LEN ( x ) ,
BDIGITS ( y ) , RBIGNUM_LEN ( y ) ) ;
2013-07-07 15:02:47 +04:00
return z ;
2013-06-15 17:32:16 +04:00
}
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big + other - > Numeric
*
* Adds big and other , returning the result .
*/
VALUE
rb_big_plus ( VALUE x , VALUE y )
2013-07-01 17:59:50 +04:00
{
2013-07-07 15:02:47 +04:00
long n ;
2013-07-07 10:03:52 +04:00
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2013-07-07 15:02:47 +04:00
n = FIX2LONG ( y ) ;
if ( ( n > 0 ) ! = RBIGNUM_SIGN ( x ) ) {
if ( n < 0 ) {
n = - n ;
}
return bigsub_int ( x , n ) ;
}
if ( n < 0 ) {
n = - n ;
}
return bigadd_int ( x , n ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return bignorm ( bigadd ( x , y , 1 ) ) ;
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return DBL2NUM ( rb_big2dbl ( x ) + RFLOAT_VALUE ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
else {
2013-07-07 15:02:47 +04:00
return rb_num_coerce_bin ( x , y , ' + ' ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
}
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
/*
* call - seq :
* big - other - > Numeric
*
* Subtracts other from big , returning the result .
*/
2013-07-07 10:03:52 +04:00
2013-07-07 15:02:47 +04:00
VALUE
rb_big_minus ( VALUE x , VALUE y )
{
long n ;
2013-07-07 10:03:52 +04:00
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2013-07-07 15:02:47 +04:00
n = FIX2LONG ( y ) ;
if ( ( n > 0 ) ! = RBIGNUM_SIGN ( x ) ) {
if ( n < 0 ) {
n = - n ;
}
return bigadd_int ( x , n ) ;
}
if ( n < 0 ) {
n = - n ;
}
return bigsub_int ( x , n ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return bignorm ( bigadd ( x , y , 0 ) ) ;
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2013-07-07 15:02:47 +04:00
return DBL2NUM ( rb_big2dbl ( x ) - RFLOAT_VALUE ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
else {
2013-07-07 15:02:47 +04:00
return rb_num_coerce_bin ( x , y , ' - ' ) ;
2013-07-07 10:03:52 +04:00
}
2013-07-07 15:02:47 +04:00
}
2013-07-07 10:03:52 +04:00
2013-07-21 16:13:47 +04:00
static VALUE
bigsq ( VALUE x )
{
long xn , zn ;
VALUE z ;
BDIGIT * xds , * zds ;
xn = RBIGNUM_LEN ( x ) ;
zn = 2 * xn ;
z = bignew ( zn , 1 ) ;
xds = BDIGITS ( x ) ;
zds = BDIGITS ( z ) ;
2013-08-31 16:17:18 +04:00
# ifdef USE_GMP
if ( xn < GMP_MUL_DIGITS )
bary_sq_fast ( zds , zn , xds , xn ) ;
else
bary_mul ( zds , zn , xds , xn , xds , xn ) ;
# else
2013-07-21 16:13:47 +04:00
if ( xn < KARATSUBA_MUL_DIGITS )
bary_sq_fast ( zds , zn , xds , xn ) ;
else
bary_mul ( zds , zn , xds , xn , xds , xn ) ;
2013-08-31 16:17:18 +04:00
# endif
2013-07-21 16:13:47 +04:00
RB_GC_GUARD ( x ) ;
return z ;
}
2008-12-14 06:59:02 +03:00
static VALUE
bigmul0 ( VALUE x , VALUE y )
{
2013-07-07 10:03:52 +04:00
long xn , yn , zn ;
VALUE z ;
BDIGIT * xds , * yds , * zds ;
2008-12-14 06:59:02 +03:00
2013-07-21 16:13:47 +04:00
if ( x = = y )
return bigsq ( x ) ;
2008-12-14 06:59:02 +03:00
xn = RBIGNUM_LEN ( x ) ;
yn = RBIGNUM_LEN ( y ) ;
2013-07-07 10:03:52 +04:00
zn = xn + yn ;
2008-12-14 06:59:02 +03:00
2013-07-07 10:03:52 +04:00
z = bignew ( zn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
2008-12-14 06:59:02 +03:00
2013-07-07 10:03:52 +04:00
xds = BDIGITS ( x ) ;
yds = BDIGITS ( y ) ;
zds = BDIGITS ( z ) ;
2008-12-14 06:59:02 +03:00
2013-07-11 07:06:02 +04:00
bary_mul ( zds , zn , xds , xn , yds , yn ) ;
2008-12-14 06:59:02 +03:00
2013-07-07 10:03:52 +04:00
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
return z ;
2008-12-14 06:59:02 +03:00
}
2005-08-10 05:39:24 +04:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big * other - > Numeric
2005-08-10 05:39:24 +04:00
*
* Multiplies big and other , returning the result .
*/
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_mul ( VALUE x , VALUE y )
2005-08-10 05:39:24 +04:00
{
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2008-12-14 06:59:02 +03:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
2008-12-14 06:59:02 +03:00
return DBL2NUM ( rb_big2dbl ( x ) * RFLOAT_VALUE ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
else {
2008-12-14 06:59:02 +03:00
return rb_num_coerce_bin ( x , y , ' * ' ) ;
}
return bignorm ( bigmul0 ( x , y ) ) ;
1998-01-16 15:13:05 +03:00
}
2008-01-29 15:58:24 +03:00
static VALUE
2012-11-27 16:46:32 +04:00
bigdivrem ( VALUE x , VALUE y , volatile VALUE * divp , volatile VALUE * modp )
2008-01-29 15:58:24 +03:00
{
2013-09-04 19:10:48 +04:00
long xn = RBIGNUM_LEN ( x ) , yn = RBIGNUM_LEN ( y ) ;
VALUE z ;
BDIGIT * xds , * yds , * zds ;
2013-06-16 03:46:07 +04:00
BDIGIT dd ;
1998-01-16 15:13:05 +03:00
2013-09-04 19:10:48 +04:00
VALUE q = Qnil , r = Qnil ;
BDIGIT * qds , * rds ;
long qn , rn ;
1998-01-16 15:13:05 +03:00
yds = BDIGITS ( y ) ;
2013-08-05 18:50:07 +04:00
BARY_TRUNC ( yds , yn ) ;
if ( yn = = 0 )
2013-06-13 19:15:07 +04:00
rb_num_zerodiv ( ) ;
xds = BDIGITS ( x ) ;
2013-08-05 18:50:07 +04:00
BARY_TRUNC ( xds , xn ) ;
2013-06-13 19:15:07 +04:00
2013-08-05 18:50:07 +04:00
if ( xn < yn | | ( xn = = yn & & xds [ xn - 1 ] < yds [ yn - 1 ] ) ) {
2000-07-12 11:33:34 +04:00
if ( divp ) * divp = rb_int2big ( 0 ) ;
2000-07-12 10:06:50 +04:00
if ( modp ) * modp = x ;
2007-12-19 14:40:52 +03:00
return Qnil ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
if ( yn = = 1 ) {
1998-01-16 15:13:05 +03:00
dd = yds [ 0 ] ;
2013-08-05 18:50:07 +04:00
z = bignew ( xn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
1998-01-16 15:13:05 +03:00
zds = BDIGITS ( z ) ;
2013-08-05 18:50:07 +04:00
dd = bigdivrem_single ( zds , xds , xn , dd ) ;
2001-01-09 10:26:21 +03:00
if ( modp ) {
2013-06-16 03:56:32 +04:00
* modp = rb_uint2big ( ( VALUE ) dd ) ;
2007-09-01 16:02:36 +04:00
RBIGNUM_SET_SIGN ( * modp , RBIGNUM_SIGN ( x ) ) ;
2001-01-09 10:26:21 +03:00
}
2000-07-12 10:06:50 +04:00
if ( divp ) * divp = z ;
2007-12-19 14:40:52 +03:00
return Qnil ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
if ( xn = = 2 & & yn = = 2 ) {
2013-08-03 19:26:04 +04:00
BDIGIT_DBL x0 = bary2bdigitdbl ( xds , 2 ) ;
BDIGIT_DBL y0 = bary2bdigitdbl ( yds , 2 ) ;
2013-07-28 19:14:20 +04:00
BDIGIT_DBL q0 = x0 / y0 ;
BDIGIT_DBL r0 = x0 % y0 ;
if ( divp ) {
z = bignew ( bdigit_roomof ( sizeof ( BDIGIT_DBL ) ) , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
zds = BDIGITS ( z ) ;
zds [ 0 ] = BIGLO ( q0 ) ;
zds [ 1 ] = BIGLO ( BIGDN ( q0 ) ) ;
* divp = z ;
}
if ( modp ) {
z = bignew ( bdigit_roomof ( sizeof ( BDIGIT_DBL ) ) , RBIGNUM_SIGN ( x ) ) ;
zds = BDIGITS ( z ) ;
zds [ 0 ] = BIGLO ( r0 ) ;
zds [ 1 ] = BIGLO ( BIGDN ( r0 ) ) ;
* modp = z ;
}
return Qnil ;
}
2011-05-22 19:37:00 +04:00
2013-09-04 19:10:48 +04:00
if ( divp ) {
qn = xn + BIGDIVREM_EXTRA_WORDS ;
q = bignew ( qn , RBIGNUM_SIGN ( x ) = = RBIGNUM_SIGN ( y ) ) ;
qds = BDIGITS ( q ) ;
}
else {
qn = 0 ;
qds = NULL ;
}
if ( modp ) {
rn = yn ;
r = bignew ( rn , RBIGNUM_SIGN ( x ) ) ;
rds = BDIGITS ( r ) ;
}
else {
rn = 0 ;
rds = NULL ;
}
2013-09-05 03:22:27 +04:00
bary_divmod_branch ( qds , qn , rds , rn , xds , xn , yds , yn ) ;
2013-09-04 19:10:48 +04:00
if ( divp ) {
bigtrunc ( q ) ;
* divp = q ;
}
if ( modp ) {
bigtrunc ( r ) ;
* modp = r ;
1998-01-16 15:13:05 +03:00
}
2000-11-08 08:29:37 +03:00
2013-06-13 16:26:33 +04:00
return Qnil ;
2007-12-19 13:13:03 +03:00
}
2000-07-06 11:21:26 +04:00
static void
2009-08-25 12:38:28 +04:00
bigdivmod ( VALUE x , VALUE y , volatile VALUE * divp , volatile VALUE * modp )
2000-07-06 11:21:26 +04:00
{
VALUE mod ;
bigdivrem ( x , y , divp , & mod ) ;
2007-09-01 16:02:36 +04:00
if ( RBIGNUM_SIGN ( x ) ! = RBIGNUM_SIGN ( y ) & & ! BIGZEROP ( mod ) ) {
2000-07-06 11:21:26 +04:00
if ( divp ) * divp = bigadd ( * divp , rb_int2big ( 1 ) , 0 ) ;
if ( modp ) * modp = bigadd ( mod , y , 1 ) ;
}
2008-08-29 20:56:44 +04:00
else if ( modp ) {
* modp = mod ;
1998-01-16 15:13:05 +03:00
}
}
2003-12-19 03:01:19 +03:00
2008-04-07 17:52:26 +04:00
static VALUE
rb_big_divide ( VALUE x , VALUE y , ID op )
1998-01-16 15:13:05 +03:00
{
VALUE z ;
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
1999-01-20 07:59:39 +03:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
if ( op = = ' / ' ) {
return DBL2NUM ( rb_big2dbl ( x ) / RFLOAT_VALUE ( y ) ) ;
2008-05-01 18:20:15 +04:00
}
2013-09-07 23:04:18 +04:00
else {
double dy = RFLOAT_VALUE ( y ) ;
if ( dy = = 0.0 ) rb_num_zerodiv ( ) ;
return rb_dbl2big ( rb_big2dbl ( x ) / dy ) ;
}
}
else {
2008-04-07 17:52:26 +04:00
return rb_num_coerce_bin ( x , y , op ) ;
1998-01-16 15:13:05 +03:00
}
2000-07-06 11:21:26 +04:00
bigdivmod ( x , y , & z , 0 ) ;
1998-01-16 15:13:05 +03:00
2000-07-12 10:06:50 +04:00
return bignorm ( z ) ;
1998-01-16 15:13:05 +03:00
}
2008-04-07 17:52:26 +04:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big / other - > Numeric
2008-04-07 17:52:26 +04:00
*
2009-09-04 12:06:12 +04:00
* Performs division : the class of the resulting object depends on
* the class of < code > numeric < / code > and on the magnitude of the
* result .
2008-04-07 17:52:26 +04:00
*/
VALUE
rb_big_div ( VALUE x , VALUE y )
{
2009-09-04 09:40:52 +04:00
return rb_big_divide ( x , y , ' / ' ) ;
2008-04-07 17:52:26 +04:00
}
2009-09-04 12:06:12 +04:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big . div ( other ) - > integer
2009-09-04 12:06:12 +04:00
*
* Performs integer division : returns integer value .
*/
2008-04-07 17:52:26 +04:00
VALUE
rb_big_idiv ( VALUE x , VALUE y )
{
2009-09-04 09:40:52 +04:00
return rb_big_divide ( x , y , rb_intern ( " div " ) ) ;
2008-04-07 17:52:26 +04:00
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big % other - > Numeric
* big . modulo ( other ) - > Numeric
2003-12-19 03:01:19 +03:00
*
* Returns big modulo other . See Numeric . divmod for more
* information .
*/
2005-08-03 11:09:48 +04:00
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_modulo ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
VALUE z ;
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
1999-01-20 07:59:39 +03:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( ! RB_BIGNUM_TYPE_P ( y ) ) {
2008-02-12 05:46:21 +03:00
return rb_num_coerce_bin ( x , y , ' % ' ) ;
1998-01-16 15:13:05 +03:00
}
2000-07-03 09:46:36 +04:00
bigdivmod ( x , y , 0 , & z ) ;
1998-01-16 15:13:05 +03:00
2000-07-12 10:06:50 +04:00
return bignorm ( z ) ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big . remainder ( numeric ) - > number
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* Returns the remainder after dividing < i > big < / i > by < i > numeric < / i > .
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* - 1234567890987654321. remainder ( 13731 ) # = > - 6966
* - 1234567890987654321. remainder ( 13731.24 ) # = > - 9906.22531493148
*/
2000-07-06 11:21:26 +04:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_remainder ( VALUE x , VALUE y )
2000-07-06 11:21:26 +04:00
{
VALUE z ;
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2000-07-06 11:21:26 +04:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( ! RB_BIGNUM_TYPE_P ( y ) ) {
2008-02-12 05:46:21 +03:00
return rb_num_coerce_bin ( x , y , rb_intern ( " remainder " ) ) ;
2000-07-06 11:21:26 +04:00
}
bigdivrem ( x , y , 0 , & z ) ;
return bignorm ( z ) ;
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big . divmod ( numeric ) - > array
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* See < code > Numeric # divmod < / code > .
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
*/
2000-05-12 13:07:57 +04:00
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_divmod ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
VALUE div , mod ;
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
1999-01-20 07:59:39 +03:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( ! RB_BIGNUM_TYPE_P ( y ) ) {
2008-02-12 05:46:21 +03:00
return rb_num_coerce_bin ( x , y , rb_intern ( " divmod " ) ) ;
1998-01-16 15:13:05 +03:00
}
2000-07-03 09:46:36 +04:00
bigdivmod ( x , y , & div , & mod ) ;
1998-01-16 15:13:05 +03:00
2000-07-12 10:06:50 +04:00
return rb_assoc_new ( bignorm ( div ) , bignorm ( mod ) ) ;
1998-01-16 15:13:05 +03:00
}
2009-05-26 08:58:15 +04:00
static VALUE
big_shift ( VALUE x , long n )
2007-07-19 09:38:48 +04:00
{
if ( n < 0 )
2013-07-13 19:19:48 +04:00
return big_lshift ( x , 1 + ( unsigned long ) ( - ( n + 1 ) ) ) ;
2007-07-19 09:38:48 +04:00
else if ( n > 0 )
2009-05-26 08:58:15 +04:00
return big_rshift ( x , ( unsigned long ) n ) ;
2007-07-19 09:38:48 +04:00
return x ;
}
2007-05-02 12:12:31 +04:00
2010-05-29 22:51:39 +04:00
static VALUE
2013-09-07 23:04:15 +04:00
big_fdiv ( VALUE x , VALUE y , long ey )
2009-06-17 16:55:16 +04:00
{
# define DBL_BIGDIG ((DBL_MANT_DIG + BITSPERDIG) / BITSPERDIG)
VALUE z ;
2013-09-07 23:04:15 +04:00
long l , ex ;
2009-06-17 16:55:16 +04:00
bigtrunc ( x ) ;
2013-06-05 16:17:30 +04:00
l = RBIGNUM_LEN ( x ) ;
ex = l * BITSPERDIG - nlz ( BDIGITS ( x ) [ l - 1 ] ) ;
2009-06-17 16:55:16 +04:00
ex - = 2 * DBL_BIGDIG * BITSPERDIG ;
if ( ex ) x = big_shift ( x , ex ) ;
2012-04-15 04:06:13 +04:00
bigdivrem ( x , y , & z , 0 ) ;
l = ex - ey ;
# if SIZEOF_LONG > SIZEOF_INT
{
/* Visual C++ can't be here */
if ( l > INT_MAX ) return DBL2NUM ( INFINITY ) ;
if ( l < INT_MIN ) return DBL2NUM ( 0.0 ) ;
}
# endif
return DBL2NUM ( ldexp ( big2dbl ( z ) , ( int ) l ) ) ;
2009-06-17 16:55:16 +04:00
}
2013-09-07 23:04:15 +04:00
static VALUE
big_fdiv_int ( VALUE x , VALUE y )
{
long l , ey ;
bigtrunc ( y ) ;
l = RBIGNUM_LEN ( y ) ;
ey = l * BITSPERDIG - nlz ( BDIGITS ( y ) [ l - 1 ] ) ;
ey - = DBL_BIGDIG * BITSPERDIG ;
if ( ey ) y = big_shift ( y , ey ) ;
return big_fdiv ( x , y , ey ) ;
}
static VALUE
big_fdiv_float ( VALUE x , VALUE y )
{
int i ;
y = dbl2big ( ldexp ( frexp ( RFLOAT_VALUE ( y ) , & i ) , DBL_MANT_DIG ) ) ;
return big_fdiv ( x , y , i - DBL_MANT_DIG ) ;
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2008-05-07 08:14:57 +04:00
* big . fdiv ( numeric ) - > float
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* Returns the floating point result of dividing < i > big < / i > by
* < i > numeric < / i > .
2007-05-09 07:49:18 +04:00
*
2008-05-07 08:14:57 +04:00
* - 1234567890987654321.f div ( 13731 ) # = > - 89910996357705.5
* - 1234567890987654321.f div ( 13731.24 ) # = > - 89909424858035.7
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
*/
2009-06-17 16:55:16 +04:00
VALUE
2008-03-16 03:23:43 +03:00
rb_big_fdiv ( VALUE x , VALUE y )
2003-01-23 09:22:50 +03:00
{
2009-06-17 16:55:16 +04:00
double dx , dy ;
2003-01-23 09:22:50 +03:00
2009-06-17 16:55:16 +04:00
dx = big2dbl ( x ) ;
2013-09-07 23:04:18 +04:00
if ( FIXNUM_P ( y ) ) {
2003-01-23 09:22:50 +03:00
dy = ( double ) FIX2LONG ( y ) ;
2009-06-17 16:55:16 +04:00
if ( isinf ( dx ) )
2013-09-07 23:04:15 +04:00
return big_fdiv_int ( x , rb_int2big ( FIX2LONG ( y ) ) ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2003-01-23 09:22:50 +03:00
dy = rb_big2dbl ( y ) ;
2009-06-17 16:55:16 +04:00
if ( isinf ( dx ) | | isinf ( dy ) )
2013-09-07 23:04:15 +04:00
return big_fdiv_int ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else if ( RB_FLOAT_TYPE_P ( y ) ) {
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
dy = RFLOAT_VALUE ( y ) ;
2009-06-17 16:55:16 +04:00
if ( isnan ( dy ) )
return y ;
if ( isinf ( dx ) )
2013-09-07 23:04:15 +04:00
return big_fdiv_float ( x , y ) ;
2013-09-07 23:04:18 +04:00
}
else {
2008-03-16 03:23:43 +03:00
return rb_num_coerce_bin ( x , y , rb_intern ( " fdiv " ) ) ;
2003-01-23 09:22:50 +03:00
}
2008-09-05 22:24:21 +04:00
return DBL2NUM ( dx / dy ) ;
2003-01-23 09:22:50 +03:00
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big * * exponent - > numeric
2003-12-19 03:01:19 +03:00
*
* Raises _big_ to the _exponent_ power ( which may be an integer , float ,
* or anything that will coerce to a number ) . The result may be
* a Fixnum , Bignum , or Float
*
* 123456789 * * 2 # = > 15241578750190521
* 123456789 * * 1.2 # = > 5126464716.09932
* 123456789 * * - 2 # = > 6.5610001194102e-17
*/
1998-01-16 15:13:05 +03:00
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_pow ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
double d ;
2007-05-02 00:39:48 +04:00
SIGNED_VALUE yy ;
2013-06-26 19:27:20 +04:00
again :
1998-01-16 15:13:05 +03:00
if ( y = = INT2FIX ( 0 ) ) return INT2FIX ( 1 ) ;
2013-09-07 23:04:18 +04:00
if ( RB_FLOAT_TYPE_P ( y ) ) {
* include/ruby/ruby.h: introduce 2 macros:
RFLOAT_VALUE(v), DOUBLE2NUM(dbl).
Rename RFloat#value -> RFloat#double_value.
Do not touch RFloat#double_value directly.
* bignum.c, insns.def, marshal.c, math.c, numeric.c, object.c,
pack.c, parse.y, process.c, random.c, sprintf.c, string.c,
time.c: apply above changes.
* ext/dl/mkcallback.rb, ext/json/ext/generator/generator.c:
ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13913 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-11-13 19:00:53 +03:00
d = RFLOAT_VALUE ( y ) ;
2009-08-17 03:03:45 +04:00
if ( ( ! RBIGNUM_SIGN ( x ) & & ! BIGZEROP ( x ) ) & & d ! = round ( d ) )
return rb_funcall ( rb_complex_raw1 ( x ) , rb_intern ( " ** " ) , 1 , y ) ;
2013-09-07 23:04:18 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-06-26 19:27:20 +04:00
y = bignorm ( y ) ;
if ( FIXNUM_P ( y ) )
goto again ;
1999-01-20 07:59:39 +03:00
rb_warn ( " in a**b, b may be too big " ) ;
d = rb_big2dbl ( y ) ;
2013-09-07 23:04:18 +04:00
}
else if ( FIXNUM_P ( y ) ) {
2004-03-15 05:27:29 +03:00
yy = FIX2LONG ( y ) ;
2008-03-16 03:23:43 +03:00
if ( yy < 0 )
2008-09-19 17:55:52 +04:00
return rb_funcall ( rb_rational_raw1 ( x ) , rb_intern ( " ** " ) , 1 , y ) ;
2008-03-16 03:23:43 +03:00
else {
2007-05-02 00:39:48 +04:00
VALUE z = 0 ;
2007-07-15 19:26:12 +04:00
SIGNED_VALUE mask ;
2013-06-26 19:27:20 +04:00
const size_t xbits = rb_absint_numwords ( x , 1 , NULL ) ;
const size_t BIGLEN_LIMIT = 32 * 1024 * 1024 ;
1999-01-20 07:59:39 +03:00
2013-06-26 19:27:20 +04:00
if ( xbits = = ( size_t ) - 1 | |
( xbits > BIGLEN_LIMIT ) | |
( xbits * yy > BIGLEN_LIMIT ) ) {
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
rb_warn ( " in a**b, b may be too big " ) ;
d = ( double ) yy ;
}
2013-09-07 23:04:18 +04:00
else {
for ( mask = FIXNUM_MAX + 1 ; mask ; mask > > = 1 ) {
if ( z ) z = bigsq ( z ) ;
if ( yy & mask ) {
z = z ? bigtrunc ( bigmul0 ( z , x ) ) : x ;
}
2007-05-02 00:39:48 +04:00
}
2013-09-07 23:04:18 +04:00
return bignorm ( z ) ;
1999-01-20 07:59:39 +03:00
}
}
2013-09-07 23:04:18 +04:00
}
else {
2008-02-12 05:46:21 +03:00
return rb_num_coerce_bin ( x , y , rb_intern ( " ** " ) ) ;
1998-01-16 15:13:05 +03:00
}
2008-09-05 22:24:21 +04:00
return DBL2NUM ( pow ( rb_big2dbl ( x ) , d ) ) ;
1998-01-16 15:13:05 +03:00
}
2009-05-27 20:16:57 +04:00
static VALUE
2013-06-28 03:07:59 +04:00
bigand_int ( VALUE x , long xn , BDIGIT hibitsx , long y )
2009-05-27 20:16:57 +04:00
{
VALUE z ;
BDIGIT * xds , * zds ;
2013-06-28 03:07:59 +04:00
long zn ;
2009-05-27 20:16:57 +04:00
long i ;
2013-06-28 03:07:59 +04:00
BDIGIT hibitsy ;
2009-05-27 20:16:57 +04:00
if ( y = = 0 ) return INT2FIX ( 0 ) ;
2013-06-29 03:21:57 +04:00
if ( xn = = 0 ) return hibitsx ? LONG2NUM ( y ) : 0 ;
2013-06-28 03:07:59 +04:00
hibitsy = 0 < = y ? 0 : BDIGMAX ;
2009-05-27 20:16:57 +04:00
xds = BDIGITS ( x ) ;
2013-06-19 14:36:22 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
2013-06-28 03:07:59 +04:00
if ( ! hibitsy ) {
2009-05-27 20:16:57 +04:00
y & = xds [ 0 ] ;
return LONG2NUM ( y ) ;
}
# endif
2013-06-28 03:07:59 +04:00
zn = xn ;
2013-06-26 07:16:12 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
2013-06-28 03:07:59 +04:00
if ( hibitsx & & zn < bdigit_roomof ( SIZEOF_LONG ) )
2013-06-26 07:16:12 +04:00
zn = bdigit_roomof ( SIZEOF_LONG ) ;
# endif
2009-05-27 20:16:57 +04:00
2013-06-28 03:07:59 +04:00
z = bignew ( zn , 0 ) ;
2009-05-27 20:16:57 +04:00
zds = BDIGITS ( z ) ;
2013-06-19 14:36:22 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
2009-05-27 20:16:57 +04:00
i = 1 ;
2013-11-24 17:27:14 +04:00
zds [ 0 ] = xds [ 0 ] & BIGLO ( y ) ;
2009-05-27 20:16:57 +04:00
# else
2013-06-26 02:28:43 +04:00
for ( i = 0 ; i < xn ; i + + ) {
if ( y = = 0 | | y = = - 1 ) break ;
zds [ i ] = xds [ i ] & BIGLO ( y ) ;
y = BIGDN ( y ) ;
2009-05-27 20:16:57 +04:00
}
2013-06-26 07:16:12 +04:00
for ( ; i < zn ; i + + ) {
if ( y = = 0 | | y = = - 1 ) break ;
2013-06-28 03:07:59 +04:00
zds [ i ] = hibitsx & BIGLO ( y ) ;
2013-06-26 07:16:12 +04:00
y = BIGDN ( y ) ;
}
2009-05-27 20:16:57 +04:00
# endif
2013-06-26 07:16:12 +04:00
for ( ; i < xn ; i + + ) {
2013-06-28 03:07:59 +04:00
zds [ i ] = xds [ i ] & hibitsy ;
2013-06-26 07:16:12 +04:00
}
for ( ; i < zn ; i + + ) {
2013-06-28 03:07:59 +04:00
zds [ i ] = hibitsx & hibitsy ;
2009-05-27 20:16:57 +04:00
}
2013-06-28 03:07:59 +04:00
twocomp2abs_bang ( z , hibitsx & & hibitsy ) ;
RB_GC_GUARD ( x ) ;
2009-05-27 20:16:57 +04:00
return bignorm ( z ) ;
}
2003-12-19 03:01:19 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big & numeric - > integer
2003-12-19 03:01:19 +03:00
*
* Performs bitwise + and + between _big_ and _numeric_ .
*/
1998-01-16 15:13:05 +03:00
VALUE
2013-06-27 17:54:02 +04:00
rb_big_and ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2013-06-27 17:54:02 +04:00
VALUE z ;
2000-10-31 11:37:47 +03:00
BDIGIT * ds1 , * ds2 , * zds ;
2013-08-05 18:50:07 +04:00
long i , xn , yn , n1 , n2 ;
2013-06-27 17:54:02 +04:00
BDIGIT hibitsx , hibitsy ;
BDIGIT hibits1 , hibits2 ;
VALUE tmpv ;
BDIGIT tmph ;
2013-08-05 18:50:07 +04:00
long tmpn ;
1998-01-16 15:13:05 +03:00
2013-09-07 23:04:23 +04:00
if ( ! FIXNUM_P ( y ) & & ! RB_BIGNUM_TYPE_P ( y ) ) {
2013-06-27 17:54:02 +04:00
return rb_num_coerce_bit ( x , y , ' & ' ) ;
2012-12-22 19:06:22 +04:00
}
2013-08-05 18:50:07 +04:00
hibitsx = abs2twocomp ( & x , & xn ) ;
1998-01-16 15:13:05 +03:00
if ( FIXNUM_P ( y ) ) {
2013-08-05 18:50:07 +04:00
return bigand_int ( x , xn , hibitsx , FIX2LONG ( y ) ) ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
hibitsy = abs2twocomp ( & y , & yn ) ;
if ( xn > yn ) {
2013-06-27 17:54:02 +04:00
tmpv = x ; x = y ; y = tmpv ;
2013-08-05 18:50:07 +04:00
tmpn = xn ; xn = yn ; yn = tmpn ;
2013-06-27 17:54:02 +04:00
tmph = hibitsx ; hibitsx = hibitsy ; hibitsy = tmph ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
n1 = xn ;
n2 = yn ;
2013-06-27 17:54:02 +04:00
ds1 = BDIGITS ( x ) ;
ds2 = BDIGITS ( y ) ;
hibits1 = hibitsx ;
hibits2 = hibitsy ;
2013-06-28 07:35:39 +04:00
if ( ! hibits1 )
2013-08-05 18:50:07 +04:00
n2 = n1 ;
2013-06-28 07:35:39 +04:00
2013-08-05 18:50:07 +04:00
z = bignew ( n2 , 0 ) ;
1998-01-16 15:13:05 +03:00
zds = BDIGITS ( z ) ;
2013-08-05 18:50:07 +04:00
for ( i = 0 ; i < n1 ; i + + ) {
1998-01-16 15:13:05 +03:00
zds [ i ] = ds1 [ i ] & ds2 [ i ] ;
}
2013-08-05 18:50:07 +04:00
for ( ; i < n2 ; i + + ) {
2013-06-27 17:54:02 +04:00
zds [ i ] = hibits1 & ds2 [ i ] ;
1998-01-16 15:13:05 +03:00
}
2013-06-27 17:54:02 +04:00
twocomp2abs_bang ( z , hibits1 & & hibits2 ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
1998-01-16 15:13:05 +03:00
return bignorm ( z ) ;
}
2009-05-27 20:16:57 +04:00
static VALUE
2013-06-29 03:21:57 +04:00
bigor_int ( VALUE x , long xn , BDIGIT hibitsx , long y )
2009-05-27 20:16:57 +04:00
{
VALUE z ;
BDIGIT * xds , * zds ;
2013-06-29 03:21:57 +04:00
long zn ;
2009-05-27 20:16:57 +04:00
long i ;
2013-06-29 03:21:57 +04:00
BDIGIT hibitsy ;
2009-05-27 20:16:57 +04:00
2013-06-29 04:35:57 +04:00
if ( y = = - 1 ) return INT2FIX ( - 1 ) ;
2013-06-29 03:21:57 +04:00
if ( xn = = 0 ) return hibitsx ? INT2FIX ( - 1 ) : LONG2FIX ( y ) ;
hibitsy = 0 < = y ? 0 : BDIGMAX ;
2009-05-27 20:16:57 +04:00
xds = BDIGITS ( x ) ;
2013-06-29 03:21:57 +04:00
zn = RBIGNUM_LEN ( x ) ;
2013-06-26 07:16:12 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
if ( zn < bdigit_roomof ( SIZEOF_LONG ) )
zn = bdigit_roomof ( SIZEOF_LONG ) ;
# endif
2013-06-29 03:21:57 +04:00
z = bignew ( zn , 0 ) ;
2009-05-27 20:16:57 +04:00
zds = BDIGITS ( z ) ;
2013-06-19 14:36:22 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
2009-05-27 20:16:57 +04:00
i = 1 ;
2013-11-24 17:27:14 +04:00
zds [ 0 ] = xds [ 0 ] | BIGLO ( y ) ;
2013-06-26 07:16:12 +04:00
if ( i < zn )
goto y_is_fixed_point ;
goto finish ;
2009-05-27 20:16:57 +04:00
# else
2013-06-26 07:16:12 +04:00
for ( i = 0 ; i < xn ; i + + ) {
if ( y = = 0 | | y = = - 1 ) goto y_is_fixed_point ;
zds [ i ] = xds [ i ] | BIGLO ( y ) ;
y = BIGDN ( y ) ;
2009-05-27 20:16:57 +04:00
}
2013-06-29 03:21:57 +04:00
if ( hibitsx )
2013-06-26 07:16:12 +04:00
goto fill_hibits ;
for ( ; i < zn ; i + + ) {
if ( y = = 0 | | y = = - 1 ) goto y_is_fixed_point ;
zds [ i ] = BIGLO ( y ) ;
y = BIGDN ( y ) ;
}
goto finish ;
2009-05-27 20:16:57 +04:00
# endif
2013-06-26 07:16:12 +04:00
y_is_fixed_point :
2013-06-29 03:21:57 +04:00
if ( hibitsy )
2013-06-26 07:16:12 +04:00
goto fill_hibits ;
for ( ; i < xn ; i + + ) {
zds [ i ] = xds [ i ] ;
2009-05-27 20:16:57 +04:00
}
2013-06-29 03:21:57 +04:00
if ( hibitsx )
2013-06-26 07:16:12 +04:00
goto fill_hibits ;
for ( ; i < zn ; i + + ) {
zds [ i ] = 0 ;
}
goto finish ;
fill_hibits :
for ( ; i < zn ; i + + ) {
zds [ i ] = BDIGMAX ;
}
finish :
2013-06-29 03:21:57 +04:00
twocomp2abs_bang ( z , hibitsx | | hibitsy ) ;
2013-06-29 04:08:47 +04:00
RB_GC_GUARD ( x ) ;
2009-05-27 20:16:57 +04:00
return bignorm ( z ) ;
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big | numeric - > integer
2003-12-19 06:58:57 +03:00
*
* Performs bitwise + or + between _big_ and _numeric_ .
*/
1998-01-16 15:13:05 +03:00
VALUE
2013-06-29 03:21:57 +04:00
rb_big_or ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2013-06-29 03:21:57 +04:00
VALUE z ;
2000-10-31 11:37:47 +03:00
BDIGIT * ds1 , * ds2 , * zds ;
2013-08-05 18:50:07 +04:00
long i , xn , yn , n1 , n2 ;
2013-06-29 03:21:57 +04:00
BDIGIT hibitsx , hibitsy ;
BDIGIT hibits1 , hibits2 ;
VALUE tmpv ;
BDIGIT tmph ;
2013-08-05 18:50:07 +04:00
long tmpn ;
1998-01-16 15:13:05 +03:00
2013-09-07 23:04:23 +04:00
if ( ! FIXNUM_P ( y ) & & ! RB_BIGNUM_TYPE_P ( y ) ) {
2013-06-29 03:21:57 +04:00
return rb_num_coerce_bit ( x , y , ' | ' ) ;
2012-12-22 19:06:22 +04:00
}
2013-08-05 18:50:07 +04:00
hibitsx = abs2twocomp ( & x , & xn ) ;
1998-01-16 15:13:05 +03:00
if ( FIXNUM_P ( y ) ) {
2013-08-05 18:50:07 +04:00
return bigor_int ( x , xn , hibitsx , FIX2LONG ( y ) ) ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
hibitsy = abs2twocomp ( & y , & yn ) ;
if ( xn > yn ) {
2013-06-29 03:21:57 +04:00
tmpv = x ; x = y ; y = tmpv ;
2013-08-05 18:50:07 +04:00
tmpn = xn ; xn = yn ; yn = tmpn ;
2013-06-29 03:21:57 +04:00
tmph = hibitsx ; hibitsx = hibitsy ; hibitsy = tmph ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
n1 = xn ;
n2 = yn ;
2013-06-29 03:21:57 +04:00
ds1 = BDIGITS ( x ) ;
ds2 = BDIGITS ( y ) ;
hibits1 = hibitsx ;
hibits2 = hibitsy ;
if ( hibits1 )
2013-08-05 18:50:07 +04:00
n2 = n1 ;
2013-06-29 03:21:57 +04:00
2013-08-05 18:50:07 +04:00
z = bignew ( n2 , 0 ) ;
1998-01-16 15:13:05 +03:00
zds = BDIGITS ( z ) ;
2013-08-05 18:50:07 +04:00
for ( i = 0 ; i < n1 ; i + + ) {
1998-01-16 15:13:05 +03:00
zds [ i ] = ds1 [ i ] | ds2 [ i ] ;
}
2013-08-05 18:50:07 +04:00
for ( ; i < n2 ; i + + ) {
2013-06-29 03:21:57 +04:00
zds [ i ] = hibits1 | ds2 [ i ] ;
1998-01-16 15:13:05 +03:00
}
2013-06-29 03:21:57 +04:00
twocomp2abs_bang ( z , hibits1 | | hibits2 ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
1998-01-16 15:13:05 +03:00
return bignorm ( z ) ;
}
2009-05-27 20:16:57 +04:00
static VALUE
2013-06-29 04:08:47 +04:00
bigxor_int ( VALUE x , long xn , BDIGIT hibitsx , long y )
2009-05-27 20:16:57 +04:00
{
VALUE z ;
BDIGIT * xds , * zds ;
2013-06-29 04:08:47 +04:00
long zn ;
2009-05-27 20:16:57 +04:00
long i ;
2013-06-29 04:08:47 +04:00
BDIGIT hibitsy ;
2009-05-27 20:16:57 +04:00
2013-06-29 04:08:47 +04:00
hibitsy = 0 < = y ? 0 : BDIGMAX ;
2009-05-27 20:16:57 +04:00
xds = BDIGITS ( x ) ;
2013-06-29 04:08:47 +04:00
zn = RBIGNUM_LEN ( x ) ;
2013-06-26 07:49:45 +04:00
# if SIZEOF_BDIGITS < SIZEOF_LONG
if ( zn < bdigit_roomof ( SIZEOF_LONG ) )
zn = bdigit_roomof ( SIZEOF_LONG ) ;
# endif
2013-06-29 04:08:47 +04:00
z = bignew ( zn , 0 ) ;
2009-05-27 20:16:57 +04:00
zds = BDIGITS ( z ) ;
2013-06-19 14:36:22 +04:00
# if SIZEOF_BDIGITS >= SIZEOF_LONG
2009-05-27 20:16:57 +04:00
i = 1 ;
2013-11-24 17:27:14 +04:00
zds [ 0 ] = xds [ 0 ] ^ BIGLO ( y ) ;
2009-05-27 20:16:57 +04:00
# else
2013-06-26 07:49:45 +04:00
for ( i = 0 ; i < xn ; i + + ) {
zds [ i ] = xds [ i ] ^ BIGLO ( y ) ;
y = BIGDN ( y ) ;
}
for ( ; i < zn ; i + + ) {
2013-06-29 04:08:47 +04:00
zds [ i ] = hibitsx ^ BIGLO ( y ) ;
2013-06-26 07:49:45 +04:00
y = BIGDN ( y ) ;
2009-05-27 20:16:57 +04:00
}
# endif
2013-06-26 07:49:45 +04:00
for ( ; i < xn ; i + + ) {
2013-06-29 04:08:47 +04:00
zds [ i ] = xds [ i ] ^ hibitsy ;
2013-06-26 07:49:45 +04:00
}
for ( ; i < zn ; i + + ) {
2013-06-29 04:08:47 +04:00
zds [ i ] = hibitsx ^ hibitsy ;
2009-05-27 20:16:57 +04:00
}
2013-06-29 04:08:47 +04:00
twocomp2abs_bang ( z , ( hibitsx ^ hibitsy ) ! = 0 ) ;
RB_GC_GUARD ( x ) ;
2009-05-27 20:16:57 +04:00
return bignorm ( z ) ;
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big ^ numeric - > integer
2003-12-19 06:58:57 +03:00
*
* Performs bitwise + exclusive or + between _big_ and _numeric_ .
*/
1998-01-16 15:13:05 +03:00
VALUE
2013-06-29 04:08:47 +04:00
rb_big_xor ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
VALUE z ;
2000-10-31 11:37:47 +03:00
BDIGIT * ds1 , * ds2 , * zds ;
2013-08-05 18:50:07 +04:00
long i , xn , yn , n1 , n2 ;
2013-06-29 04:08:47 +04:00
BDIGIT hibitsx , hibitsy ;
BDIGIT hibits1 , hibits2 ;
VALUE tmpv ;
BDIGIT tmph ;
2013-08-05 18:50:07 +04:00
long tmpn ;
1998-01-16 15:13:05 +03:00
2013-09-07 23:04:23 +04:00
if ( ! FIXNUM_P ( y ) & & ! RB_BIGNUM_TYPE_P ( y ) ) {
2013-06-29 04:08:47 +04:00
return rb_num_coerce_bit ( x , y , ' ^ ' ) ;
2012-12-22 19:06:22 +04:00
}
2013-08-05 18:50:07 +04:00
hibitsx = abs2twocomp ( & x , & xn ) ;
1998-01-16 15:13:05 +03:00
if ( FIXNUM_P ( y ) ) {
2013-08-05 18:50:07 +04:00
return bigxor_int ( x , xn , hibitsx , FIX2LONG ( y ) ) ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
hibitsy = abs2twocomp ( & y , & yn ) ;
if ( xn > yn ) {
2013-06-29 04:08:47 +04:00
tmpv = x ; x = y ; y = tmpv ;
2013-08-05 18:50:07 +04:00
tmpn = xn ; xn = yn ; yn = tmpn ;
2013-06-29 04:08:47 +04:00
tmph = hibitsx ; hibitsx = hibitsy ; hibitsy = tmph ;
1998-01-16 15:13:05 +03:00
}
2013-08-05 18:50:07 +04:00
n1 = xn ;
n2 = yn ;
2013-06-29 04:08:47 +04:00
ds1 = BDIGITS ( x ) ;
ds2 = BDIGITS ( y ) ;
hibits1 = hibitsx ;
hibits2 = hibitsy ;
2013-08-05 18:50:07 +04:00
z = bignew ( n2 , 0 ) ;
1998-01-16 15:13:05 +03:00
zds = BDIGITS ( z ) ;
2013-08-05 18:50:07 +04:00
for ( i = 0 ; i < n1 ; i + + ) {
1998-01-16 15:13:05 +03:00
zds [ i ] = ds1 [ i ] ^ ds2 [ i ] ;
}
2013-08-05 18:50:07 +04:00
for ( ; i < n2 ; i + + ) {
2013-06-29 04:08:47 +04:00
zds [ i ] = hibitsx ^ ds2 [ i ] ;
1998-01-16 15:13:05 +03:00
}
2013-06-29 04:08:47 +04:00
twocomp2abs_bang ( z , ( hibits1 ^ hibits2 ) ! = 0 ) ;
RB_GC_GUARD ( x ) ;
RB_GC_GUARD ( y ) ;
1998-01-16 15:13:05 +03:00
return bignorm ( z ) ;
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big < < numeric - > integer
2003-12-19 06:58:57 +03:00
*
* Shifts big left _numeric_ positions ( right if _numeric_ is negative ) .
*/
1998-01-16 15:13:05 +03:00
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_lshift ( VALUE x , VALUE y )
2007-07-19 09:38:48 +04:00
{
2013-07-13 18:03:13 +04:00
int lshift_p ;
size_t shift_numdigits ;
int shift_numbits ;
2007-07-19 09:38:48 +04:00
for ( ; ; ) {
if ( FIXNUM_P ( y ) ) {
2013-06-20 17:23:33 +04:00
long l = FIX2LONG ( y ) ;
2013-07-13 18:03:13 +04:00
unsigned long shift ;
2013-06-20 17:23:33 +04:00
if ( 0 < = l ) {
2013-07-13 18:03:13 +04:00
lshift_p = 1 ;
2013-06-20 17:23:33 +04:00
shift = l ;
}
else {
2013-07-13 18:03:13 +04:00
lshift_p = 0 ;
2013-06-20 17:23:33 +04:00
shift = 1 + ( unsigned long ) ( - ( l + 1 ) ) ;
2007-07-19 09:38:48 +04:00
}
2013-07-15 06:11:15 +04:00
shift_numbits = ( int ) ( shift & ( BITSPERDIG - 1 ) ) ;
2013-08-31 22:34:42 +04:00
shift_numdigits = shift > > bit_length ( BITSPERDIG - 1 ) ;
2013-07-13 18:03:13 +04:00
return bignorm ( big_shift3 ( x , lshift_p , shift_numdigits , shift_numbits ) ) ;
2007-07-19 09:38:48 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-07-13 18:03:13 +04:00
return bignorm ( big_shift2 ( x , 1 , y ) ) ;
2007-07-19 09:38:48 +04:00
}
y = rb_to_int ( y ) ;
}
}
1998-01-16 15:13:05 +03:00
2003-12-19 06:58:57 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big > > numeric - > integer
2003-12-19 06:58:57 +03:00
*
* Shifts big right _numeric_ positions ( left if _numeric_ is negative ) .
*/
2007-07-19 09:38:48 +04:00
VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_rshift ( VALUE x , VALUE y )
2007-07-19 09:38:48 +04:00
{
2013-07-13 18:03:13 +04:00
int lshift_p ;
size_t shift_numdigits ;
int shift_numbits ;
2007-07-19 09:38:48 +04:00
for ( ; ; ) {
if ( FIXNUM_P ( y ) ) {
2013-06-20 17:23:33 +04:00
long l = FIX2LONG ( y ) ;
2013-07-13 18:03:13 +04:00
unsigned long shift ;
2013-06-20 17:23:33 +04:00
if ( 0 < = l ) {
2013-07-13 18:03:13 +04:00
lshift_p = 0 ;
2013-06-20 17:23:33 +04:00
shift = l ;
}
else {
2013-07-13 18:03:13 +04:00
lshift_p = 1 ;
2013-06-20 17:23:33 +04:00
shift = 1 + ( unsigned long ) ( - ( l + 1 ) ) ;
2007-07-19 09:38:48 +04:00
}
2013-07-15 06:11:15 +04:00
shift_numbits = ( int ) ( shift & ( BITSPERDIG - 1 ) ) ;
2013-08-31 22:34:42 +04:00
shift_numdigits = shift > > bit_length ( BITSPERDIG - 1 ) ;
2013-07-13 18:03:13 +04:00
return bignorm ( big_shift3 ( x , lshift_p , shift_numdigits , shift_numbits ) ) ;
2007-07-19 09:38:48 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( RB_BIGNUM_TYPE_P ( y ) ) {
2013-07-13 18:03:13 +04:00
return bignorm ( big_shift2 ( x , 0 , y ) ) ;
2007-07-19 09:38:48 +04:00
}
y = rb_to_int ( y ) ;
}
1998-01-16 15:13:05 +03:00
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
* big [ n ] - > 0 , 1
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* Bit Reference - - - Returns the < em > n < / em > th bit in the ( assumed ) binary
* representation of < i > big < / i > , where < i > big < / i > [ 0 ] is the least
* significant bit .
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* a = 9 * * 15
* 50. downto ( 0 ) do | n |
* print a [ n ]
* end
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* < em > produces : < / em >
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* 000101110110100000111000011110010100111100010111001
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
*/
1998-01-16 15:13:05 +03:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_aref ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
2000-10-31 11:37:47 +03:00
BDIGIT * xds ;
2013-06-20 17:23:33 +04:00
unsigned long shift ;
2007-07-30 06:16:42 +04:00
long i , s1 , s2 ;
2013-07-13 19:36:18 +04:00
BDIGIT bit ;
1998-01-16 15:13:05 +03:00
2013-09-07 23:04:23 +04:00
if ( RB_BIGNUM_TYPE_P ( y ) ) {
2007-09-01 16:02:36 +04:00
if ( ! RBIGNUM_SIGN ( y ) )
2001-11-01 08:11:24 +03:00
return INT2FIX ( 0 ) ;
2009-05-26 06:19:33 +04:00
bigtrunc ( y ) ;
2013-06-20 03:09:05 +04:00
if ( BIGSIZE ( y ) > sizeof ( long ) ) {
2007-07-30 06:16:42 +04:00
out_of_range :
2007-09-01 16:02:36 +04:00
return RBIGNUM_SIGN ( x ) ? INT2FIX ( 0 ) : INT2FIX ( 1 ) ;
2007-07-30 06:16:42 +04:00
}
2013-06-25 16:19:58 +04:00
shift = big2ulong ( y , " long " ) ;
2007-07-30 06:16:42 +04:00
}
else {
i = NUM2LONG ( y ) ;
if ( i < 0 ) return INT2FIX ( 0 ) ;
2013-06-20 17:23:33 +04:00
shift = i ;
2001-11-01 08:11:24 +03:00
}
1998-01-16 15:19:22 +03:00
s1 = shift / BITSPERDIG ;
s2 = shift % BITSPERDIG ;
2013-07-13 19:36:18 +04:00
bit = ( BDIGIT ) 1 < < s2 ;
1998-01-16 15:13:05 +03:00
2007-09-01 16:02:36 +04:00
if ( s1 > = RBIGNUM_LEN ( x ) ) goto out_of_range ;
2013-07-13 19:36:18 +04:00
xds = BDIGITS ( x ) ;
if ( RBIGNUM_POSITIVE_P ( x ) )
return ( xds [ s1 ] & bit ) ? INT2FIX ( 1 ) : INT2FIX ( 0 ) ;
if ( xds [ s1 ] & ( bit - 1 ) )
return ( xds [ s1 ] & bit ) ? INT2FIX ( 0 ) : INT2FIX ( 1 ) ;
for ( i = 0 ; i < s1 ; i + + )
if ( xds [ i ] )
return ( xds [ s1 ] & bit ) ? INT2FIX ( 0 ) : INT2FIX ( 1 ) ;
return ( xds [ s1 ] & bit ) ? INT2FIX ( 1 ) : INT2FIX ( 0 ) ;
1998-01-16 15:13:05 +03:00
}
2003-12-29 06:56:22 +03:00
/*
* call - seq :
2010-05-18 01:07:33 +04:00
* big . hash - > fixnum
2003-12-29 06:56:22 +03:00
*
* Compute a hash based on the value of _big_ .
*/
1998-01-16 15:13:05 +03:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_hash ( VALUE x )
1998-01-16 15:13:05 +03:00
{
2009-09-08 17:10:04 +04:00
st_index_t hash ;
1998-01-16 15:13:05 +03:00
2007-09-01 16:02:36 +04:00
hash = rb_memhash ( BDIGITS ( x ) , sizeof ( BDIGIT ) * RBIGNUM_LEN ( x ) ) ^ RBIGNUM_SIGN ( x ) ;
2006-09-22 02:52:38 +04:00
return INT2FIX ( hash ) ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 03:01:19 +03:00
/*
2013-07-15 06:13:13 +04:00
* call - seq :
* big . coerce ( numeric ) - > array
*
* Returns an array with both a + numeric + and a + big + represented as Bignum
* objects .
*
* This is achieved by converting + numeric + to a Bignum .
*
* A TypeError is raised if the + numeric + is not a Fixnum or Bignum type .
*
* ( 0x3FFFFFFFFFFFFFFF + 1 ) . coerce ( 42 ) # = > [ 42 , 4611686018427387904 ]
2003-12-19 03:01:19 +03:00
*/
1998-01-16 15:13:05 +03:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_coerce ( VALUE x , VALUE y )
1998-01-16 15:13:05 +03:00
{
if ( FIXNUM_P ( y ) ) {
2012-04-15 04:06:13 +04:00
y = rb_int2big ( FIX2LONG ( y ) ) ;
2005-08-10 05:39:24 +04:00
}
2013-09-07 23:04:23 +04:00
else if ( ! RB_BIGNUM_TYPE_P ( y ) ) {
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
rb_raise ( rb_eTypeError , " can't coerce %s to Bignum " ,
2003-01-31 07:00:17 +03:00
rb_obj_classname ( y ) ) ;
1998-01-16 15:13:05 +03:00
}
2012-04-15 04:06:13 +04:00
return rb_assoc_new ( y , x ) ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
* big . abs - > aBignum
2013-04-12 06:59:07 +04:00
* big . magnitude - > aBignum
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* Returns the absolute value of < i > big < / i > .
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* - 1234567890987654321. abs # = > 1234567890987654321
*/
1998-01-16 15:13:05 +03:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_abs ( VALUE x )
1998-01-16 15:13:05 +03:00
{
2007-09-01 16:02:36 +04:00
if ( ! RBIGNUM_SIGN ( x ) ) {
1999-01-20 07:59:39 +03:00
x = rb_big_clone ( x ) ;
2007-09-01 16:02:36 +04:00
RBIGNUM_SET_SIGN ( x , 1 ) ;
1998-01-16 15:13:05 +03:00
}
1999-01-20 07:59:39 +03:00
return x ;
1998-01-16 15:13:05 +03:00
}
2003-12-19 06:58:57 +03:00
/*
* call - seq :
* big . size - > integer
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* Returns the number of bytes in the machine representation of
* < i > big < / i > .
2007-05-09 07:49:18 +04:00
*
2003-12-19 06:58:57 +03:00
* ( 256 * * 10 - 1 ) . size # = > 12
* ( 256 * * 20 - 1 ) . size # = > 20
* ( 256 * * 40 - 1 ) . size # = > 40
*/
1998-01-16 15:13:05 +03:00
static VALUE
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
rb_big_size ( VALUE big )
1998-01-16 15:13:05 +03:00
{
2013-07-27 19:39:01 +04:00
return SIZET2NUM ( BIGSIZE ( big ) ) ;
1998-01-16 15:13:05 +03:00
}
2013-08-31 19:09:20 +04:00
/*
* call - seq :
* int . bit_length - > integer
*
* Returns the number of bits of the value of < i > int < / i > .
*
* " the number of bits " means that
* the bit position of the highest bit which is different to the sign bit .
* ( The bit position of the bit 2 * * n is n + 1. )
* If there is no such bit ( zero or minus one ) , zero is returned .
*
2013-09-01 05:00:15 +04:00
* I . e . This method returns ceil ( log2 ( int < 0 ? - int : int + 1 ) ) .
*
2013-08-31 19:09:20 +04:00
* ( - 2 * * 10000 - 1 ) . bit_length # = > 10001
* ( - 2 * * 10000 ) . bit_length # = > 10000
* ( - 2 * * 10000 + 1 ) . bit_length # = > 10000
*
* ( - 2 * * 1000 - 1 ) . bit_length # = > 1001
* ( - 2 * * 1000 ) . bit_length # = > 1000
* ( - 2 * * 1000 + 1 ) . bit_length # = > 1000
*
* ( 2 * * 1000 - 1 ) . bit_length # = > 1000
* ( 2 * * 1000 ) . bit_length # = > 1001
* ( 2 * * 1000 + 1 ) . bit_length # = > 1001
*
* ( 2 * * 10000 - 1 ) . bit_length # = > 10000
* ( 2 * * 10000 ) . bit_length # = > 10001
* ( 2 * * 10000 + 1 ) . bit_length # = > 10001
*
*/
static VALUE
rb_big_bit_length ( VALUE big )
{
int nlz_bits ;
size_t numbytes ;
static const BDIGIT char_bit [ 1 ] = { CHAR_BIT } ;
BDIGIT numbytes_bary [ bdigit_roomof ( sizeof ( size_t ) ) ] ;
BDIGIT nlz_bary [ 1 ] ;
BDIGIT result_bary [ bdigit_roomof ( sizeof ( size_t ) + 1 ) ] ;
numbytes = rb_absint_size ( big , & nlz_bits ) ;
if ( numbytes = = 0 )
return LONG2FIX ( 0 ) ;
if ( RBIGNUM_NEGATIVE_P ( big ) & & rb_absint_singlebit_p ( big ) ) {
if ( nlz_bits ! = CHAR_BIT - 1 ) {
nlz_bits + + ;
}
else {
nlz_bits = 0 ;
numbytes - - ;
}
}
if ( numbytes < = SIZE_MAX / CHAR_BIT ) {
return SIZET2NUM ( numbytes * CHAR_BIT - nlz_bits ) ;
}
nlz_bary [ 0 ] = nlz_bits ;
bary_unpack ( BARY_ARGS ( numbytes_bary ) , & numbytes , 1 , sizeof ( numbytes ) , 0 ,
INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
BARY_SHORT_MUL ( result_bary , numbytes_bary , char_bit ) ;
BARY_SUB ( result_bary , result_bary , nlz_bary ) ;
return rb_integer_unpack ( result_bary , numberof ( result_bary ) , sizeof ( BDIGIT ) , 0 ,
INTEGER_PACK_LSWORD_FIRST | INTEGER_PACK_NATIVE_BYTE_ORDER ) ;
}
2007-11-16 17:41:11 +03:00
/*
* call - seq :
* big . odd ? - > true or false
*
* Returns < code > true < / code > if < i > big < / i > is an odd number .
*/
static VALUE
rb_big_odd_p ( VALUE num )
{
2013-08-07 15:08:03 +04:00
if ( RBIGNUM_LEN ( num ) ! = 0 & & BDIGITS ( num ) [ 0 ] & 1 ) {
2007-11-27 20:42:12 +03:00
return Qtrue ;
2007-11-16 17:41:11 +03:00
}
return Qfalse ;
}
/*
* call - seq :
* big . even ? - > true or false
*
* Returns < code > true < / code > if < i > big < / i > is an even number .
*/
static VALUE
rb_big_even_p ( VALUE num )
{
2013-08-07 15:08:03 +04:00
if ( RBIGNUM_LEN ( num ) ! = 0 & & BDIGITS ( num ) [ 0 ] & 1 ) {
2007-11-27 20:42:12 +03:00
return Qfalse ;
2007-11-16 17:41:11 +03:00
}
return Qtrue ;
}
2003-12-19 03:01:19 +03:00
/*
* Bignum objects hold integers outside the range of
* Fixnum . Bignum objects are created
* automatically when integer calculations would otherwise overflow a
* Fixnum . When a calculation involving
* Bignum objects returns a result that will fit in a
* Fixnum , the result is automatically converted .
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* For the purposes of the bitwise operations and < code > [ ] < / code > , a
* Bignum is treated as if it were an infinite - length
* bitstring with 2 ' s complement representation .
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
* While Fixnum values are immediate , Bignum
* objects are not - - - assignment and parameter passing work with
* references to objects , not the objects themselves .
2007-05-09 07:49:18 +04:00
*
2003-12-19 03:01:19 +03:00
*/
1998-01-16 15:13:05 +03:00
void
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
Init_Bignum ( void )
1998-01-16 15:13:05 +03:00
{
1999-01-20 07:59:39 +03:00
rb_cBignum = rb_define_class ( " Bignum " , rb_cInteger ) ;
2001-11-19 08:03:03 +03:00
rb_define_method ( rb_cBignum , " to_s " , rb_big_to_s , - 1 ) ;
2012-08-15 15:50:01 +04:00
rb_define_alias ( rb_cBignum , " inspect " , " to_s " ) ;
1999-01-20 07:59:39 +03:00
rb_define_method ( rb_cBignum , " coerce " , rb_big_coerce , 1 ) ;
rb_define_method ( rb_cBignum , " -@ " , rb_big_uminus , 0 ) ;
rb_define_method ( rb_cBignum , " + " , rb_big_plus , 1 ) ;
rb_define_method ( rb_cBignum , " - " , rb_big_minus , 1 ) ;
rb_define_method ( rb_cBignum , " * " , rb_big_mul , 1 ) ;
rb_define_method ( rb_cBignum , " / " , rb_big_div , 1 ) ;
2000-07-06 11:21:26 +04:00
rb_define_method ( rb_cBignum , " % " , rb_big_modulo , 1 ) ;
2008-04-07 17:52:26 +04:00
rb_define_method ( rb_cBignum , " div " , rb_big_idiv , 1 ) ;
1999-01-20 07:59:39 +03:00
rb_define_method ( rb_cBignum , " divmod " , rb_big_divmod , 1 ) ;
2000-07-06 11:21:26 +04:00
rb_define_method ( rb_cBignum , " modulo " , rb_big_modulo , 1 ) ;
rb_define_method ( rb_cBignum , " remainder " , rb_big_remainder , 1 ) ;
2008-03-16 03:23:43 +03:00
rb_define_method ( rb_cBignum , " fdiv " , rb_big_fdiv , 1 ) ;
1999-01-20 07:59:39 +03:00
rb_define_method ( rb_cBignum , " ** " , rb_big_pow , 1 ) ;
rb_define_method ( rb_cBignum , " & " , rb_big_and , 1 ) ;
rb_define_method ( rb_cBignum , " | " , rb_big_or , 1 ) ;
rb_define_method ( rb_cBignum , " ^ " , rb_big_xor , 1 ) ;
rb_define_method ( rb_cBignum , " ~ " , rb_big_neg , 0 ) ;
rb_define_method ( rb_cBignum , " << " , rb_big_lshift , 1 ) ;
rb_define_method ( rb_cBignum , " >> " , rb_big_rshift , 1 ) ;
rb_define_method ( rb_cBignum , " [] " , rb_big_aref , 1 ) ;
rb_define_method ( rb_cBignum , " <=> " , rb_big_cmp , 1 ) ;
rb_define_method ( rb_cBignum , " == " , rb_big_eq , 1 ) ;
2010-02-04 18:36:29 +03:00
rb_define_method ( rb_cBignum , " > " , big_gt , 1 ) ;
rb_define_method ( rb_cBignum , " >= " , big_ge , 1 ) ;
rb_define_method ( rb_cBignum , " < " , big_lt , 1 ) ;
rb_define_method ( rb_cBignum , " <= " , big_le , 1 ) ;
2009-08-12 09:55:06 +04:00
rb_define_method ( rb_cBignum , " === " , rb_big_eq , 1 ) ;
2001-11-08 09:43:14 +03:00
rb_define_method ( rb_cBignum , " eql? " , rb_big_eql , 1 ) ;
1999-01-20 07:59:39 +03:00
rb_define_method ( rb_cBignum , " hash " , rb_big_hash , 0 ) ;
rb_define_method ( rb_cBignum , " to_f " , rb_big_to_f , 0 ) ;
rb_define_method ( rb_cBignum , " abs " , rb_big_abs , 0 ) ;
2008-08-29 18:50:43 +04:00
rb_define_method ( rb_cBignum , " magnitude " , rb_big_abs , 0 ) ;
1999-01-20 07:59:39 +03:00
rb_define_method ( rb_cBignum , " size " , rb_big_size , 0 ) ;
2013-08-31 19:09:20 +04:00
rb_define_method ( rb_cBignum , " bit_length " , rb_big_bit_length , 0 ) ;
2007-11-16 17:41:11 +03:00
rb_define_method ( rb_cBignum , " odd? " , rb_big_odd_p , 0 ) ;
rb_define_method ( rb_cBignum , " even? " , rb_big_even_p , 0 ) ;
2008-03-07 15:14:17 +03:00
2013-09-02 02:04:35 +04:00
# ifdef USE_GMP
rb_define_const ( rb_cBignum , " GMP_VERSION " , rb_sprintf ( " GMP %s " , gmp_version ) ) ;
# endif
2008-03-07 15:14:17 +03:00
power_cache_init ( ) ;
1998-01-16 15:13:05 +03:00
}