2015-10-30 15:36:37 +00:00
/*
* $ Id $
*
2019-11-19 09:40:26 +00:00
Copyright ( c ) 2014 - 2019 Chung , Hyung - Hwan . All rights reserved .
2015-10-30 15:36:37 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
1. Redistributions of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions in binary form must reproduce the above copyright
notice , this list of conditions and the following disclaimer in the
documentation and / or other materials provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE AUTHOR " AS IS " AND ANY EXPRESS OR
2023-11-21 14:50:00 +00:00
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
2015-10-30 15:36:37 +00:00
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2015-10-29 15:24:46 +00:00
2016-11-09 15:50:18 +00:00
/*
* Copyright ( c ) 2002 by The XFree86 Project , Inc .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
* WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*
* Except as contained in this notice , the name of the XFree86 Project shall
* not be used in advertising or otherwise to promote the sale , use or other
* dealings in this Software without prior written authorization from the
* XFree86 Project .
*
* Author : Paulo César Pereira de Andrade
*/
2019-04-02 08:49:41 +00:00
/*
* Copyright 1994 - 1996 LongView Technologies L . L . C . $ Revision : 1.5 $
* Copyright ( c ) 2006 , Sun Microsystems , Inc .
All rights reserved .
Redistribution and use in source and binary forms , with or without modification , are permitted provided that the
following conditions are met :
* Redistributions of source code must retain the above copyright notice , this list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright notice , this list of conditions and the following
disclaimer in the documentation and / or other materials provided with the distribution .
* Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived
from this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT
NOT LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE
OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/
2016-11-09 15:50:18 +00:00
2017-01-09 09:54:49 +00:00
# include "moo-prv.h"
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
2015-11-22 13:32:06 +00:00
/* nothing special */
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
# define MAKE_WORD(hw1,hw2) ((moo_oow_t)(hw1) | (moo_oow_t)(hw2) << MOO_LIW_BITS)
2015-12-02 16:14:37 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
2015-11-17 14:13:59 +00:00
# endif
2015-12-25 05:09:17 +00:00
# define IS_SIGN_DIFF(x,y) (((x) ^ (y)) < 0)
2019-03-24 18:49:16 +00:00
/*#define IS_POW2(ui) (((ui) > 0) && (((ui) & (~(ui)+ 1)) == (ui)))*/
# define IS_POW2(ui) (((ui) > 0) && ((ui) & ((ui) - 1)) == 0)
2015-12-18 15:58:45 +00:00
/* digit character array */
2018-12-21 16:25:25 +00:00
static char * _digitc_array [ ] =
{
" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " ,
" 0123456789abcdefghijklmnopqrstuvwxyz "
} ;
2015-12-18 15:58:45 +00:00
2019-03-24 18:49:16 +00:00
/* exponent table for pow2 between 1 and 32 inclusive. */
static moo_uint8_t _exp_tab [ 32 ] =
2015-12-18 15:58:45 +00:00
{
2019-03-24 18:49:16 +00:00
0 , 1 , 0 , 2 , 0 , 0 , 0 , 3 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 5
2015-12-18 15:58:45 +00:00
} ;
2019-03-24 18:49:16 +00:00
static const moo_uint8_t debruijn_32 [ 32 ] =
{
0 , 1 , 28 , 2 , 29 , 14 , 24 , 3 ,
30 , 22 , 20 , 15 , 25 , 17 , 4 , 8 ,
31 , 27 , 13 , 23 , 21 , 19 , 16 , 7 ,
26 , 12 , 18 , 6 , 11 , 5 , 10 , 9
} ;
static const moo_uint8_t debruijn_64 [ 64 ] =
{
0 , 1 , 2 , 53 , 3 , 7 , 54 , 27 ,
4 , 38 , 41 , 8 , 34 , 55 , 48 , 28 ,
62 , 5 , 39 , 46 , 44 , 42 , 22 , 9 ,
24 , 35 , 59 , 56 , 49 , 18 , 29 , 11 ,
63 , 52 , 6 , 26 , 37 , 40 , 33 , 47 ,
61 , 45 , 43 , 21 , 23 , 58 , 17 , 10 ,
51 , 25 , 36 , 32 , 60 , 20 , 57 , 16 ,
50 , 31 , 19 , 15 , 30 , 14 , 13 , 12
} ;
# if defined(MOO_HAVE_UINT32_T)
# define LOG2_FOR_POW2_32(x) (debruijn_32[(moo_uint32_t)((moo_uint32_t)(x) * 0x077CB531) >> 27])
# endif
# if defined(MOO_HAVE_UINT64_T)
# define LOG2_FOR_POW2_64(x) (debruijn_64[(moo_uint64_t)((moo_uint64_t)(x) * 0x022fdd63cc95386d) >> 58])
# endif
# if defined(MOO_HAVE_UINT32_T) && (MOO_SIZEOF_OOW_T == MOO_SIZEOF_UINT32_T)
# define LOG2_FOR_POW2(x) LOG2_FOR_POW2_32(x)
# elif defined(MOO_HAVE_UINT64_T) && (MOO_SIZEOF_OOW_T == MOO_SIZEOF_UINT64_T)
# define LOG2_FOR_POW2(x) LOG2_FOR_POW2_64(x)
# else
2019-05-04 04:27:27 +00:00
# define LOG2_FOR_POW2(x) moo_get_pos_of_msb_set_pow2(x)
2019-03-24 18:49:16 +00:00
# endif
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_OOW_T == MOO_SIZEOF_INT) && defined(MOO_HAVE_BUILTIN_UADD_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_OOW_T == MOO_SIZEOF_LONG) && defined(MOO_HAVE_BUILTIN_UADDL_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_OOW_T == MOO_SIZEOF_LONG_LONG) && defined(MOO_HAVE_BUILTIN_UADDLL_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE int oow_add_overflow ( moo_oow_t a , moo_oow_t b , moo_oow_t * c )
2015-11-04 17:32:28 +00:00
{
* c = a + b ;
2017-01-09 09:54:49 +00:00
return b > MOO_TYPE_MAX ( moo_oow_t ) - a ;
2015-11-04 17:32:28 +00:00
}
# endif
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_OOW_T == MOO_SIZEOF_INT) && defined(MOO_HAVE_BUILTIN_UMUL_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umul_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_OOW_T == MOO_SIZEOF_LONG) && defined(MOO_HAVE_BUILTIN_UMULL_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umull_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_OOW_T == MOO_SIZEOF_LONG_LONG) && defined(MOO_HAVE_BUILTIN_UMULLL_OVERFLOW)
2015-11-04 17:32:28 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umulll_overflow(a,b,c)
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE int oow_mul_overflow ( moo_oow_t a , moo_oow_t b , moo_oow_t * c )
2015-11-04 17:32:28 +00:00
{
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_UINTMAX_T > MOO_SIZEOF_OOW_T)
moo_uintmax_t k ;
k = ( moo_uintmax_t ) a * ( moo_uintmax_t ) b ;
* c = ( moo_oow_t ) k ;
return ( k > > MOO_OOW_BITS ) > 0 ;
/*return k > MOO_TYPE_MAX(moo_oow_t);*/
2015-11-04 17:32:28 +00:00
# else
* c = a * b ;
2017-01-09 09:54:49 +00:00
return b ! = 0 & & a > MOO_TYPE_MAX ( moo_oow_t ) / b ; /* works for unsigned types only */
2015-11-04 17:32:28 +00:00
# endif
}
# endif
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_OOI_T == MOO_SIZEOF_INT) && defined(MOO_HAVE_BUILTIN_SMUL_OVERFLOW)
# define smooi_mul_overflow(moo,a,b,c) __builtin_smul_overflow(a,b,c)
# elif (MOO_SIZEOF_OOI_T == MOO_SIZEOF_LONG) && defined(MOO_HAVE_BUILTIN_SMULL_OVERFLOW)
# define smooi_mul_overflow(moo,a,b,c) __builtin_smull_overflow(a,b,c)
# elif (MOO_SIZEOF_OOI_T == MOO_SIZEOF_LONG_LONG) && defined(MOO_HAVE_BUILTIN_SMULLL_OVERFLOW)
# define smooi_mul_overflow(moo,a,b,c) __builtin_smulll_overflow(a,b,c)
2015-11-13 15:55:56 +00:00
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE int smooi_mul_overflow ( moo_t * moo , moo_ooi_t a , moo_ooi_t b , moo_ooi_t * c )
2015-11-13 15:55:56 +00:00
{
2015-11-17 14:13:59 +00:00
/* take note that this function is not supposed to handle
2017-01-09 09:54:49 +00:00
* the whole moo_ooi_t range . it handles the smooi subrange */
2015-11-17 14:13:59 +00:00
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_UINTMAX_T > MOO_SIZEOF_OOI_T)
moo_intmax_t k ;
2015-11-16 09:53:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( a ) ) ;
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( b ) ) ;
2015-11-16 09:53:31 +00:00
2017-01-09 09:54:49 +00:00
k = ( moo_intmax_t ) a * ( moo_intmax_t ) b ;
* c = ( moo_ooi_t ) k ;
2015-11-16 09:53:31 +00:00
2017-01-09 09:54:49 +00:00
return k > MOO_TYPE_MAX ( moo_ooi_t ) | | k < MOO_TYPE_MIN ( moo_ooi_t ) ;
2015-11-13 15:55:56 +00:00
# else
2015-11-16 09:53:31 +00:00
2017-01-09 09:54:49 +00:00
moo_ooi_t ua , ub ;
2015-11-16 09:53:31 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( a ) ) ;
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( b ) ) ;
2015-11-16 09:53:31 +00:00
2015-11-13 15:55:56 +00:00
* c = a * b ;
2015-11-16 09:53:31 +00:00
ub = ( b > = 0 ) ? b : - b ;
ua = ( a > = 0 ) ? a : - a ;
/* though this fomula basically works for unsigned types in principle,
* the values used here are all absolute values and they fall in
2015-12-22 15:50:01 +00:00
* a safe range to apply this fomula . the safe range is guaranteed because
2015-11-17 14:13:59 +00:00
* the sources are supposed to be smoois . */
2017-01-09 09:54:49 +00:00
return ub ! = 0 & & ua > MOO_TYPE_MAX ( moo_ooi_t ) / ub ;
2015-11-13 15:55:56 +00:00
# endif
}
# endif
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_LIW_T == MOO_SIZEOF_INT) && defined(MOO_HAVE_BUILTIN_UADD_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_LIW_T == MOO_SIZEOF_LONG) && defined(MOO_HAVE_BUILTIN_UADDL_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_LIW_T == MOO_SIZEOF_LONG_LONG) && defined(MOO_HAVE_BUILTIN_UADDLL_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
2015-11-11 13:31:05 +00:00
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE int liw_add_overflow ( moo_liw_t a , moo_liw_t b , moo_liw_t * c )
2015-11-11 13:31:05 +00:00
{
* c = a + b ;
2017-01-09 09:54:49 +00:00
return b > MOO_TYPE_MAX ( moo_liw_t ) - a ;
2015-11-11 13:31:05 +00:00
}
# endif
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_LIW_T == MOO_SIZEOF_INT) && defined(MOO_HAVE_BUILTIN_UMUL_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_mul_overflow(a,b,c) __builtin_umul_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_LIW_T == MOO_SIZEOF_LONG) && defined(MOO_HAVE_BUILTIN_UMULL_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_mul_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2017-01-09 09:54:49 +00:00
# elif (MOO_SIZEOF_LIW_T == MOO_SIZEOF_LONG_LONG) && defined(MOO_HAVE_BUILTIN_UMULLL_OVERFLOW)
2015-11-17 14:13:59 +00:00
# define liw_mul_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
2015-11-11 13:31:05 +00:00
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE int liw_mul_overflow ( moo_liw_t a , moo_liw_t b , moo_liw_t * c )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
# if (MOO_SIZEOF_UINTMAX_T > MOO_SIZEOF_LIW_T)
moo_uintmax_t k ;
k = ( moo_uintmax_t ) a * ( moo_uintmax_t ) b ;
* c = ( moo_liw_t ) k ;
return ( k > > MOO_LIW_BITS ) > 0 ;
/*return k > MOO_TYPE_MAX(moo_liw_t);*/
2015-11-11 13:31:05 +00:00
# else
* c = a * b ;
2017-01-09 09:54:49 +00:00
return b ! = 0 & & a > MOO_TYPE_MAX ( moo_liw_t ) / b ; /* works for unsigned types only */
2015-11-11 13:31:05 +00:00
# endif
}
# endif
2017-01-09 09:54:49 +00:00
static int is_normalized_integer ( moo_t * moo , moo_oop_t oop )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( oop ) ) return 1 ;
if ( MOO_OOP_IS_POINTER ( oop ) )
2015-12-24 14:11:04 +00:00
{
/* TODO: is it better to introduce a special integer mark into the class itself */
/* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_BIGINT ( moo , oop ) )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t sz ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
sz = MOO_OBJ_GET_SIZE ( oop ) ;
MOO_ASSERT ( moo , sz > = 1 ) ;
2015-12-24 14:11:04 +00:00
2019-08-11 10:11:54 +00:00
return MOO_OBJ_GET_LIWORD_VAL ( oop , sz - 1 ) = = 0 ? 0 : 1 ;
2015-12-24 14:11:04 +00:00
}
}
2015-10-30 15:36:37 +00:00
2015-12-24 14:11:04 +00:00
return 0 ;
}
2019-11-01 09:15:53 +00:00
static MOO_INLINE int bigint_to_oow_noseterr ( moo_t * moo , moo_oop_t num , moo_oow_t * w )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( num ) ) ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_PBIGINT ( moo , num ) | | MOO_POINTER_IS_NBIGINT ( moo , num ) ) ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( num ) > = 1 ) ;
if ( MOO_OBJ_GET_SIZE ( num ) = = 1 )
2015-12-27 18:02:59 +00:00
{
2019-08-11 14:58:04 +00:00
* w = MOO_OBJ_GET_WORD_VAL ( num , 0 ) ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , num ) ) ? - 1 : 1 ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
2015-12-27 18:02:59 +00:00
/* this function must be called with a real large integer.
* a real large integer is at least 2 half - word long .
* you must not call this function with an unnormalized
* large integer . */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( num ) > = 2 ) ;
if ( MOO_OBJ_GET_SIZE ( num ) = = 2 )
2015-12-27 18:02:59 +00:00
{
2019-08-11 14:58:04 +00:00
* w = MAKE_WORD ( MOO_OBJ_GET_HALFWORD_VAL ( num , 0 ) , MOO_OBJ_GET_HALFWORD_VAL ( num , 1 ) ) ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , num ) ) ? - 1 : 1 ;
2015-12-27 18:02:59 +00:00
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
return 0 ; /* not convertable */
}
2019-11-01 09:15:53 +00:00
static MOO_INLINE int integer_to_oow_noseterr ( moo_t * moo , moo_oop_t x , moo_oow_t * w )
2015-12-21 17:12:57 +00:00
{
/* return value
2017-01-09 09:54:49 +00:00
* 1 - a positive number including 0 that can fit into moo_oow_t
* - 1 - a negative number whose absolute value can fit into moo_oow_t
2015-12-21 17:12:57 +00:00
* 0 - number too large or too small
*/
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2015-12-24 14:11:04 +00:00
if ( v < 0 )
{
* w = - v ;
return - 1 ;
}
else
{
* w = v ;
return 1 ;
}
}
2019-05-04 17:53:16 +00:00
MOO_ASSERT ( moo , moo_isbigint ( moo , x ) ) ;
2019-11-01 09:15:53 +00:00
return bigint_to_oow_noseterr ( moo , x , w ) ;
}
int moo_inttooow_noseterr ( moo_t * moo , moo_oop_t x , moo_oow_t * w )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
{
moo_ooi_t v ;
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v < 0 )
{
* w = - v ;
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
/* 0 -> too big, too small, or not an integer */
return moo_isbigint ( moo , x ) ? bigint_to_oow_noseterr ( moo , x , w ) : 0 ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
int moo_inttooow ( moo_t * moo , moo_oop_t x , moo_oow_t * w )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-21 17:12:57 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-27 18:02:59 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2015-12-27 18:02:59 +00:00
if ( v < 0 )
{
* w = - v ;
2019-11-01 09:15:53 +00:00
moo_seterrnum ( moo , MOO_ERANGE ) ;
2017-04-03 13:24:18 +00:00
return - 1 ; /* negative number negated - kind of an error */
2015-12-27 18:02:59 +00:00
}
else
{
* w = v ;
2017-01-06 09:53:40 +00:00
return 1 ; /* zero or positive number */
2015-12-27 18:02:59 +00:00
}
2015-12-21 17:12:57 +00:00
}
2019-11-01 09:15:53 +00:00
/* 0 -> too big, too small, or not an integer */
if ( moo_isbigint ( moo , x ) )
{
int n ;
if ( ( n = bigint_to_oow_noseterr ( moo , x , w ) ) < = 0 ) moo_seterrnum ( moo , MOO_ERANGE ) ;
return n ;
}
2015-12-24 14:11:04 +00:00
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " not an integer - %O " , x ) ;
2019-11-01 09:15:53 +00:00
return 0 ; /* error. not convertible */
2015-12-27 18:02:59 +00:00
}
2019-11-01 09:15:53 +00:00
int moo_inttoooi_noseterr ( moo_t * moo , moo_oop_t x , moo_ooi_t * i )
2017-01-15 17:53:37 +00:00
{
2019-11-01 09:15:53 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
{
* i = MOO_OOP_TO_SMOOI ( x ) ;
return ( * i < 0 ) ? - 1 : 1 ;
}
2017-01-15 17:53:37 +00:00
2019-11-01 09:15:53 +00:00
if ( moo_isbigint ( moo , x ) )
2017-04-27 15:40:04 +00:00
{
2019-11-01 09:15:53 +00:00
moo_oow_t w ;
int n ;
n = bigint_to_oow_noseterr ( moo , x , & w ) ;
if ( n < 0 )
2017-04-27 15:40:04 +00:00
{
2019-11-01 09:15:53 +00:00
MOO_STATIC_ASSERT ( MOO_TYPE_MAX ( moo_ooi_t ) + MOO_TYPE_MIN ( moo_ooi_t ) = = - 1 ) ; /* assume 2's complement */
if ( w > ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 ) return 0 ; /* too small */
* i = - w ; /* negate back */
2017-04-27 15:40:04 +00:00
}
2019-11-01 09:15:53 +00:00
else if ( n > 0 )
{
if ( w > MOO_TYPE_MAX ( moo_ooi_t ) ) return 0 ; /* too big */
* i = w ;
}
return n ;
2017-04-27 15:40:04 +00:00
}
2019-11-01 09:15:53 +00:00
return 0 ; /* not integer */
}
int moo_inttoooi ( moo_t * moo , moo_oop_t x , moo_ooi_t * i )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
2017-04-27 15:40:04 +00:00
{
2019-11-01 09:15:53 +00:00
* i = MOO_OOP_TO_SMOOI ( x ) ;
return ( * i < 0 ) ? - 1 : 1 ;
}
if ( moo_isbigint ( moo , x ) )
{
moo_oow_t w ;
int n ;
n = bigint_to_oow_noseterr ( moo , x , & w ) ;
if ( n < 0 )
2017-04-27 15:40:04 +00:00
{
2019-11-01 09:15:53 +00:00
MOO_STATIC_ASSERT ( MOO_TYPE_MAX ( moo_ooi_t ) + MOO_TYPE_MIN ( moo_ooi_t ) = = - 1 ) ; /* assume 2's complement */
if ( w > ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 )
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
return 0 ; /* too small */
}
* i = - w ; /* negate back */
2017-04-27 15:40:04 +00:00
}
2019-11-01 09:15:53 +00:00
else if ( n > 0 )
{
if ( w > MOO_TYPE_MAX ( moo_ooi_t ) )
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
return 0 ; /* too big */
}
* i = w ;
}
else
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
}
return n ;
2017-04-27 15:40:04 +00:00
}
2017-01-15 17:53:37 +00:00
2019-11-01 09:15:53 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " not an integer - %O " , x ) ;
return 0 ; /* not integer */
2017-01-15 17:53:37 +00:00
}
2019-08-10 16:20:44 +00:00
# if (MOO_SIZEOF_UINTMAX_T == MOO_SIZEOF_OOW_T)
/* do nothing. required macros are defined in moo.h */
2019-11-02 06:34:18 +00:00
# elif (MOO_SIZEOF_UINTMAX_T == MOO_SIZEOF_OOW_T * 2) || (MOO_SIZEOF_UINTMAX_T == MOO_SIZEOF_OOW_T * 4)
2019-11-01 09:15:53 +00:00
static MOO_INLINE int bigint_to_uintmax_noseterr ( moo_t * moo , moo_oop_t num , moo_uintmax_t * w )
2019-08-10 16:20:44 +00:00
{
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( num ) ) ;
MOO_ASSERT ( moo , MOO_POINTER_IS_PBIGINT ( moo , num ) | | MOO_POINTER_IS_NBIGINT ( moo , num ) ) ;
# if (MOO_LIW_BITS == MOO_OOW_BITS)
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( num ) > = 1 ) ;
switch ( MOO_OBJ_GET_SIZE ( num ) )
{
case 1 :
2019-08-11 16:15:55 +00:00
* w = ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 0 ) ;
2019-08-10 16:20:44 +00:00
goto done ;
case 2 :
2019-11-02 06:34:18 +00:00
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 0 ) < < MOO_LIW_BITS ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 1 ) ) ;
2019-08-10 16:20:44 +00:00
goto done ;
2019-11-02 06:34:18 +00:00
# if (MOO_SIZEOF_UINTMAX_T >= MOO_SIZEOF_OOW_T * 4)
case 3 :
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 0 ) < < ( MOO_LIW_BITS * 2 ) ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 1 ) < < ( MOO_LIW_BITS * 1 ) ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 2 ) )
goto done ;
case 4 :
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 0 ) < < ( MOO_LIW_BITS * 3 ) ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 1 ) < < ( MOO_LIW_BITS * 2 ) ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 2 ) < < ( MOO_LIW_BITS * 1 ) ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_WORD_VAL ( num , 3 ) )
goto done ;
# endif
2019-08-10 16:20:44 +00:00
default :
2019-11-01 09:15:53 +00:00
return 0 ; /* not convertable */
2019-08-10 16:20:44 +00:00
}
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
MOO_ASSERT ( moo , MOO_OBJ_GET_SIZE ( num ) > = 2 ) ;
switch ( MOO_OBJ_GET_SIZE ( num ) )
{
case 2 :
2019-11-02 06:34:18 +00:00
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < MOO_LIW_BITS ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 1 ) ) ;
2019-08-10 16:20:44 +00:00
goto done ;
case 4 :
2019-08-11 14:58:04 +00:00
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < MOO_LIW_BITS * 3 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < MOO_LIW_BITS * 2 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < MOO_LIW_BITS * 1 ) |
2019-11-02 06:34:18 +00:00
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 3 ) ) ;
goto done ;
# if (MOO_SIZEOF_UINTMAX_T >= MOO_SIZEOF_OOW_T * 4)
case 6 :
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < MOO_LIW_BITS * 5 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < MOO_LIW_BITS * 4 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < MOO_LIW_BITS * 3 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 3 ) < < MOO_LIW_BITS * 2 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 4 ) < < MOO_LIW_BITS * 1 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 5 ) ) ;
goto done ;
case 8 :
* w = ( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < MOO_LIW_BITS * 7 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < MOO_LIW_BITS * 6 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < MOO_LIW_BITS * 5 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 3 ) < < MOO_LIW_BITS * 4 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 4 ) < < MOO_LIW_BITS * 3 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 5 ) < < MOO_LIW_BITS * 2 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 6 ) < < MOO_LIW_BITS * 1 ) |
( ( moo_uintmax_t ) MOO_OBJ_GET_HALFWORD_VAL ( num , 7 ) ) ;
2019-08-10 16:20:44 +00:00
goto done ;
2019-11-02 06:34:18 +00:00
# endif
2019-08-10 16:20:44 +00:00
default :
2019-11-01 09:15:53 +00:00
return 0 ; /* not convertable */
2019-08-10 16:20:44 +00:00
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
done :
return ( MOO_POINTER_IS_NBIGINT ( moo , num ) ) ? - 1 : 1 ;
2019-11-01 09:15:53 +00:00
}
2019-08-10 16:20:44 +00:00
2019-11-01 09:15:53 +00:00
int moo_inttouintmax_noseterr ( moo_t * moo , moo_oop_t x , moo_uintmax_t * w )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
{
moo_ooi_t v ;
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v < 0 )
{
* w = - v ;
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
if ( moo_isbigint ( moo , x ) ) return bigint_to_uintmax_noseterr ( moo , x , w ) ;
return 0 ; /* not convertable - too big, too small, or not an integer */
2019-08-10 16:20:44 +00:00
}
int moo_inttouintmax ( moo_t * moo , moo_oop_t x , moo_uintmax_t * w )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
{
moo_ooi_t v ;
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v < 0 )
{
* w = - v ;
2019-11-01 09:15:53 +00:00
moo_seterrnum ( moo , MOO_ERANGE ) ;
2019-08-10 16:20:44 +00:00
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
2019-11-01 09:15:53 +00:00
if ( moo_isbigint ( moo , x ) )
{
int n ;
if ( ( n = bigint_to_uintmax_noseterr ( moo , x , w ) ) < = 0 ) moo_seterrnum ( moo , MOO_ERANGE ) ;
return n ;
}
2019-08-10 16:20:44 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " not an integer - %O " , x ) ;
return 0 ; /* not convertable - too big, too small, or not an integer */
}
2019-11-01 09:15:53 +00:00
int moo_inttointmax_noseterr ( moo_t * moo , moo_oop_t x , moo_intmax_t * i )
2019-08-10 16:20:44 +00:00
{
2019-11-01 09:15:53 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
{
* i = MOO_OOP_TO_SMOOI ( x ) ;
return ( * i < 0 ) ? - 1 : 1 ;
}
2019-08-10 16:20:44 +00:00
2019-11-01 09:15:53 +00:00
if ( moo_isbigint ( moo , x ) )
2019-08-10 16:20:44 +00:00
{
2019-11-01 09:15:53 +00:00
int n ;
moo_uintmax_t w ;
n = bigint_to_uintmax_noseterr ( moo , x , & w ) ;
if ( n < 0 )
{
/* negative number negated to a positve number */
MOO_STATIC_ASSERT ( MOO_TYPE_MAX ( moo_intmax_t ) + MOO_TYPE_MIN ( moo_intmax_t ) = = - 1 ) ; /* assume 2's complement */
if ( w > ( moo_uintmax_t ) MOO_TYPE_MAX ( moo_intmax_t ) + 1 ) return 0 ; /* not convertable - too small */
* i = - w ; /* negate it back */
}
else if ( n > 0 )
2019-08-10 16:20:44 +00:00
{
2019-11-01 09:15:53 +00:00
if ( w > MOO_TYPE_MAX ( moo_intmax_t ) ) return 0 ; /* not convertable - too big */
* i = w ;
2019-08-10 16:20:44 +00:00
}
2019-11-01 09:15:53 +00:00
return n ;
}
moo_seterrbfmt ( moo , MOO_EINVAL , " not an integer - %O " , x ) ;
return 0 ; /* not convertable - not an integer */
}
int moo_inttointmax ( moo_t * moo , moo_oop_t x , moo_intmax_t * i )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
{
* i = MOO_OOP_TO_SMOOI ( x ) ;
return ( * i < 0 ) ? - 1 : 1 ;
2019-08-10 16:20:44 +00:00
}
2019-11-01 09:15:53 +00:00
if ( moo_isbigint ( moo , x ) )
2019-08-10 16:20:44 +00:00
{
2019-11-01 09:15:53 +00:00
int n ;
moo_uintmax_t w ;
n = bigint_to_uintmax_noseterr ( moo , x , & w ) ;
if ( n < 0 )
2019-08-10 16:20:44 +00:00
{
2019-11-01 09:15:53 +00:00
/* negative number negated to a positve number */
MOO_STATIC_ASSERT ( MOO_TYPE_MAX ( moo_intmax_t ) + MOO_TYPE_MIN ( moo_intmax_t ) = = - 1 ) ; /* assume 2's complement */
if ( w > ( moo_uintmax_t ) MOO_TYPE_MAX ( moo_intmax_t ) + 1 )
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
return 0 ; /* not convertable. too small */
}
* i = - w ; /* negate it back */
2019-08-10 16:20:44 +00:00
}
2019-11-01 09:15:53 +00:00
else if ( n > 0 )
{
if ( w > MOO_TYPE_MAX ( moo_intmax_t ) )
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
return 0 ; /* not convertable. too big */
}
* i = w ;
}
else
{
moo_seterrnum ( moo , MOO_ERANGE ) ;
}
return n ;
2019-08-10 16:20:44 +00:00
}
2019-11-01 09:15:53 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " not an integer - %O " , x ) ;
return 0 ; /* not convertable - too big, too small, or not an integer */
2019-08-10 16:20:44 +00:00
}
# else
# error UNSUPPORTED UINTMAX SIZE
# endif
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t make_bigint_with_oow ( moo_t * moo , moo_oow_t w )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
2019-11-26 05:10:34 +00:00
MOO_STATIC_ASSERT ( MOO_SIZEOF ( moo_oow_t ) = = MOO_SIZEOF ( moo_liw_t ) ) ;
2018-12-08 15:35:26 +00:00
return moo_instantiate ( moo , moo - > _large_positive_integer , & w , 1 ) ;
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
moo_liw_t hw [ 2 ] ;
hw [ 0 ] = w /*& MOO_LBMASK(moo_oow_t,MOO_LIW_BITS)*/ ;
hw [ 1 ] = w > > MOO_LIW_BITS ;
2019-05-04 17:53:16 +00:00
return moo_instantiate ( moo , moo - > _large_positive_integer , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2015-12-21 17:12:57 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
}
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t make_bigint_with_ooi ( moo_t * moo , moo_ooi_t i )
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
2019-08-12 01:43:11 +00:00
moo_oow_t w ;
2015-11-11 13:31:05 +00:00
2019-08-11 16:15:55 +00:00
MOO_STATIC_ASSERT ( MOO_SIZEOF ( moo_oow_t ) = = MOO_SIZEOF ( moo_liw_t ) ) ;
2015-11-11 13:31:05 +00:00
if ( i > = 0 )
{
2019-08-12 01:43:11 +00:00
w = i ;
2018-12-08 15:35:26 +00:00
return moo_instantiate ( moo , moo - > _large_positive_integer , & w , 1 ) ;
2015-11-11 13:31:05 +00:00
}
else
{
2019-08-12 01:43:11 +00:00
w = ( i = = MOO_TYPE_MIN ( moo_ooi_t ) ) ? ( ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 ) : - i ;
2018-12-08 15:35:26 +00:00
return moo_instantiate ( moo , moo - > _large_negative_integer , & w , 1 ) ;
2015-11-11 13:31:05 +00:00
}
2019-08-11 16:15:55 +00:00
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
2019-08-12 01:43:11 +00:00
moo_liw_t hw [ 2 ] ;
moo_oow_t w ;
2015-10-30 15:36:37 +00:00
2019-08-11 16:15:55 +00:00
MOO_STATIC_ASSERT ( MOO_SIZEOF ( moo_oohw_t ) = = MOO_SIZEOF ( moo_liw_t ) ) ;
2015-10-30 15:36:37 +00:00
if ( i > = 0 )
{
2019-08-12 01:43:11 +00:00
w = i ;
2017-01-09 09:54:49 +00:00
hw [ 0 ] = w /*& MOO_LBMASK(moo_oow_t,MOO_LIW_BITS)*/ ;
hw [ 1 ] = w > > MOO_LIW_BITS ;
2019-05-04 17:53:16 +00:00
return moo_instantiate ( moo , moo - > _large_positive_integer , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2015-10-30 15:36:37 +00:00
}
2019-08-12 01:43:11 +00:00
else
2015-10-30 15:36:37 +00:00
{
2019-08-12 01:43:11 +00:00
w = ( i = = MOO_TYPE_MIN ( moo_ooi_t ) ) ? ( ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 ) : - i ;
2017-01-09 09:54:49 +00:00
hw [ 0 ] = w /*& MOO_LBMASK(moo_oow_t,MOO_LIW_BITS)*/ ;
hw [ 1 ] = w > > MOO_LIW_BITS ;
2019-05-04 17:53:16 +00:00
return moo_instantiate ( moo , moo - > _large_negative_integer , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2015-10-30 15:36:37 +00:00
}
2015-12-02 16:14:37 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
2015-11-11 13:31:05 +00:00
# endif
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t make_bloated_bigint_with_ooi ( moo_t * moo , moo_ooi_t i , moo_oow_t extra )
2015-12-18 15:58:45 +00:00
{
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
moo_oow_t w ;
moo_oop_t z ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , extra < = MOO_OBJ_SIZE_MAX - 1 ) ;
2019-11-26 05:10:34 +00:00
MOO_STATIC_ASSERT ( MOO_SIZEOF ( moo_oow_t ) = = MOO_SIZEOF ( moo_liw_t ) ) ;
2015-12-18 15:58:45 +00:00
if ( i > = 0 )
{
w = i ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , 1 + extra ) ;
2015-12-18 15:58:45 +00:00
}
2019-08-12 01:43:11 +00:00
2015-12-18 15:58:45 +00:00
else
{
2019-08-12 01:43:11 +00:00
w = ( i = = MOO_TYPE_MIN ( moo_ooi_t ) ) ? ( ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 ) : - i ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_negative_integer , MOO_NULL , 1 + extra ) ;
2015-12-18 15:58:45 +00:00
}
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-08-11 10:11:54 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , 0 , w ) ;
2015-12-18 15:58:45 +00:00
return z ;
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
moo_liw_t hw [ 2 ] ;
moo_oow_t w ;
moo_oop_t z ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , extra < = MOO_OBJ_SIZE_MAX - 2 ) ;
2015-12-18 15:58:45 +00:00
if ( i > = 0 )
{
w = i ;
2017-01-09 09:54:49 +00:00
hw [ 0 ] = w /*& MOO_LBMASK(moo_oow_t,MOO_LIW_BITS)*/ ;
hw [ 1 ] = w > > MOO_LIW_BITS ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , ( hw [ 1 ] > 0 ? 2 : 1 ) + extra ) ;
2015-12-18 15:58:45 +00:00
}
else
{
2019-08-12 01:43:11 +00:00
w = ( i = = MOO_TYPE_MIN ( moo_ooi_t ) ) ? ( ( moo_oow_t ) MOO_TYPE_MAX ( moo_ooi_t ) + 1 ) : - i ;
2017-01-09 09:54:49 +00:00
hw [ 0 ] = w /*& MOO_LBMASK(moo_oow_t,MOO_LIW_BITS)*/ ;
hw [ 1 ] = w > > MOO_LIW_BITS ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_negative_integer , MOO_NULL , ( hw [ 1 ] > 0 ? 2 : 1 ) + extra ) ;
2015-12-18 15:58:45 +00:00
}
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-08-11 10:11:54 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , 0 , hw [ 0 ] ) ;
if ( hw [ 1 ] > 0 ) MOO_OBJ_SET_LIWORD_VAL ( z , 1 , hw [ 1 ] ) ;
2015-12-18 15:58:45 +00:00
return z ;
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t make_bigint_with_intmax ( moo_t * moo , moo_intmax_t v )
2015-11-12 06:57:35 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t len ;
moo_liw_t buf [ MOO_SIZEOF_INTMAX_T / MOO_SIZEOF_LIW_T ] ;
moo_uintmax_t ui ;
2019-08-12 02:32:04 +00:00
moo_oop_class_t _class ;
2015-11-12 06:57:35 +00:00
2019-08-12 02:32:04 +00:00
if ( v > = 0 )
{
ui = v ;
_class = moo - > _large_positive_integer ;
}
else
{
ui = ( v = = MOO_TYPE_MIN ( moo_intmax_t ) ) ? ( ( moo_uintmax_t ) MOO_TYPE_MAX ( moo_intmax_t ) + 1 ) : - v ;
_class = moo - > _large_negative_integer ;
}
2015-11-12 06:57:35 +00:00
len = 0 ;
do
{
2017-01-09 09:54:49 +00:00
buf [ len + + ] = ( moo_liw_t ) ui ;
ui = ui > > MOO_LIW_BITS ;
2015-11-12 06:57:35 +00:00
}
while ( ui > 0 ) ;
2019-08-12 02:32:04 +00:00
return moo_instantiate ( moo , _class , buf , len ) ;
}
static MOO_INLINE moo_oop_t make_bigint_with_uintmax ( moo_t * moo , moo_uintmax_t ui )
{
moo_oow_t len ;
moo_liw_t buf [ MOO_SIZEOF_INTMAX_T / MOO_SIZEOF_LIW_T ] ;
len = 0 ;
do
{
buf [ len + + ] = ( moo_liw_t ) ui ;
ui = ui > > MOO_LIW_BITS ;
}
while ( ui > 0 ) ;
return moo_instantiate ( moo , moo - > _large_positive_integer , buf , len ) ;
2015-11-12 06:57:35 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_oowtoint ( moo_t * moo , moo_oow_t w )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_TYPE_IS_UNSIGNED ( moo_oow_t ) ) ;
/*if (MOO_IN_SMOOI_RANGE(w))*/
if ( w < = MOO_SMOOI_MAX )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( w ) ;
2015-12-27 18:02:59 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
return make_bigint_with_oow ( moo , w ) ;
2015-12-27 18:02:59 +00:00
}
}
2017-01-10 13:56:19 +00:00
moo_oop_t moo_ooitoint ( moo_t * moo , moo_ooi_t i )
{
if ( MOO_IN_SMOOI_RANGE ( i ) )
{
return MOO_SMOOI_TO_OOP ( i ) ;
}
else
{
2018-12-08 15:35:26 +00:00
return make_bigint_with_ooi ( moo , i ) ;
2017-01-10 13:56:19 +00:00
}
}
2021-03-25 16:58:24 +00:00
# if (MOO_SIZEOF_UINTMAX_T == MOO_SIZEOF_OOW_T)
/* do nothing. required macros are defined in moo.h */
# else
2019-08-11 16:15:55 +00:00
moo_oop_t moo_intmaxtoint ( moo_t * moo , moo_intmax_t i )
{
if ( MOO_IN_SMOOI_RANGE ( i ) )
{
return MOO_SMOOI_TO_OOP ( i ) ;
}
else
{
return make_bigint_with_intmax ( moo , i ) ;
}
}
2019-08-12 02:32:04 +00:00
moo_oop_t moo_uintmaxtoint ( moo_t * moo , moo_uintmax_t i )
{
if ( MOO_IN_SMOOI_RANGE ( i ) )
{
return MOO_SMOOI_TO_OOP ( i ) ;
}
else
{
return make_bigint_with_uintmax ( moo , i ) ;
}
}
2021-03-25 16:58:24 +00:00
# endif
2019-08-12 02:32:04 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t expand_bigint ( moo_t * moo , moo_oop_t oop , moo_oow_t inc )
2015-12-21 17:12:57 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i ;
moo_oow_t count ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( oop ) ) ;
count = MOO_OBJ_GET_SIZE ( oop ) ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
if ( inc > MOO_OBJ_SIZE_MAX - count )
2015-12-21 17:12:57 +00:00
{
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TODO: is it a soft failure or a hard failure? is this error code proper? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & oop ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , MOO_OBJ_GET_CLASS ( oop ) , MOO_NULL , count + inc ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-21 17:12:57 +00:00
for ( i = 0 ; i < count ; i + + )
{
2019-08-11 10:11:54 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( oop , i ) ) ;
2015-12-21 17:12:57 +00:00
}
return z ;
}
2017-02-15 11:57:24 +00:00
static MOO_INLINE moo_oop_t _clone_bigint ( moo_t * moo , moo_oop_t oop , moo_oow_t count , moo_oop_class_t _class )
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( oop ) ) ;
if ( count < = 0 ) count = MOO_OBJ_GET_SIZE ( oop ) ;
2015-10-30 15:36:37 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & oop ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , _class , MOO_NULL , count ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-10-30 15:36:37 +00:00
for ( i = 0 ; i < count ; i + + )
{
2019-08-11 10:11:54 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( oop , i ) ) ;
2015-10-30 15:36:37 +00:00
}
2015-10-29 15:24:46 +00:00
return z ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t clone_bigint ( moo_t * moo , moo_oop_t oop , moo_oow_t count )
2015-12-17 16:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
return _clone_bigint ( moo , oop , count , MOO_OBJ_GET_CLASS ( oop ) ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t clone_bigint_negated ( moo_t * moo , moo_oop_t oop , moo_oow_t count )
2015-11-12 06:57:35 +00:00
{
2017-02-15 11:57:24 +00:00
moo_oop_class_t _class ;
2015-11-12 06:57:35 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( oop ) ) ;
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , oop ) )
2015-12-17 16:11:10 +00:00
{
2017-02-15 11:57:24 +00:00
_class = moo - > _large_negative_integer ;
2015-12-17 16:11:10 +00:00
}
2015-11-12 06:57:35 +00:00
else
2015-12-17 16:11:10 +00:00
{
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , oop ) ) ;
2017-02-15 11:57:24 +00:00
_class = moo - > _large_positive_integer ;
2015-12-17 16:11:10 +00:00
}
2015-11-12 06:57:35 +00:00
2017-02-15 11:57:24 +00:00
return _clone_bigint ( moo , oop , count , _class ) ;
2015-12-17 16:11:10 +00:00
}
2015-11-12 06:57:35 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t clone_bigint_to_positive ( moo_t * moo , moo_oop_t oop , moo_oow_t count )
2015-12-17 16:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
return _clone_bigint ( moo , oop , count , moo - > _large_positive_integer ) ;
2015-11-12 06:57:35 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oow_t count_effective ( moo_liw_t * x , moo_oow_t xs )
2015-11-30 14:29:57 +00:00
{
2016-11-09 15:50:18 +00:00
#if 0
while ( xs > 1 & & x [ xs - 1 ] = = 0 ) xs - - ;
return xs ;
# else
while ( xs > 1 ) { if ( x [ - - xs ] ) return xs + 1 ; }
2015-11-30 14:29:57 +00:00
return 1 ;
2016-11-09 15:50:18 +00:00
# endif
2015-11-30 14:29:57 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oow_t count_effective_digits ( moo_oop_t oop )
2015-11-01 09:47:27 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2015-11-01 09:47:27 +00:00
2017-01-09 09:54:49 +00:00
for ( i = MOO_OBJ_GET_SIZE ( oop ) ; i > 1 ; )
2015-11-01 09:47:27 +00:00
{
- - i ;
2019-08-11 14:58:04 +00:00
if ( MOO_OBJ_GET_LIWORD_VAL ( oop , i ) ) return i + 1 ;
2015-11-01 09:47:27 +00:00
}
return 1 ;
}
2017-01-09 09:54:49 +00:00
static moo_oop_t normalize_bigint ( moo_t * moo , moo_oop_t oop )
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t count ;
2015-10-30 15:36:37 +00:00
2019-02-20 17:40:34 +00:00
if ( MOO_OOP_IS_SMOOI ( oop ) ) return oop ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_POINTER ( oop ) ) ;
2019-02-20 17:40:34 +00:00
count = count_effective_digits ( oop ) ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
2015-11-20 09:05:55 +00:00
if ( count = = 1 ) /* 1 word */
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t w ;
2015-11-11 13:31:05 +00:00
2019-08-11 14:58:04 +00:00
w = MOO_OBJ_GET_LIWORD_VAL ( oop , 0 ) ;
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , oop ) )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( w ) ;
2015-11-11 13:31:05 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , - MOO_SMOOI_MAX = = MOO_SMOOI_MIN ) ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , oop ) ) ;
2017-01-09 09:54:49 +00:00
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( - ( moo_ooi_t ) w ) ;
2015-11-11 13:31:05 +00:00
}
}
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
2015-12-02 16:14:37 +00:00
2015-11-20 09:05:55 +00:00
if ( count = = 1 ) /* 1 half-word */
2015-10-30 15:36:37 +00:00
{
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , oop ) )
2015-10-30 15:36:37 +00:00
{
2019-08-11 14:58:04 +00:00
return MOO_SMOOI_TO_OOP ( MOO_OBJ_GET_LIWORD_VAL ( oop , 0 ) ) ;
2015-10-30 15:36:37 +00:00
}
else
{
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , oop ) ) ;
2019-08-11 14:58:04 +00:00
return MOO_SMOOI_TO_OOP ( - ( moo_ooi_t ) MOO_OBJ_GET_LIWORD_VAL ( oop , 0 ) ) ;
2015-10-30 15:36:37 +00:00
}
}
2015-11-20 09:05:55 +00:00
else if ( count = = 2 ) /* 2 half-words */
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t w ;
2015-10-30 15:36:37 +00:00
2019-08-11 14:58:04 +00:00
w = MAKE_WORD ( MOO_OBJ_GET_LIWORD_VAL ( oop , 0 ) , MOO_OBJ_GET_LIWORD_VAL ( oop , 1 ) ) ;
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , oop ) )
2015-10-30 15:36:37 +00:00
{
2017-01-09 09:54:49 +00:00
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( w ) ;
2015-10-30 15:36:37 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , - MOO_SMOOI_MAX = = MOO_SMOOI_MIN ) ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , oop ) ) ;
2017-01-09 09:54:49 +00:00
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( - ( moo_ooi_t ) w ) ;
2015-10-30 15:36:37 +00:00
}
}
2015-12-02 16:14:37 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
2015-11-11 13:31:05 +00:00
# endif
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_SIZE ( oop ) = = count )
2015-10-30 15:36:37 +00:00
{
/* no compaction is needed. return it as it is */
return oop ;
}
2019-02-20 17:40:34 +00:00
return clone_bigint ( moo , oop , count ) ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_less_unsigned_array ( const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2015-10-29 15:24:46 +00:00
if ( xs ! = ys ) return xs < ys ;
for ( i = xs ; i > 0 ; )
{
- - i ;
if ( x [ i ] ! = y [ i ] ) return x [ i ] < y [ i ] ;
}
return 0 ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_less_unsigned ( moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
return is_less_unsigned_array (
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-10-29 15:24:46 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_less ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( x ) ! = MOO_OBJ_GET_CLASS ( y ) )
2015-10-29 15:24:46 +00:00
{
2018-12-21 16:25:25 +00:00
return MOO_POINTER_IS_NBIGINT ( moo , x ) ;
2015-10-29 15:24:46 +00:00
}
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2015-12-27 18:02:59 +00:00
{
2018-12-08 15:35:26 +00:00
return is_less_unsigned ( x , y ) ;
2015-12-27 18:02:59 +00:00
}
else
{
2018-12-08 15:35:26 +00:00
return is_less_unsigned ( y , x ) ;
2015-12-27 18:02:59 +00:00
}
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_greater_unsigned_array ( const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2015-12-27 18:02:59 +00:00
if ( xs ! = ys ) return xs > ys ;
for ( i = xs ; i > 0 ; )
{
- - i ;
if ( x [ i ] ! = y [ i ] ) return x [ i ] > y [ i ] ;
}
return 0 ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_greater_unsigned ( moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2018-12-08 15:35:26 +00:00
return is_greater_unsigned_array (
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_greater ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( x ) ! = MOO_OBJ_GET_CLASS ( y ) )
2015-12-27 18:02:59 +00:00
{
2018-12-21 16:25:25 +00:00
return MOO_POINTER_IS_NBIGINT ( moo , y ) ;
2015-12-27 18:02:59 +00:00
}
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2015-12-27 18:02:59 +00:00
{
2018-12-08 15:35:26 +00:00
return is_greater_unsigned ( x , y ) ;
2015-12-27 18:02:59 +00:00
}
else
{
2018-12-08 15:35:26 +00:00
return is_greater_unsigned ( y , x ) ;
2015-12-27 18:02:59 +00:00
}
2015-10-29 15:24:46 +00:00
}
2019-02-20 17:40:34 +00:00
static MOO_INLINE int is_equal_unsigned_array ( const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys )
{
return xs = = ys & & MOO_MEMCMP ( x , y , xs * MOO_SIZEOF ( * x ) ) = = 0 ;
}
static MOO_INLINE int is_equal_unsigned ( moo_oop_t x , moo_oop_t y )
{
return is_equal_unsigned_array (
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ) ;
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE int is_equal ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
/* check if two large integers are equal to each other */
2019-02-20 17:40:34 +00:00
/*return MOO_OBJ_GET_CLASS(x) == MOO_OBJ_GET_CLASS(y) && MOO_OBJ_GET_SIZE(x) == MOO_OBJ_GET_SIZE(y) &&
MOO_MEMCMP ( MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( x ) * MOO_SIZEOF ( moo_liw_t ) ) = = 0 ; */
return MOO_OBJ_GET_CLASS ( x ) = = MOO_OBJ_GET_CLASS ( y ) & & is_equal_unsigned ( x , y ) ;
2015-10-29 15:24:46 +00:00
}
2017-01-09 09:54:49 +00:00
static void complement2_unsigned_array ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , moo_liw_t * z )
2015-12-17 16:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
moo_lidw_t w ;
moo_lidw_t carry ;
2015-12-17 16:11:10 +00:00
/* get 2's complement (~x + 1) */
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2017-01-09 09:54:49 +00:00
w = ( moo_lidw_t ) ( ~ x [ i ] ) + carry ;
/*w = (moo_lidw_t)(x[i] ^ (~(moo_liw_t)0)) + carry;*/
carry = w > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
z [ i ] = w ;
}
/* if the array pointed to by x contains all zeros, carry will be
* 1 here and it actually requires 1 more slot . Let ' t take this 8 - bit
* zero for instance :
* 2 r00000000 - > 2 r11111111 + 1 = > 2 r0000000100000000
*
* this function is not designed to handle such a case .
* in fact , 0 is a small integer and it must not stand a change
* to be given to this function */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oow_t add_unsigned_array ( const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * z )
2015-10-29 15:24:46 +00:00
{
2016-11-09 15:50:18 +00:00
# if 1
2017-01-09 09:54:49 +00:00
register moo_oow_t i ;
moo_lidw_t w ;
2015-10-29 15:24:46 +00:00
2016-11-09 15:50:18 +00:00
if ( xs < ys )
{
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2017-01-09 09:54:49 +00:00
i = ( moo_oow_t ) x ;
2016-11-09 15:50:18 +00:00
x = y ;
2017-01-09 09:54:49 +00:00
y = ( moo_liw_t * ) i ;
2016-11-09 15:50:18 +00:00
}
w = 0 ;
i = 0 ;
while ( i < ys )
{
2017-01-09 09:54:49 +00:00
w + = ( moo_lidw_t ) x [ i ] + ( moo_lidw_t ) y [ i ] ;
z [ i + + ] = w & MOO_LBMASK ( moo_lidw_t , MOO_LIW_BITS ) ;
w > > = MOO_LIW_BITS ;
2016-11-09 15:50:18 +00:00
}
while ( w & & i < xs )
{
w + = x [ i ] ;
2017-01-09 09:54:49 +00:00
z [ i + + ] = w & MOO_LBMASK ( moo_lidw_t , MOO_LIW_BITS ) ;
w > > = MOO_LIW_BITS ;
2016-11-09 15:50:18 +00:00
}
while ( i < xs )
{
z [ i ] = x [ i ] ;
i + + ;
}
2017-01-09 09:54:49 +00:00
if ( w ) z [ i + + ] = w & MOO_LBMASK ( moo_lidw_t , MOO_LIW_BITS ) ;
2016-11-09 15:50:18 +00:00
return i ;
# else
2017-01-09 09:54:49 +00:00
register moo_oow_t i ;
moo_lidw_t w ;
moo_liw_t carry = 0 ;
2016-11-09 15:50:18 +00:00
if ( xs < ys )
{
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2017-01-09 09:54:49 +00:00
i = ( moo_oow_t ) x ;
2016-11-09 15:50:18 +00:00
x = y ;
2017-01-09 09:54:49 +00:00
y = ( moo_liw_t * ) i ;
2016-11-09 15:50:18 +00:00
}
2015-10-29 15:24:46 +00:00
for ( i = 0 ; i < ys ; i + + )
{
2017-01-09 09:54:49 +00:00
w = ( moo_lidw_t ) x [ i ] + ( moo_lidw_t ) y [ i ] + carry ;
carry = w > > MOO_LIW_BITS ;
z [ i ] = w /*& MOO_LBMASK(moo_lidw_t, MOO_LIW_BITS) */ ;
2015-10-29 15:24:46 +00:00
}
2015-10-30 15:36:37 +00:00
2016-11-09 15:50:18 +00:00
if ( x = = z )
2015-10-29 15:24:46 +00:00
{
2016-11-09 15:50:18 +00:00
for ( ; carry & & i < xs ; i + + )
{
2017-01-09 09:54:49 +00:00
w = ( moo_lidw_t ) x [ i ] + carry ;
carry = w > > MOO_LIW_BITS ;
z [ i ] = w /*& MOO_LBMASK(moo_lidw_t, MOO_LIW_BITS) */ ;
2016-11-09 15:50:18 +00:00
}
i = xs ;
}
else
{
for ( ; i < xs ; i + + )
{
2017-01-09 09:54:49 +00:00
w = ( moo_lidw_t ) x [ i ] + carry ;
carry = w > > MOO_LIW_BITS ;
z [ i ] = w /*& MOO_LBMASK(moo_lidw_t, MOO_LIW_BITS)*/ ;
2016-11-09 15:50:18 +00:00
}
2015-10-29 15:24:46 +00:00
}
2016-11-09 15:50:18 +00:00
if ( carry ) z [ i + + ] = carry ;
return i ; /* the number of effective digits in the result */
# endif
2015-10-29 15:24:46 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oow_t subtract_unsigned_array ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * z )
2015-10-29 15:24:46 +00:00
{
2016-11-09 15:50:18 +00:00
# if 1
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
moo_lidi_t w = 0 ;
2016-11-09 15:50:18 +00:00
if ( x = = y )
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , xs = = ys ) ;
2016-11-09 15:50:18 +00:00
z [ 0 ] = 0 ;
return 1 ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ! is_less_unsigned_array ( x , xs , y , ys ) ) ;
2016-11-09 15:50:18 +00:00
for ( i = 0 ; i < ys ; i + + )
{
2017-01-09 09:54:49 +00:00
w + = ( moo_lidi_t ) x [ i ] - ( moo_lidi_t ) y [ i ] ;
z [ i ] = w & MOO_LBMASK ( moo_lidw_t , MOO_LIW_BITS ) ;
w > > = MOO_LIW_BITS ;
2016-11-09 15:50:18 +00:00
}
while ( w & & i < xs )
{
w + = x [ i ] ;
2017-01-09 09:54:49 +00:00
z [ i + + ] = w & MOO_LBMASK ( moo_lidw_t , MOO_LIW_BITS ) ;
w > > = MOO_LIW_BITS ;
2016-11-09 15:50:18 +00:00
}
while ( i < xs )
{
z [ i ] = x [ i ] ;
i + + ;
}
while ( i > 1 & & z [ i - 1 ] = = 0 ) i - - ;
return i ;
# else
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
moo_lidw_t w ;
moo_lidw_t borrow = 0 ;
moo_lidw_t borrowed_word ;
2015-10-29 15:24:46 +00:00
2016-11-09 15:50:18 +00:00
if ( x = = y )
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , xs = = ys ) ;
2016-11-09 15:50:18 +00:00
z [ 0 ] = 0 ;
return 1 ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ! is_less_unsigned_array ( x , xs , y , ys ) ) ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
borrowed_word = ( moo_lidw_t ) 1 < < MOO_LIW_BITS ;
2015-10-29 15:24:46 +00:00
for ( i = 0 ; i < ys ; i + + )
{
2017-01-09 09:54:49 +00:00
w = ( moo_lidw_t ) y [ i ] + borrow ;
if ( ( moo_lidw_t ) x [ i ] > = w )
2015-10-29 15:24:46 +00:00
{
z [ i ] = x [ i ] - w ;
borrow = 0 ;
}
else
{
2017-01-09 09:54:49 +00:00
z [ i ] = ( borrowed_word + ( moo_lidw_t ) x [ i ] ) - w ;
2015-10-29 15:24:46 +00:00
borrow = 1 ;
}
}
for ( ; i < xs ; i + + )
{
if ( x [ i ] > = borrow )
{
2017-01-09 09:54:49 +00:00
z [ i ] = x [ i ] - ( moo_liw_t ) borrow ;
2015-10-29 15:24:46 +00:00
borrow = 0 ;
}
else
{
2017-01-09 09:54:49 +00:00
z [ i ] = ( borrowed_word + ( moo_lidw_t ) x [ i ] ) - borrow ;
2015-10-29 15:24:46 +00:00
borrow = 1 ;
}
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , borrow = = 0 ) ;
2016-11-09 15:50:18 +00:00
while ( i > 1 & & z [ i - 1 ] = = 0 ) i - - ;
return i ; /* the number of effective digits in the result */
# endif
2015-10-29 15:24:46 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void multiply_unsigned_array ( const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * z )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_lidw_t v ;
moo_oow_t pa ;
2015-11-11 13:31:05 +00:00
2016-11-09 15:50:18 +00:00
if ( xs < ys )
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2016-11-09 15:50:18 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
i = ( moo_oow_t ) x ;
2016-11-09 15:50:18 +00:00
x = y ;
2017-01-09 09:54:49 +00:00
y = ( moo_liw_t * ) i ;
2016-11-09 15:50:18 +00:00
}
2019-04-05 07:33:27 +00:00
if ( ys = = 1 )
{
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
moo_oow_t i ;
for ( i = 0 ; i < xs ; i + + )
{
dw = ( ( moo_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
z [ i ] = ( moo_liw_t ) dw ;
}
z [ i ] = carry ;
return ;
}
2016-11-09 15:50:18 +00:00
pa = xs ;
2017-01-09 09:54:49 +00:00
if ( pa < = ( ( moo_oow_t ) 1 < < ( MOO_LIDW_BITS - ( MOO_LIW_BITS * 2 ) ) ) )
2015-11-11 13:31:05 +00:00
{
2015-11-11 14:46:00 +00:00
/* Comba(column-array) multiplication */
2015-11-11 13:31:05 +00:00
2015-11-11 14:46:00 +00:00
/* when the input length is too long, v may overflow. if it
* happens , comba ' s method doesn ' t work as carry propagation is
* affected badly . so we need to use this method only if
* the input is short enough . */
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
moo_oow_t pa , ix , iy , iz , tx , ty ;
2015-11-11 13:31:05 +00:00
2015-11-11 14:46:00 +00:00
pa = xs + ys ;
v = 0 ;
for ( ix = 0 ; ix < pa ; ix + + )
2015-11-11 13:31:05 +00:00
{
2015-11-11 14:46:00 +00:00
ty = ( ix < ys - 1 ) ? ix : ( ys - 1 ) ;
tx = ix - ty ;
iy = ( ty + 1 < xs - tx ) ? ( ty + 1 ) : ( xs - tx ) ;
for ( iz = 0 ; iz < iy ; iz + + )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
v = v + ( moo_lidw_t ) x [ tx + iz ] * ( moo_lidw_t ) y [ ty - iz ] ;
2015-11-11 13:31:05 +00:00
}
2017-01-09 09:54:49 +00:00
z [ ix ] = ( moo_liw_t ) v ;
v = v > > MOO_LIW_BITS ;
2015-11-11 13:31:05 +00:00
}
}
2015-11-11 14:46:00 +00:00
else
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t i , j ;
moo_liw_t carry ;
2015-11-11 13:31:05 +00:00
2016-11-09 15:50:18 +00:00
for ( i = 0 ; i < xs ; i + + )
2015-11-11 13:31:05 +00:00
{
2016-11-09 15:50:18 +00:00
if ( x [ i ] = = 0 )
2015-11-11 14:46:00 +00:00
{
2016-11-09 15:50:18 +00:00
z [ i + ys ] = 0 ;
2015-11-11 14:46:00 +00:00
}
else
{
carry = 0 ;
2016-11-09 15:50:18 +00:00
for ( j = 0 ; j < ys ; j + + )
2015-11-11 14:46:00 +00:00
{
2017-01-09 09:54:49 +00:00
v = ( moo_lidw_t ) x [ i ] * ( moo_lidw_t ) y [ j ] + ( moo_lidw_t ) carry + ( moo_lidw_t ) z [ i + j ] ;
z [ i + j ] = ( moo_liw_t ) v ;
carry = ( moo_liw_t ) ( v > > MOO_LIW_BITS ) ;
2015-11-11 14:46:00 +00:00
}
2016-11-09 15:50:18 +00:00
z [ i + j ] = carry ;
2015-11-11 14:46:00 +00:00
}
2015-11-11 13:31:05 +00:00
}
2016-11-09 15:50:18 +00:00
}
}
2015-11-11 13:31:05 +00:00
2016-11-09 15:50:18 +00:00
/* KARATSUBA MULTIPLICATION
*
* c = | a | * | b |
*
* Let B represent the radix ( 2 ^ DIGIT_BITS )
* Let n represent half the number of digits
*
* a = a1 * B ^ n + a0
* b = b1 * B ^ n + b0
* a * b = > a1b1 * B ^ 2 n + ( ( a1 + a0 ) ( b1 + b0 ) - ( a0b0 + a1b1 ) ) * B ^ n + a0b0
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* For example , for 2 number 0xFAC2 and 0xABCD = > A848635A
* DIGIT_BITS = 8 ( 1 byte , each digit is 1 byte long )
* B = 2 ^ 8 = 0x100
* n = 1 ( half the digits of 2 digit numbers )
* B ^ n = 0x100 ^ 1 = 0x100
* B ^ 2 n = 0x100 ^ 2 = 0x10000
* 0xFAC2 = 0xFA * 0x100 + 0xC2
* 0xABCD = 0xAB * 0x100 + 0xCD
* a1 = 0xFA , a0 = 0xC2
* b1 = 0xAB , b0 = 0xCD
* a1b1 = 0xFA * 0xAB = 0xA6FE
* a0b0 = 0xC2 * 0xCD = 0x9B5A
* a1 + a0 = 0xFA + 0xC2 = 0x1BC
* b1 + b0 = 0xAB + 0xCD = 0x178
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* ( A6FE * 10000 ) + ( ( ( 1 BC * 178 ) - ( 985 A + A6FE ) ) * 100 ) + 9 B5A =
* ( A6FE < < ( 8 * 2 ) ) + ( ( ( 1 BC * 178 ) - ( 985 A + A6FE ) ) < < ( 8 * 1 ) ) =
* A6FE0000 + 14 CC800 + 9 B5A = 9848635 A
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* 0xABCD9876 * 0xEFEFABAB = > 0xA105C97C9755A8D2
* B = 2 ^ 8 = 0x100
* n = 2
* B ^ n = 0x100 ^ 2 = 0x10000
* B ^ 2 n = 0x100 ^ 4 = 0x100000000
* 0xABCD9876 = 0xABCD * 0x10000 + 0x9876
* 0xEFEFABAB = 0xEFEF * 0x10000 + 0xABAB
* a1 = 0xABCD , a0 = 0x9876
* b1 - 0xEFEF , b0 = 0xABAB
* a1b1 = 0xA104C763
* a0b0 = 0x663CA8D2
* a1 + a0 = 0x14443
* b1 + b0 = 0x19B9A
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* ( A104C763 * 100000000 ) + ( ( ( 14443 * 19 B9A ) - ( 663 CA8D2 + A104C763 ) ) * 10000 ) + 663 CA8D2 =
* ( A104C763 < < ( 8 * 4 ) ) + ( ( ( 14443 * 19 B9A ) - ( 663 CA8D2 + A104C763 ) ) < < ( 8 * 2 ) ) + 663 CA8D2 = A105C97C9755A8D2
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Multiplying by B is t same as shifting by DIGIT_BITS .
2017-01-09 09:54:49 +00:00
* DIGIT_BITS in this implementation is MOO_LIW_BITS
* B = > 2 ^ MOO_LIW_BITS
* X * B ^ n = > X < < ( MOO_LIW_BITS * n )
* X * B ^ 2 n = > X < < ( MOO_LIW_BITS * n * 2 )
2016-11-09 15:50:18 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2017-12-16 16:14:23 +00:00
2018-02-21 09:35:59 +00:00
# if defined(MOO_BUILD_DEBUG)
2017-12-16 16:14:23 +00:00
# define CANNOT_KARATSUBA(moo,xs,ys) \
( ( xs ) < ( moo ) - > option . karatsuba_cutoff | | ( ys ) < ( moo ) - > option . karatsuba_cutoff | | \
( ( xs ) > ( ys ) & & ( ys ) < = ( ( ( xs ) + 1 ) / 2 ) ) | | \
( ( xs ) < ( ys ) & & ( xs ) < = ( ( ( ys ) + 1 ) / 2 ) ) )
# else
# define CANNOT_KARATSUBA(moo,xs,ys) \
2017-12-16 16:24:21 +00:00
( ( xs ) < MOO_KARATSUBA_CUTOFF | | ( ys ) < MOO_KARATSUBA_CUTOFF | | \
2016-11-09 15:50:18 +00:00
( ( xs ) > ( ys ) & & ( ys ) < = ( ( ( xs ) + 1 ) / 2 ) ) | | \
( ( xs ) < ( ys ) & & ( xs ) < = ( ( ( ys ) + 1 ) / 2 ) ) )
2017-12-16 16:14:23 +00:00
# endif
2015-11-11 14:46:00 +00:00
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oow_t multiply_unsigned_array_karatsuba ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * z )
2016-11-09 15:50:18 +00:00
{
# if 1
2017-01-09 09:54:49 +00:00
moo_lidw_t nshifts ;
moo_lidw_t ndigits_xh , ndigits_xl ;
moo_lidw_t ndigits_yh , ndigits_yl ;
moo_liw_t * tmp [ 2 ] = { MOO_NULL , MOO_NULL } ;
moo_liw_t * zsp ;
moo_oow_t tmplen [ 2 ] ;
moo_oow_t xlen , zcapa ;
2016-11-09 15:50:18 +00:00
zcapa = xs + ys ; /* the caller ensures this capacity for z at the minimum*/
if ( xs < ys )
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2015-11-11 13:31:05 +00:00
2016-11-09 15:50:18 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
i = ( moo_oow_t ) x ;
2016-11-09 15:50:18 +00:00
x = y ;
2017-01-09 09:54:49 +00:00
y = ( moo_liw_t * ) i ;
2016-11-09 15:50:18 +00:00
}
2015-11-11 14:46:00 +00:00
2019-04-05 07:33:27 +00:00
if ( ys = = 1 )
{
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
moo_oow_t i ;
for ( i = 0 ; i < xs ; i + + )
{
dw = ( ( moo_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
z [ i ] = ( moo_liw_t ) dw ;
}
z [ i ] = carry ;
2019-04-07 11:23:24 +00:00
return count_effective ( z , xs + 1 ) ;
2019-04-05 07:33:27 +00:00
}
2017-01-09 09:54:49 +00:00
/* calculate value of nshifts, that is 2^(MOO_LIW_BITS*nshifts) */
2016-11-09 15:50:18 +00:00
nshifts = ( xs + 1 ) / 2 ;
ndigits_xl = nshifts ; /* ndigits of lower part of x */
ndigits_xh = xs - nshifts ; /* ndigits of upper part of x */
ndigits_yl = nshifts ; /* ndigits of lower part of y */
ndigits_yh = ys - nshifts ; /* ndigits of uppoer part of y */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ndigits_xl > = ndigits_xh ) ;
MOO_ASSERT ( moo , ndigits_yl > = ndigits_yh ) ;
2016-11-09 15:50:18 +00:00
/* make a temporary buffer for (b0 + b1) and (a1 * b1) */
tmplen [ 0 ] = ndigits_xh + ndigits_yh ;
tmplen [ 1 ] = ndigits_yl + ndigits_yh + 1 ;
if ( tmplen [ 1 ] < tmplen [ 0 ] ) tmplen [ 1 ] = tmplen [ 0 ] ;
2019-04-16 15:43:54 +00:00
tmp [ 1 ] = ( moo_liw_t * ) moo_callocmem ( moo , MOO_SIZEOF ( moo_liw_t ) * tmplen [ 1 ] ) ; /* TODO: should i use the object memory? if not, reuse the buffer and minimize memory allocation */
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! tmp [ 1 ] ) ) goto oops ;
2016-11-09 15:50:18 +00:00
/* make a temporary for (a0 + a1) and (a0 * b0) */
tmplen [ 0 ] = ndigits_xl + ndigits_yl + 1 ;
2018-02-26 15:30:38 +00:00
tmp [ 0 ] = ( moo_liw_t * ) moo_callocmem ( moo , MOO_SIZEOF ( moo_liw_t ) * tmplen [ 0 ] ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! tmp [ 0 ] ) ) goto oops ;
2016-11-09 15:50:18 +00:00
/* tmp[0] = a0 + a1 */
2019-04-05 07:33:27 +00:00
tmplen [ 0 ] = add_unsigned_array ( x , ndigits_xl , x + nshifts , ndigits_xh , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
/* tmp[1] = b0 + b1 */
2019-04-05 07:33:27 +00:00
tmplen [ 1 ] = add_unsigned_array ( y , ndigits_yl , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
2017-01-09 09:54:49 +00:00
/*MOO_DEBUG6 (moo, "karatsuba t %p u %p ndigits_xl %d ndigits_xh %d ndigits_yl %d ndigits_yh %d\n", tmp[0], tmp[1], (int)ndigits_xl, (int)ndigits_xh, (int)ndigits_yl, (int)ndigits_yh);*/
/*MOO_DEBUG5 (moo, "zcapa %d, tmplen[0] %d tmplen[1] %d nshifts %d total %d\n", (int)zcapa, (int)tmplen[0], (int)tmplen[1], (int)nshifts, (int)(tmplen[0] + tmplen[1] + nshifts));*/
2016-11-09 15:50:18 +00:00
/* place (a0 + a1) * (b0 + b1) at the shifted position */
zsp = z + nshifts ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , tmplen [ 0 ] , tmplen [ 1 ] ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2019-03-29 17:44:32 +00:00
xlen = count_effective ( zsp , tmplen [ 0 ] + tmplen [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
xlen = multiply_unsigned_array_karatsuba ( moo , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2016-11-09 15:50:18 +00:00
if ( xlen = = 0 ) goto oops ;
}
/* tmp[0] = a0 * b0 */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( tmp [ 0 ] , 0 , sizeof ( moo_liw_t ) * tmplen [ 0 ] ) ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , ndigits_xl , ndigits_yl ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
tmplen [ 0 ] = count_effective ( tmp [ 0 ] , tmplen [ 0 ] ) ;
}
else
{
2019-04-22 14:46:23 +00:00
tmplen [ 0 ] = multiply_unsigned_array_karatsuba ( moo , x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
if ( tmplen [ 0 ] < = 0 ) goto oops ;
}
/* tmp[1] = a1 * b1 */
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( tmp [ 1 ] , 0 , sizeof ( moo_liw_t ) * tmplen [ 1 ] ) ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , ndigits_xh , ndigits_yh ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2019-03-29 17:44:32 +00:00
tmplen [ 1 ] = count_effective ( tmp [ 1 ] , tmplen [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
}
else
{
2019-04-22 14:46:23 +00:00
tmplen [ 1 ] = multiply_unsigned_array_karatsuba ( moo , x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
if ( tmplen [ 1 ] < = 0 ) goto oops ;
}
/* (a0+a1)*(b0+b1) -(a0*b0) */
2017-01-09 09:54:49 +00:00
xlen = subtract_unsigned_array ( moo , zsp , xlen , tmp [ 0 ] , tmplen [ 0 ] , zsp ) ;
2016-11-09 15:50:18 +00:00
/* (a0+a1)*(b0+b1) - (a0*b0) - (a1*b1) */
2017-01-09 09:54:49 +00:00
xlen = subtract_unsigned_array ( moo , zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2016-11-09 15:50:18 +00:00
/* a1b1 is in tmp[1]. add (a1b1 * B^2n) to the high part of 'z' */
zsp = z + ( nshifts * 2 ) ; /* emulate shifting for "* B^2n". */
xlen = zcapa - ( nshifts * 2 ) ;
2019-04-22 14:46:23 +00:00
xlen = add_unsigned_array ( zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2016-11-09 15:50:18 +00:00
/* z = z + a0b0. a0b0 is in tmp[0] */
xlen = add_unsigned_array ( z , zcapa , tmp [ 0 ] , tmplen [ 0 ] , z ) ;
2017-01-09 09:54:49 +00:00
moo_freemem ( moo , tmp [ 1 ] ) ;
moo_freemem ( moo , tmp [ 0 ] ) ;
2019-03-29 17:44:32 +00:00
return count_effective ( z , xlen ) ;
2016-11-09 15:50:18 +00:00
oops :
2017-01-09 09:54:49 +00:00
if ( tmp [ 1 ] ) moo_freemem ( moo , tmp [ 1 ] ) ;
if ( tmp [ 0 ] ) moo_freemem ( moo , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
return 0 ;
# else
2017-01-09 09:54:49 +00:00
moo_lidw_t nshifts ;
moo_lidw_t ndigits_xh , ndigits_xl ;
moo_lidw_t ndigits_yh , ndigits_yl ;
moo_liw_t * tmp [ 3 ] = { MOO_NULL , MOO_NULL , MOO_NULL } ;
moo_liw_t * zsp ;
moo_oow_t tmplen [ 3 ] ;
moo_oow_t xlen , zcapa ;
2016-11-09 15:50:18 +00:00
zcapa = xs + ys ; /* the caller ensures this capacity for z at the minimum*/
if ( xs < ys )
{
2017-01-09 09:54:49 +00:00
moo_oow_t i ;
2016-11-09 15:50:18 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2017-01-09 09:54:49 +00:00
i = ( moo_oow_t ) x ;
2016-11-09 15:50:18 +00:00
x = y ;
2017-01-09 09:54:49 +00:00
y = ( moo_liw_t * ) i ;
2016-11-09 15:50:18 +00:00
}
2019-04-05 07:33:27 +00:00
if ( ys = = 1 )
{
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
moo_oow_t i ;
for ( i = 0 ; i < xs ; i + + )
{
dw = ( ( moo_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
z [ i ] = ( moo_liw_t ) dw ;
}
z [ i ] = carry ;
return ;
}
2017-01-09 09:54:49 +00:00
/* calculate value of nshifts, that is 2^(MOO_LIW_BITS*nshifts) */
2016-11-09 15:50:18 +00:00
nshifts = ( xs + 1 ) / 2 ;
ndigits_xl = nshifts ; /* ndigits of lower part of x */
ndigits_xh = xs - nshifts ; /* ndigits of upper part of x */
ndigits_yl = nshifts ; /* ndigits of lower part of y */
ndigits_yh = ys - nshifts ; /* ndigits of uppoer part of y */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ndigits_xl > = ndigits_xh ) ;
MOO_ASSERT ( moo , ndigits_yl > = ndigits_yh ) ;
2016-11-09 15:50:18 +00:00
/* make a temporary buffer for (b0 + b1) and (a1 * b1) */
tmplen [ 0 ] = ndigits_yl + ndigits_yh + 1 ;
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
if ( tmplen [ 1 ] < tmplen [ 0 ] ) tmplen [ 1 ] = tmplen [ 0 ] ;
2018-11-03 16:11:55 +00:00
tmp [ 1 ] = ( moo_liw_t * ) moo_callocmem ( moo , MOO_SIZEOF ( moo_liw_t ) * tmplen [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
if ( ! tmp [ 1 ] ) goto oops ;
/* make a temporary for (a0 + a1) and (a0 * b0) */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2018-11-03 16:11:55 +00:00
tmp [ 0 ] = ( moo_liw_t * ) moo_callocmem ( moo , MOO_SIZEOF ( moo_liw_t ) * tmplen [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
if ( ! tmp [ 0 ] ) goto oops ;
/* tmp[0] = a0 + a1 */
tmplen [ 0 ] = add_unsigned_array ( x , ndigits_xl , x + nshifts , ndigits_xh , tmp [ 0 ] ) ;
/* tmp[1] = b0 + b1 */
tmplen [ 1 ] = add_unsigned_array ( y , ndigits_yl , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
/* tmp[2] = (a0 + a1) * (b0 + b1) */
tmplen [ 2 ] = tmplen [ 0 ] + tmplen [ 1 ] ;
2019-04-22 14:46:23 +00:00
tmp [ 2 ] = moo_callocmem ( moo , MOO_SIZEOF ( moo_liw_t ) * tmplen [ 2 ] ) ;
2016-11-09 15:50:18 +00:00
if ( ! tmp [ 2 ] ) goto oops ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , tmplen [ 0 ] , tmplen [ 1 ] ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , tmp [ 2 ] ) ;
2019-03-29 17:44:32 +00:00
xlen = count_effective ( tmp [ 2 ] , tmplen [ 2 ] ) ;
2016-11-09 15:50:18 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
xlen = multiply_unsigned_array_karatsuba ( moo , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , tmp [ 2 ] ) ;
2016-11-09 15:50:18 +00:00
if ( xlen = = 0 ) goto oops ;
}
/* tmp[0] = a0 * b0 */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( tmp [ 0 ] , 0 , sizeof ( moo_liw_t ) * tmplen [ 0 ] ) ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , ndigits_xl , ndigits_yl ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
tmplen [ 0 ] = count_effective ( tmp [ 0 ] , tmplen [ 0 ] ) ;
}
else
{
2017-01-09 09:54:49 +00:00
tmplen [ 0 ] = multiply_unsigned_array_karatsuba ( moo , x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
if ( tmplen [ 0 ] < = 0 ) goto oops ;
}
/* tmp[1] = a1 * b1 */
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( tmp [ 1 ] , 0 , sizeof ( moo_liw_t ) * tmplen [ 1 ] ) ;
2017-12-16 16:14:23 +00:00
if ( CANNOT_KARATSUBA ( moo , ndigits_xh , ndigits_yh ) )
2016-11-09 15:50:18 +00:00
{
multiply_unsigned_array ( x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2019-03-29 17:44:32 +00:00
tmplen [ 1 ] = count_effective ( tmp [ 1 ] , tmplen [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
tmplen [ 1 ] = multiply_unsigned_array_karatsuba ( moo , x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2016-11-09 15:50:18 +00:00
if ( tmplen [ 1 ] < = 0 ) goto oops ;
2015-11-11 14:46:00 +00:00
}
2016-11-09 15:50:18 +00:00
/* w = w - tmp[0] */
2017-01-09 09:54:49 +00:00
xlen = subtract_unsigned_array ( moo , tmp [ 2 ] , xlen , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 2 ] ) ;
2016-11-09 15:50:18 +00:00
/* r = w - tmp[1] */
zsp = z + nshifts ; /* emulate shifting for "* B^n" */
2017-01-09 09:54:49 +00:00
xlen = subtract_unsigned_array ( moo , tmp [ 2 ] , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2016-11-09 15:50:18 +00:00
/* a1b1 is in tmp[1]. add (a1b1 * B^2n) to the high part of 'z' */
zsp = z + ( nshifts * 2 ) ; /* emulate shifting for "* B^2n". */
xlen = zcapa - ( nshifts * 2 ) ;
xlen = add_unsigned_array ( zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
/* z = z + a0b0. a0b0 is in tmp[0] */
xlen = add_unsigned_array ( z , zcapa , tmp [ 0 ] , tmplen [ 0 ] , z ) ;
2017-01-09 09:54:49 +00:00
moo_freemem ( moo , tmp [ 2 ] ) ;
moo_freemem ( moo , tmp [ 1 ] ) ;
moo_freemem ( moo , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
2019-03-29 17:16:03 +00:00
return count_effective ( z , xlen ) ;
2016-11-09 15:50:18 +00:00
oops :
2017-01-09 09:54:49 +00:00
if ( tmp [ 2 ] ) moo_freemem ( moo , tmp [ 2 ] ) ;
if ( tmp [ 1 ] ) moo_freemem ( moo , tmp [ 1 ] ) ;
if ( tmp [ 0 ] ) moo_freemem ( moo , tmp [ 0 ] ) ;
2016-11-09 15:50:18 +00:00
return 0 ;
# endif
2015-11-11 13:31:05 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void lshift_unsigned_array ( moo_liw_t * x , moo_oow_t xs , moo_oow_t bits )
2015-11-17 14:13:59 +00:00
{
/* this function doesn't grow/shrink the array. Shifting is performed
* over the given array */
2017-01-09 09:54:49 +00:00
moo_oow_t word_shifts , bit_shifts , bit_shifts_right ;
moo_oow_t si , di ;
2015-11-17 14:13:59 +00:00
/* get how many words to shift */
2017-01-09 09:54:49 +00:00
word_shifts = bits / MOO_LIW_BITS ;
2015-11-17 14:13:59 +00:00
if ( word_shifts > = xs )
{
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( x , 0 , xs * MOO_SIZEOF ( moo_liw_t ) ) ;
2015-11-17 14:13:59 +00:00
return ;
}
/* get how many remaining bits to shift */
2017-01-09 09:54:49 +00:00
bit_shifts = bits % MOO_LIW_BITS ;
bit_shifts_right = MOO_LIW_BITS - bit_shifts ;
2015-11-17 14:13:59 +00:00
/* shift words and bits */
di = xs - 1 ;
si = di - word_shifts ;
x [ di ] = x [ si ] < < bit_shifts ;
while ( di > word_shifts )
{
x [ di ] = x [ di ] | ( x [ - - si ] > > bit_shifts_right ) ;
x [ - - di ] = x [ si ] < < bit_shifts ;
}
/* fill the remaining part with zeros */
if ( word_shifts > 0 )
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( x , 0 , word_shifts * MOO_SIZEOF ( moo_liw_t ) ) ;
2015-11-17 14:13:59 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE void rshift_unsigned_array ( moo_liw_t * x , moo_oow_t xs , moo_oow_t bits )
2015-11-17 14:13:59 +00:00
{
/* this function doesn't grow/shrink the array. Shifting is performed
* over the given array */
2017-01-09 09:54:49 +00:00
moo_oow_t word_shifts , bit_shifts , bit_shifts_left ;
moo_oow_t si , di , bound ;
2015-11-17 14:13:59 +00:00
/* get how many words to shift */
2017-01-09 09:54:49 +00:00
word_shifts = bits / MOO_LIW_BITS ;
2015-11-17 14:13:59 +00:00
if ( word_shifts > = xs )
{
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( x , 0 , xs * MOO_SIZEOF ( moo_liw_t ) ) ;
2015-11-17 14:13:59 +00:00
return ;
}
/* get how many remaining bits to shift */
2017-01-09 09:54:49 +00:00
bit_shifts = bits % MOO_LIW_BITS ;
bit_shifts_left = MOO_LIW_BITS - bit_shifts ;
2015-11-17 14:13:59 +00:00
/* TODO: verify this function */
/* shift words and bits */
di = 0 ;
si = word_shifts ;
x [ di ] = x [ si ] > > bit_shifts ;
bound = xs - word_shifts - 1 ;
while ( di < bound )
{
x [ di ] = x [ di ] | ( x [ + + si ] < < bit_shifts_left ) ;
x [ + + di ] = x [ si ] > > bit_shifts ;
}
/* fill the remaining part with zeros */
if ( word_shifts > 0 )
2017-01-09 09:54:49 +00:00
MOO_MEMSET ( & x [ xs - word_shifts ] , 0 , word_shifts * MOO_SIZEOF ( moo_liw_t ) ) ;
2015-11-17 14:13:59 +00:00
}
2017-01-09 09:54:49 +00:00
static void divide_unsigned_array ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * q , moo_liw_t * r )
2015-11-20 09:05:55 +00:00
{
2015-12-18 15:58:45 +00:00
/* TODO: this function needs to be rewritten for performance improvement.
* the binary long division is extremely slow for a big number */
2015-11-20 09:05:55 +00:00
/* Perform binary long division.
* http : //en.wikipedia.org/wiki/Division_algorithm
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Q : = 0 initialize quotient and remainder to zero
* R : = 0
* for i = n - 1. . .0 do where n is number of bits in N
* R : = R < < 1 left - shift R by 1 bit
* R ( 0 ) : = X ( i ) set the least - significant bit of R equal to bit i of the numerator
* if R > = Y then
2019-02-20 09:43:59 +00:00
* R = R - Y
2015-11-20 09:05:55 +00:00
* Q ( i ) : = 1
* end
* end
*/
2019-04-03 19:19:09 +00:00
moo_oow_t rs , rrs , i , j ;
2015-11-20 09:05:55 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , xs > = ys ) ;
2015-11-30 14:29:57 +00:00
2019-04-03 19:19:09 +00:00
/* the caller must ensure:
* - q and r are all zeros . can skip memset ( ) with zero .
* - q is as large as xs in size .
* - r is as large as ys + 1 in size */
/*MOO_MEMSET (q, 0, MOO_SIZEOF(*q) * xs);
MOO_MEMSET ( r , 0 , MOO_SIZEOF ( * q ) * ys ) ; */
rrs = ys + 1 ;
2015-11-30 14:29:57 +00:00
for ( i = xs ; i > 0 ; )
2015-11-20 09:05:55 +00:00
{
2015-11-30 14:29:57 +00:00
- - i ;
2017-01-09 09:54:49 +00:00
for ( j = MOO_LIW_BITS ; j > 0 ; )
2015-11-30 14:29:57 +00:00
{
- - j ;
2019-04-03 19:19:09 +00:00
/* the value of the remainder 'r' may get bigger than the
* divisor ' y ' temporarily until subtraction is performed
* below . so ys + 1 ( kept in rrs ) is needed for shifting here . */
lshift_unsigned_array ( r , rrs , 1 ) ;
2017-01-09 09:54:49 +00:00
MOO_SETBITS ( moo_liw_t , r [ 0 ] , 0 , 1 , MOO_GETBITS ( moo_liw_t , x [ i ] , j , 1 ) ) ;
2015-11-20 09:05:55 +00:00
2019-04-03 19:19:09 +00:00
rs = count_effective ( r , rrs ) ;
2019-03-22 08:06:14 +00:00
if ( ! is_less_unsigned_array ( r , rs , y , ys ) )
2015-11-30 14:29:57 +00:00
{
2017-01-09 09:54:49 +00:00
subtract_unsigned_array ( moo , r , rs , y , ys , r ) ;
MOO_SETBITS ( moo_liw_t , q [ i ] , j , 1 , 1 ) ;
2015-11-30 14:29:57 +00:00
}
}
}
2015-11-20 09:05:55 +00:00
}
2019-04-08 04:00:47 +00:00
static MOO_INLINE moo_liw_t calculate_remainder ( moo_t * moo , moo_liw_t * qr , moo_liw_t * y , moo_liw_t quo , int qr_start , int stop )
2019-04-02 08:49:41 +00:00
{
moo_lidw_t dw ;
2019-04-04 09:30:24 +00:00
moo_liw_t b , c , c2 , qyk ;
moo_oow_t j , k ;
2019-04-02 08:49:41 +00:00
2019-04-04 09:30:24 +00:00
for ( b = 0 , c = 0 , c2 = 0 , j = qr_start , k = 0 ; k < stop ; j + + , k + + )
2019-04-02 08:49:41 +00:00
{
dw = ( moo_lidw_t ) qr [ j ] - b ;
2019-04-04 09:30:24 +00:00
b = ( moo_liw_t ) ( ( dw > > MOO_LIW_BITS ) & 1 ) ; /* b = -(dw mod BASE) */
2019-04-02 08:49:41 +00:00
qr [ j ] = ( moo_liw_t ) dw ;
2019-04-04 09:30:24 +00:00
dw = ( ( moo_lidw_t ) y [ k ] * quo ) + c ;
2019-04-02 08:49:41 +00:00
c = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
qyk = ( moo_liw_t ) dw ;
2019-04-04 09:30:24 +00:00
dw = ( moo_lidw_t ) qr [ j ] - qyk ;
c2 = ( moo_liw_t ) ( ( dw > > MOO_LIW_BITS ) & 1 ) ;
2019-04-02 08:49:41 +00:00
qr [ j ] = ( moo_liw_t ) dw ;
dw = ( moo_lidw_t ) b + c2 + c ;
c = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
b = ( moo_liw_t ) dw ;
MOO_ASSERT ( moo , c = = 0 ) ;
}
return b ;
}
2019-04-03 19:19:09 +00:00
static void divide_unsigned_array2 ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * q , moo_liw_t * r )
2019-03-29 07:05:53 +00:00
{
2019-04-01 08:45:21 +00:00
moo_oow_t i ;
2019-04-02 08:49:41 +00:00
moo_liw_t d , y1 , y2 ;
2019-04-03 19:19:09 +00:00
/* the caller must ensure:
* - q can hold ' xs + 1 ' words and r can hold ' ys ' words .
* - q and r are set to all zeros . */
2019-04-02 18:56:25 +00:00
MOO_ASSERT ( moo , xs > = ys ) ;
2019-04-03 19:19:09 +00:00
if ( ys = = 1 )
{
/* the divisor has a single word only. perform simple division */
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
for ( i = xs ; i > 0 ; )
{
- - i ;
2019-04-04 09:30:24 +00:00
dw = ( ( moo_lidw_t ) carry < < MOO_LIW_BITS ) + x [ i ] ;
2019-04-03 19:19:09 +00:00
q [ i ] = ( moo_liw_t ) ( dw / y [ 0 ] ) ;
carry = ( moo_liw_t ) ( dw % y [ 0 ] ) ;
}
r [ 0 ] = carry ;
return ;
}
2019-04-04 09:30:24 +00:00
for ( i = 0 ; i < xs ; i + + ) q [ i ] = x [ i ] ; /* copy x to q */
q [ xs ] = 0 ; /* store zero in the last extra word */
2019-04-02 18:56:25 +00:00
for ( i = 0 ; i < ys ; i + + ) r [ i ] = y [ i ] ; /* copy y to r */
y1 = r [ ys - 1 ] ; /* highest divisor word */
2019-04-06 05:06:11 +00:00
2019-04-07 11:23:24 +00:00
/*d = (y1 == MOO_TYPE_MAX(moo_liw_t)? ((moo_liw_t)1): ((moo_liw_t)(((moo_lidw_t)1 << MOO_LIW_BITS) / (y1 + 1))));*/
2019-04-06 05:06:11 +00:00
d = ( moo_liw_t ) ( ( ( moo_lidw_t ) 1 < < MOO_LIW_BITS ) / ( ( moo_lidw_t ) y1 + 1 ) ) ;
2019-04-01 08:45:21 +00:00
if ( d > 1 )
{
2019-04-02 18:56:25 +00:00
moo_lidw_t dw ;
moo_liw_t carry ;
2019-04-06 05:06:11 +00:00
/* shift the divisor such that its high-order bit is on.
* shift the dividend the same amount as the previous step */
2019-04-02 18:56:25 +00:00
/* r = r * d */
for ( carry = 0 , i = 0 ; i < ys ; i + + )
{
dw = ( ( moo_lidw_t ) r [ i ] * d ) + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
r [ i ] = ( moo_liw_t ) dw ;
}
MOO_ASSERT ( moo , carry = = 0 ) ;
2019-04-06 05:06:11 +00:00
/* q = q * d */
for ( carry = 0 , i = 0 ; i < xs ; i + + )
{
dw = ( ( moo_lidw_t ) q [ i ] * d ) + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
q [ i ] = ( moo_liw_t ) dw ;
}
q [ xs ] = carry ;
2019-04-01 08:45:21 +00:00
}
2019-03-29 07:05:53 +00:00
2019-04-02 18:56:25 +00:00
y1 = r [ ys - 1 ] ;
y2 = r [ ys - 2 ] ;
2019-04-02 08:49:41 +00:00
2019-04-02 18:56:25 +00:00
for ( i = xs ; i > = ys ; - - i )
2019-03-29 07:05:53 +00:00
{
2019-04-08 01:18:00 +00:00
moo_lidw_t dw , quo , rem ;
moo_liw_t b , xhi , xlo ;
2019-04-01 08:45:21 +00:00
2019-04-05 07:33:27 +00:00
/* ---------------------------------------------------------- */
/* estimate the quotient.
* 2 - current - dividend - words / 2 - most - significant - divisor - words */
2019-04-02 08:49:41 +00:00
xhi = q [ i ] ;
xlo = q [ i - 1 ] ;
2019-04-01 08:45:21 +00:00
2019-04-08 01:18:00 +00:00
/* adjust the quotient if over-estimated */
dw = ( ( moo_lidw_t ) xhi < < MOO_LIW_BITS ) + xlo ;
/* TODO: optimize it with ASM - no seperate / and % */
quo = dw / y1 ;
rem = dw % y1 ;
2019-04-08 09:19:16 +00:00
2019-04-08 01:18:00 +00:00
adjust_quotient :
if ( quo > MOO_TYPE_MAX ( moo_liw_t ) | | ( quo * y2 ) > ( ( rem < < MOO_LIW_BITS ) + q [ i - 2 ] ) )
{
- - quo ;
rem + = y1 ;
if ( rem < = MOO_TYPE_MAX ( moo_liw_t ) ) goto adjust_quotient ;
}
2019-04-08 04:00:47 +00:00
2019-04-05 07:33:27 +00:00
/* ---------------------------------------------------------- */
2019-04-02 18:56:25 +00:00
b = calculate_remainder ( moo , q , r , quo , i - ys , ys ) ;
2019-04-08 17:46:10 +00:00
2019-04-06 05:06:11 +00:00
b = ( moo_liw_t ) ( ( ( ( moo_lidw_t ) xhi - b ) > > MOO_LIW_BITS ) & 1 ) ; /* is the sign bit set? */
2019-04-02 08:49:41 +00:00
if ( b )
{
2019-04-06 05:06:11 +00:00
/* yes. underflow */
2019-04-08 04:00:47 +00:00
moo_lidw_t dw ;
moo_liw_t carry ;
moo_oow_t j , k ;
for ( carry = 0 , j = i - ys , k = 0 ; k < ys ; j + + , k + + )
{
dw = ( moo_lidw_t ) q [ j ] + r [ k ] + carry ;
carry = ( moo_liw_t ) ( dw > > MOO_LIW_BITS ) ;
q [ j ] = ( moo_liw_t ) dw ;
}
MOO_ASSERT ( moo , carry = = 1 ) ;
2019-04-02 08:49:41 +00:00
q [ i ] = quo - 1 ;
}
else
{
q [ i ] = quo ;
}
2019-04-01 08:45:21 +00:00
}
2019-04-02 08:49:41 +00:00
2019-04-02 18:56:25 +00:00
if ( d > 1 )
2019-04-01 08:45:21 +00:00
{
moo_lidw_t dw ;
2019-04-02 18:56:25 +00:00
moo_liw_t carry ;
for ( carry = 0 , i = ys ; i > 0 ; )
2019-04-01 08:45:21 +00:00
{
- - i ;
2019-04-02 18:56:25 +00:00
dw = ( ( moo_lidw_t ) carry < < MOO_LIW_BITS ) + q [ i ] ;
2019-04-01 08:45:21 +00:00
/* TODO: optimize it with ASM - no seperate / and % */
2019-04-02 18:56:25 +00:00
q [ i ] = ( moo_liw_t ) ( dw / d ) ;
2019-04-03 19:19:09 +00:00
carry = ( moo_liw_t ) ( dw % d ) ;
2019-04-01 08:45:21 +00:00
}
2019-03-29 07:05:53 +00:00
}
2019-04-02 08:49:41 +00:00
2019-04-03 19:19:09 +00:00
/* split quotient and remainder held in q to q and r respectively
* q [ < - - - quotient - - - - > | < - - remainder - - > ]
* index | xs xs - 1 . . . ys + 1 ys | ys - 1 ys - 2 . . . 1 0 |
*/
for ( i = 0 ; i < ys ; i + + ) { r [ i ] = q [ i ] ; q [ i ] = 0 ; }
for ( ; i < = xs ; i + + ) { q [ i - ys ] = q [ i ] ; q [ i ] = 0 ; }
2019-04-08 09:10:02 +00:00
2019-04-04 09:30:24 +00:00
}
static void divide_unsigned_array3 ( moo_t * moo , const moo_liw_t * x , moo_oow_t xs , const moo_liw_t * y , moo_oow_t ys , moo_liw_t * q , moo_liw_t * r )
{
2019-04-08 04:00:47 +00:00
moo_oow_t s , i , j , g , k ;
2019-04-05 07:33:27 +00:00
moo_lidw_t dw , qhat , rhat ;
2019-04-08 04:00:47 +00:00
moo_lidi_t di , ci ;
2019-04-06 05:06:11 +00:00
moo_liw_t * qq , y1 , y2 ;
2019-04-04 09:30:24 +00:00
/* the caller must ensure:
* - q can hold ' xs + 1 ' words and r can hold ' ys ' words .
* - q and r are set to all zeros . */
MOO_ASSERT ( moo , xs > = ys ) ;
if ( ys = = 1 )
{
/* the divisor has a single word only. perform simple division */
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
for ( i = xs ; i > 0 ; )
{
- - i ;
dw = ( ( moo_lidw_t ) carry < < MOO_LIW_BITS ) + x [ i ] ;
q [ i ] = ( moo_liw_t ) ( dw / y [ 0 ] ) ;
carry = ( moo_liw_t ) ( dw % y [ 0 ] ) ;
}
r [ 0 ] = carry ;
return ;
}
2019-04-09 04:40:51 +00:00
# define SHARED_QQ
# if defined(SHARED_QQ)
/* as long as q is 2 words longer than x, this algorithm can store
* both quotient and remainder in q at the same time . */
qq = q ;
# else
/* this part requires an extra buffer. proper error handling isn't easy
* since the return type of this function is void */
2019-04-05 02:04:08 +00:00
if ( moo - > inttostr . t . capa < = xs )
{
moo_liw_t * t ;
moo_oow_t reqcapa ;
reqcapa = MOO_ALIGN_POW2 ( xs + 1 , 32 ) ;
t = ( moo_liw_t * ) moo_reallocmem ( moo , moo - > inttostr . t . ptr , reqcapa * MOO_SIZEOF ( * t ) ) ;
2019-04-09 04:40:51 +00:00
/* TODO: TODO: TODO: ERROR HANDLING
2019-04-08 04:00:47 +00:00
if ( ! t ) return - 1 ; */
2019-04-05 02:04:08 +00:00
moo - > inttostr . t . capa = xs + 1 ;
moo - > inttostr . t . ptr = t ;
}
qq = moo - > inttostr . t . ptr ;
2019-04-09 04:40:51 +00:00
# endif
2019-04-05 02:04:08 +00:00
2019-04-07 11:23:24 +00:00
y1 = y [ ys - 1 ] ;
2019-05-04 04:27:27 +00:00
/*s = MOO_LIW_BITS - ((y1 == 0)? -1: moo_get_pos_of_msb_set(y1)) - 1;*/
2019-04-07 11:23:24 +00:00
MOO_ASSERT ( moo , y1 > 0 ) ; /* the highest word can't be non-zero in the context where this function is called */
2019-05-04 04:27:27 +00:00
s = MOO_LIW_BITS - moo_get_pos_of_msb_set ( y1 ) - 1 ;
2019-04-04 09:30:24 +00:00
for ( i = ys ; i > 1 ; )
{
- - i ;
r [ i ] = ( y [ i ] < < s ) | ( ( moo_lidw_t ) y [ i - 1 ] > > ( MOO_LIW_BITS - s ) ) ;
}
r [ 0 ] = y [ 0 ] < < s ;
2019-04-05 02:04:08 +00:00
qq [ xs ] = ( moo_lidw_t ) x [ xs - 1 ] > > ( MOO_LIW_BITS - s ) ;
2019-04-04 09:30:24 +00:00
for ( i = xs ; i > 1 ; )
{
- - i ;
2019-04-05 02:04:08 +00:00
qq [ i ] = ( x [ i ] < < s ) | ( ( moo_lidw_t ) x [ i - 1 ] > > ( MOO_LIW_BITS - s ) ) ;
2019-04-04 09:30:24 +00:00
}
2019-04-05 02:04:08 +00:00
qq [ 0 ] = x [ 0 ] < < s ;
2019-04-06 05:06:11 +00:00
y1 = r [ ys - 1 ] ;
y2 = r [ ys - 2 ] ;
for ( j = xs ; j > = ys ; - - j )
{
g = j - ys ; /* position where remainder begins in qq */
2019-04-04 09:30:24 +00:00
2019-04-05 07:33:27 +00:00
/* estimate */
2019-04-06 05:06:11 +00:00
dw = ( ( moo_lidw_t ) qq [ j ] < < MOO_LIW_BITS ) + qq [ j - 1 ] ;
qhat = dw / y1 ;
rhat = dw - ( qhat * y1 ) ;
2019-04-04 09:30:24 +00:00
2019-04-05 07:33:27 +00:00
adjust_quotient :
2019-04-06 05:06:11 +00:00
if ( qhat > MOO_TYPE_MAX ( moo_liw_t ) | | ( qhat * y2 ) > ( ( rhat < < MOO_LIW_BITS ) + qq [ j - 2 ] ) )
2019-04-04 09:30:24 +00:00
{
qhat = qhat - 1 ;
2019-04-06 05:06:11 +00:00
rhat = rhat + y1 ;
2019-04-05 07:33:27 +00:00
if ( rhat < = MOO_TYPE_MAX ( moo_liw_t ) ) goto adjust_quotient ;
2019-04-04 09:30:24 +00:00
}
2019-04-05 07:33:27 +00:00
/* multiply and subtract */
2019-04-09 04:40:51 +00:00
for ( ci = 0 , i = g , k = 0 ; k < ys ; i + + , k + + )
2019-04-04 09:30:24 +00:00
{
2019-04-08 04:00:47 +00:00
dw = qhat * r [ k ] ;
di = qq [ i ] - ci - ( dw & MOO_TYPE_MAX ( moo_liw_t ) ) ;
ci = ( dw > > MOO_LIW_BITS ) - ( di > > MOO_LIW_BITS ) ;
2019-04-08 09:10:02 +00:00
qq [ i ] = ( moo_liw_t ) di ;
2019-04-04 09:30:24 +00:00
}
2019-04-08 04:00:47 +00:00
MOO_ASSERT ( moo , i = = j ) ;
2019-04-09 04:40:51 +00:00
di = qq [ i ] - ci ;
qq [ i ] = di ;
2019-04-04 09:30:24 +00:00
2019-04-05 07:33:27 +00:00
/* test remainder */
2019-04-08 04:00:47 +00:00
if ( di < 0 )
2019-04-04 09:30:24 +00:00
{
2019-04-09 04:40:51 +00:00
for ( ci = 0 , i = g , k = 0 ; k < ys ; i + + , k + + )
2019-04-04 09:30:24 +00:00
{
2019-04-08 04:00:47 +00:00
di = ( moo_lidw_t ) qq [ i ] + r [ k ] + ci ;
ci = ( moo_liw_t ) ( di > > MOO_LIW_BITS ) ;
qq [ i ] = ( moo_liw_t ) di ;
2019-04-04 09:30:24 +00:00
}
2019-04-08 04:00:47 +00:00
MOO_ASSERT ( moo , i = = j ) ;
/*MOO_ASSERT (moo, ci == 1);*/
2019-04-09 04:40:51 +00:00
qq [ i ] + = ci ;
# if defined(SHARED_QQ)
/* store the quotient word right after the remainder in q */
q [ i + 1 ] = qhat - 1 ;
# else
2019-04-08 04:00:47 +00:00
q [ g ] = qhat - 1 ;
2019-04-09 04:40:51 +00:00
# endif
2019-04-08 04:00:47 +00:00
}
else
{
2019-04-09 04:40:51 +00:00
# if defined(SHARED_QQ)
/* store the quotient word right after the remainder in q */
q [ i + 1 ] = qhat ;
# else
2019-04-08 04:00:47 +00:00
q [ g ] = qhat ;
2019-04-09 04:40:51 +00:00
# endif
2019-04-04 09:30:24 +00:00
}
}
for ( i = 0 ; i < ys - 1 ; i + + )
{
2019-04-05 02:04:08 +00:00
r [ i ] = ( qq [ i ] > > s ) | ( ( moo_lidw_t ) qq [ i + 1 ] < < ( MOO_LIW_BITS - s ) ) ;
2019-04-04 09:30:24 +00:00
}
2019-04-05 02:04:08 +00:00
r [ i ] = qq [ i ] > > s ;
2019-04-09 04:40:51 +00:00
# if defined(SHARED_QQ)
for ( i = 0 ; i < = ys ; i + + ) { q [ i ] = 0 ; }
for ( ; i < = xs + 1 ; i + + ) { q [ i - ys - 1 ] = q [ i ] ; q [ i ] = 0 ; }
2019-03-29 07:05:53 +00:00
# endif
2019-04-09 04:40:51 +00:00
}
2019-04-02 08:49:41 +00:00
/* ======================================================================== */
2017-01-09 09:54:49 +00:00
static moo_oop_t add_unsigned_integers ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oow_t as , bs , zs ;
moo_oop_t z ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
as = MOO_OBJ_GET_SIZE ( x ) ;
bs = MOO_OBJ_GET_SIZE ( y ) ;
2015-12-21 17:12:57 +00:00
zs = ( as > = bs ? as : bs ) ;
2017-01-09 09:54:49 +00:00
if ( zs > = MOO_OBJ_SIZE_MAX )
2015-12-21 17:12:57 +00:00
{
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TOOD: is it a soft failure or hard failure? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
zs + + ;
2015-10-29 15:24:46 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , MOO_OBJ_GET_CLASS ( x ) , MOO_NULL , zs ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-10-29 15:24:46 +00:00
2016-11-09 15:50:18 +00:00
add_unsigned_array (
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , as ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , bs ,
MOO_OBJ_GET_LIWORD_SLOT ( z )
2016-11-09 15:50:18 +00:00
) ;
2015-10-29 15:24:46 +00:00
return z ;
}
2017-01-09 09:54:49 +00:00
static moo_oop_t subtract_unsigned_integers ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ! is_less_unsigned ( x , y ) ) ;
2015-10-30 15:36:37 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( x ) ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
subtract_unsigned_array ( moo ,
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ,
MOO_OBJ_GET_LIWORD_SLOT ( z ) ) ;
2015-11-11 13:31:05 +00:00
return z ;
}
2017-01-09 09:54:49 +00:00
static moo_oop_t multiply_unsigned_integers ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t xs , ys ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
ys = MOO_OBJ_GET_SIZE ( y ) ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
if ( ys > MOO_OBJ_SIZE_MAX - xs )
2015-12-21 17:12:57 +00:00
{
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TOOD: is it a soft failure or hard failure? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
2015-11-11 13:31:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , xs + ys ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-11-11 13:31:05 +00:00
2017-12-16 16:24:21 +00:00
# if defined(MOO_ENABLE_KARATSUBA)
2019-04-05 07:33:27 +00:00
if ( CANNOT_KARATSUBA ( moo , xs , ys ) )
2016-11-09 15:50:18 +00:00
{
# endif
multiply_unsigned_array (
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ,
MOO_OBJ_GET_LIWORD_SLOT ( z ) ) ;
2017-12-16 16:24:21 +00:00
# if defined(MOO_ENABLE_KARATSUBA)
2016-11-09 15:50:18 +00:00
}
else
{
if ( multiply_unsigned_array_karatsuba (
2017-01-09 09:54:49 +00:00
moo ,
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ,
MOO_OBJ_GET_LIWORD_SLOT ( z ) ) = = 0 ) return MOO_NULL ;
2016-11-09 15:50:18 +00:00
}
# endif
2015-10-29 15:24:46 +00:00
return z ;
}
2017-01-09 09:54:49 +00:00
static moo_oop_t divide_unsigned_integers ( moo_t * moo , moo_oop_t x , moo_oop_t y , moo_oop_t * r )
2015-11-30 14:29:57 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t qq , rr ;
2015-11-30 14:29:57 +00:00
2019-02-20 17:40:34 +00:00
if ( is_less_unsigned ( x , y ) )
{
rr = clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
if ( ! rr ) return MOO_NULL ;
moo_pushvolat ( moo , & rr ) ;
qq = make_bigint_with_ooi ( moo , 0 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
moo_popvolat ( moo ) ;
if ( qq ) * r = rr ;
return qq ;
}
else if ( is_equal_unsigned ( x , y ) )
{
rr = make_bigint_with_ooi ( moo , 0 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
if ( ! rr ) return MOO_NULL ;
moo_pushvolat ( moo , & rr ) ;
qq = make_bigint_with_ooi ( moo , 1 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
moo_popvolat ( moo ) ;
if ( qq ) * r = rr ;
return qq ;
}
2015-11-30 14:29:57 +00:00
/* the caller must ensure that x >= y */
2019-02-20 17:40:34 +00:00
MOO_ASSERT ( moo , ! is_less_unsigned ( x , y ) ) ;
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2019-04-09 04:40:51 +00:00
2019-04-05 07:33:27 +00:00
# define USE_DIVIDE_UNSIGNED_ARRAY2
2019-04-08 04:00:47 +00:00
/*#define USE_DIVIDE_UNSIGNED_ARRAY3*/
2019-04-07 11:23:24 +00:00
2019-04-09 04:40:51 +00:00
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
qq = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( x ) + 2 ) ;
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
2019-04-02 08:49:41 +00:00
qq = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( x ) + 1 ) ;
# else
2018-12-08 15:35:26 +00:00
qq = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( x ) ) ;
2019-04-02 08:49:41 +00:00
# endif
2015-12-07 09:40:45 +00:00
if ( ! qq )
{
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-07 09:40:45 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & qq ) ;
2019-04-09 04:40:51 +00:00
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
rr = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( y ) ) ;
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
2019-04-03 19:19:09 +00:00
rr = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( y ) ) ;
# else
rr = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , MOO_OBJ_GET_SIZE ( y ) + 1 ) ;
# endif
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 3 ) ;
2017-01-09 09:54:49 +00:00
if ( ! rr ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
2019-04-09 04:40:51 +00:00
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
2019-04-07 11:23:24 +00:00
divide_unsigned_array3 ( moo ,
2019-04-09 04:40:51 +00:00
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
divide_unsigned_array2 ( moo ,
2019-04-02 08:49:41 +00:00
# else
2017-01-09 09:54:49 +00:00
divide_unsigned_array ( moo ,
2019-04-02 08:49:41 +00:00
# endif
2018-12-16 17:35:46 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( x ) , MOO_OBJ_GET_SIZE ( x ) ,
MOO_OBJ_GET_LIWORD_SLOT ( y ) , MOO_OBJ_GET_SIZE ( y ) ,
2019-04-07 11:23:24 +00:00
MOO_OBJ_GET_LIWORD_SLOT ( qq ) , MOO_OBJ_GET_LIWORD_SLOT ( rr )
) ;
2015-11-30 14:29:57 +00:00
2015-11-30 15:17:41 +00:00
* r = rr ;
2015-11-30 14:29:57 +00:00
return qq ;
}
2019-04-02 08:49:41 +00:00
/* ======================================================================== */
2017-01-09 09:54:49 +00:00
moo_oop_t moo_addints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t i ;
2015-11-12 06:57:35 +00:00
2015-10-30 15:36:37 +00:00
/* no integer overflow/underflow must occur as the possible integer
* range is narrowed by the tag bits used */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_SMOOI_MAX + MOO_SMOOI_MAX < MOO_TYPE_MAX ( moo_ooi_t ) ) ;
MOO_ASSERT ( moo , MOO_SMOOI_MIN + MOO_SMOOI_MIN > MOO_TYPE_MIN ( moo_ooi_t ) ) ;
2015-11-12 06:57:35 +00:00
2017-01-09 09:54:49 +00:00
i = MOO_OOP_TO_SMOOI ( x ) + MOO_OOP_TO_SMOOI ( y ) ;
if ( MOO_IN_SMOOI_RANGE ( i ) ) return MOO_SMOOI_TO_OOP ( i ) ;
2015-10-30 15:36:37 +00:00
2018-12-21 16:25:25 +00:00
return make_bigint_with_ooi ( moo , i ) ;
2015-10-29 15:24:46 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-10-30 15:36:37 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2019-02-20 17:40:34 +00:00
if ( v = = 0 ) return clone_bigint ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-10-30 15:36:37 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2018-12-21 16:25:25 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-10-30 15:36:37 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
2019-02-20 17:40:34 +00:00
if ( v = = 0 ) return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-10-30 15:36:37 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2018-12-21 16:25:25 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2015-10-30 15:36:37 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( x ) ! = MOO_OBJ_GET_CLASS ( y ) )
2015-10-30 15:36:37 +00:00
{
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , x ) )
2015-10-30 15:36:37 +00:00
{
/* x is negative, y is positive */
2018-12-21 16:25:25 +00:00
if ( is_less_unsigned ( x , y ) )
2015-11-30 14:29:57 +00:00
{
2018-12-21 16:25:25 +00:00
z = subtract_unsigned_integers ( moo , y , x ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
}
else
{
2018-12-21 16:25:25 +00:00
z = subtract_unsigned_integers ( moo , x , y ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-11-30 14:29:57 +00:00
}
2015-10-30 15:36:37 +00:00
}
else
{
/* x is positive, y is negative */
2018-12-21 16:25:25 +00:00
if ( is_less_unsigned ( x , y ) )
2015-11-30 14:29:57 +00:00
{
2018-12-21 16:25:25 +00:00
z = subtract_unsigned_integers ( moo , y , x ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-11-30 14:29:57 +00:00
}
else
{
2018-12-21 16:25:25 +00:00
z = subtract_unsigned_integers ( moo , x , y ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
}
2015-10-30 15:36:37 +00:00
}
}
else
{
2015-11-12 06:57:35 +00:00
int neg ;
2015-10-30 15:36:37 +00:00
/* both are positive or negative */
2018-12-21 16:25:25 +00:00
neg = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
z = add_unsigned_integers ( moo , x , y ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( neg ) MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-10-30 15:36:37 +00:00
}
2015-10-29 15:24:46 +00:00
}
2018-12-21 16:25:25 +00:00
return normalize_bigint ( moo , z ) ;
2015-10-30 15:36:37 +00:00
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-10-29 15:24:46 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_subints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
2015-10-29 15:24:46 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-10-29 15:24:46 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t i ;
2015-11-12 06:57:35 +00:00
2015-10-30 15:36:37 +00:00
/* no integer overflow/underflow must occur as the possible integer
* range is narrowed by the tag bits used */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_SMOOI_MAX - MOO_SMOOI_MIN < MOO_TYPE_MAX ( moo_ooi_t ) ) ;
MOO_ASSERT ( moo , MOO_SMOOI_MIN - MOO_SMOOI_MAX > MOO_TYPE_MIN ( moo_ooi_t ) ) ;
2015-11-12 06:57:35 +00:00
2017-01-09 09:54:49 +00:00
i = MOO_OOP_TO_SMOOI ( x ) - MOO_OOP_TO_SMOOI ( y ) ;
if ( MOO_IN_SMOOI_RANGE ( i ) ) return MOO_SMOOI_TO_OOP ( i ) ;
2015-10-30 15:36:37 +00:00
2018-12-27 15:46:19 +00:00
return make_bigint_with_ooi ( moo , i ) ;
2015-10-29 15:24:46 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-10-30 15:36:37 +00:00
int neg ;
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-10-29 15:24:46 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2015-10-30 15:36:37 +00:00
if ( v = = 0 )
{
/* switch the sign to the opposite and return it */
2018-12-27 15:46:19 +00:00
return clone_bigint_negated ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-10-30 15:36:37 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2018-12-27 15:46:19 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-10-30 15:36:37 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
2018-12-27 15:46:19 +00:00
if ( v = = 0 ) return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-10-30 15:36:37 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2018-12-27 15:46:19 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! y ) ) return MOO_NULL ;
2015-10-30 15:36:37 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-10-30 15:36:37 +00:00
}
2017-01-09 09:54:49 +00:00
if ( MOO_OBJ_GET_CLASS ( x ) ! = MOO_OBJ_GET_CLASS ( y ) )
2015-10-30 15:36:37 +00:00
{
2018-12-21 16:25:25 +00:00
neg = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
2018-12-27 15:46:19 +00:00
z = add_unsigned_integers ( moo , x , y ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( neg ) MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-10-29 15:24:46 +00:00
}
else
{
2015-10-30 15:36:37 +00:00
/* both are positive or negative */
if ( is_less_unsigned ( x , y ) )
{
2018-12-21 16:25:25 +00:00
neg = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
2017-01-09 09:54:49 +00:00
z = subtract_unsigned_integers ( moo , y , x ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( ! neg ) MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-10-30 15:36:37 +00:00
}
else
{
2018-12-21 16:25:25 +00:00
neg = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
2017-01-09 09:54:49 +00:00
z = subtract_unsigned_integers ( moo , x , y ) ; /* take x's sign */
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( neg ) MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-10-30 15:36:37 +00:00
}
2015-10-29 15:24:46 +00:00
}
}
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-10-30 15:36:37 +00:00
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-10-29 15:24:46 +00:00
}
2015-10-30 15:36:37 +00:00
2017-01-09 09:54:49 +00:00
moo_oop_t moo_mulints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-11-11 13:31:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-11-11 13:31:05 +00:00
{
2019-04-01 08:45:21 +00:00
# if (MOO_SIZEOF_INTMAX_T > MOO_SIZEOF_OOI_T)
2017-01-09 09:54:49 +00:00
moo_intmax_t i ;
i = ( moo_intmax_t ) MOO_OOP_TO_SMOOI ( x ) * ( moo_intmax_t ) MOO_OOP_TO_SMOOI ( y ) ;
if ( MOO_IN_SMOOI_RANGE ( i ) ) return MOO_SMOOI_TO_OOP ( ( moo_ooi_t ) i ) ;
2018-12-27 15:46:19 +00:00
return make_bigint_with_intmax ( moo , i ) ;
2015-11-12 06:57:35 +00:00
# else
2017-01-09 09:54:49 +00:00
moo_ooi_t i ;
moo_ooi_t xv , yv ;
2015-11-13 15:55:56 +00:00
2017-01-09 09:54:49 +00:00
xv = MOO_OOP_TO_SMOOI ( x ) ;
yv = MOO_OOP_TO_SMOOI ( y ) ;
2018-12-27 15:46:19 +00:00
if ( smooi_mul_overflow ( moo , xv , yv , & i ) )
2015-11-13 15:55:56 +00:00
{
2015-11-16 09:53:31 +00:00
/* overflowed - convert x and y normal objects and carry on */
2018-12-28 08:29:27 +00:00
/* no need to call moo_pushvolat before creating x because
2015-11-16 09:53:31 +00:00
* xv and yv contains actual values needed */
2017-01-09 09:54:49 +00:00
x = make_bigint_with_ooi ( moo , xv ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-11-16 09:53:31 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ; /* protect x made above */
2018-12-27 15:46:19 +00:00
y = make_bigint_with_ooi ( moo , yv ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! y ) ) return MOO_NULL ;
2015-11-16 09:53:31 +00:00
2019-04-01 08:45:21 +00:00
goto full_multiply ;
2015-11-13 15:55:56 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( i ) ) return MOO_SMOOI_TO_OOP ( i ) ;
2018-12-27 15:46:19 +00:00
return make_bigint_with_ooi ( moo , i ) ;
2015-11-13 15:55:56 +00:00
}
2015-11-12 06:57:35 +00:00
# endif
2015-11-11 13:31:05 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2018-12-28 08:29:27 +00:00
int neg ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-11-11 13:31:05 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2015-11-12 06:57:35 +00:00
switch ( v )
{
case 0 :
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-11-12 06:57:35 +00:00
case 1 :
2018-12-27 15:46:19 +00:00
return clone_bigint ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-11-12 06:57:35 +00:00
case - 1 :
2018-12-27 15:46:19 +00:00
return clone_bigint_negated ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-11-12 06:57:35 +00:00
}
2015-11-11 13:31:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2018-12-27 15:46:19 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-11-11 13:31:05 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-11-11 13:31:05 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-11-11 13:31:05 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
2015-11-12 06:57:35 +00:00
switch ( v )
{
case 0 :
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-11-12 06:57:35 +00:00
case 1 :
2018-12-27 15:46:19 +00:00
return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-11-12 06:57:35 +00:00
case - 1 :
2018-12-27 15:46:19 +00:00
return clone_bigint_negated ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-11-12 06:57:35 +00:00
}
2015-11-11 13:31:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2017-01-09 09:54:49 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2015-11-11 13:31:05 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-11-11 13:31:05 +00:00
}
2019-04-01 08:45:21 +00:00
full_multiply :
2018-12-28 08:29:27 +00:00
neg = ( MOO_OBJ_GET_CLASS ( x ) ! = MOO_OBJ_GET_CLASS ( y ) ) ; /* checking sign before multication. no need to preserve x and y */
z = multiply_unsigned_integers ( moo , x , y ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2018-12-28 08:29:27 +00:00
if ( neg ) MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-11-11 13:31:05 +00:00
}
2018-12-28 08:29:27 +00:00
return normalize_bigint ( moo , z ) ;
2015-11-11 13:31:05 +00:00
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-11 13:31:05 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_divints ( moo_t * moo , moo_oop_t x , moo_oop_t y , int modulo , moo_oop_t * rem )
2015-11-17 14:13:59 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z , r ;
2019-03-30 13:43:10 +00:00
int x_neg_sign , y_neg_sign ;
2015-11-20 09:05:55 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-11-20 09:05:55 +00:00
{
2019-03-24 18:49:16 +00:00
moo_ooi_t xv , yv , q , ri ;
2015-11-20 09:05:55 +00:00
2017-01-09 09:54:49 +00:00
xv = MOO_OOP_TO_SMOOI ( x ) ;
yv = MOO_OOP_TO_SMOOI ( y ) ;
2015-11-20 09:05:55 +00:00
if ( yv = = 0 )
{
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EDIVBY0 ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-20 09:05:55 +00:00
}
2015-12-01 12:13:40 +00:00
if ( xv = = 0 )
{
2017-01-09 09:54:49 +00:00
if ( rem ) * rem = MOO_SMOOI_TO_OOP ( 0 ) ;
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-01 12:13:40 +00:00
}
2015-11-22 15:04:48 +00:00
/* In C89, integer division with a negative number is
* implementation dependent . In C99 , it truncates towards zero .
*
* http : //python-history.blogspot.kr/2010/08/why-pythons-integer-division-floors.html
* The integer division operation ( //) and its sibling,
* the modulo operation ( % ) , go together and satisfy a nice
* mathematical relationship ( all variables are integers ) :
* a / b = q with remainder r
* such that
2015-11-30 15:17:41 +00:00
* b * q + r = a and 0 < = r < b ( assuming - a and b are > = 0 ) .
2015-11-22 15:04:48 +00:00
*
* If you want the relationship to extend for negative a
* ( keeping b positive ) , you have two choices : if you truncate q
* towards zero , r will become negative , so that the invariant
* changes to 0 < = abs ( r ) < abs ( b ) . otherwise , you can floor q
* towards negative infinity , and the invariant remains 0 < = r < b .
*/
2015-11-20 09:05:55 +00:00
q = xv / yv ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( q ) ) ;
2015-11-20 09:05:55 +00:00
2019-03-24 18:49:16 +00:00
ri = xv - yv * q ; /* xv % yv; */
if ( ri )
2015-11-22 14:48:09 +00:00
{
2015-11-30 15:17:41 +00:00
if ( modulo )
2015-11-22 14:48:09 +00:00
{
2015-11-30 15:17:41 +00:00
/* modulo */
/*
xv yv q r
- - - - - - - - - - - - - - - - - - - - - - - - -
7 3 2 1
- 7 3 - 3 2
7 - 3 - 3 - 2
- 7 - 3 2 - 1
*/
/* r must be floored. that is, it rounds away from zero
* and towards negative infinity */
2019-03-24 18:49:16 +00:00
if ( IS_SIGN_DIFF ( yv , ri ) )
2015-11-30 15:17:41 +00:00
{
/* if the divisor has a different sign from r,
* change the sign of r to the divisor ' s sign */
2019-03-24 18:49:16 +00:00
ri + = yv ;
2015-11-30 15:17:41 +00:00
- - q ;
2019-03-24 18:49:16 +00:00
MOO_ASSERT ( moo , ri & & ! IS_SIGN_DIFF ( yv , ri ) ) ;
2015-11-30 15:17:41 +00:00
}
2015-11-22 14:48:09 +00:00
}
2015-11-30 15:17:41 +00:00
else
2015-11-22 14:48:09 +00:00
{
2015-11-30 15:17:41 +00:00
/* remainder */
/*
xv yv q r
- - - - - - - - - - - - - - - - - - - - - - - - -
7 3 2 1
- 7 3 - 2 - 1
7 - 3 - 2 1
- 7 - 3 2 - 1
*/
2019-03-24 18:49:16 +00:00
if ( xv & & IS_SIGN_DIFF ( xv , ri ) )
2015-11-30 15:17:41 +00:00
{
/* if the dividend has a different sign from r,
2015-12-01 12:13:40 +00:00
* change the sign of r to the dividend ' s sign .
* all the compilers i ' ve worked with produced
* the quotient and the remainder that don ' t need
* any adjustment . however , there may be an esoteric
* architecture . */
2019-03-24 18:49:16 +00:00
ri - = yv ;
2015-11-30 15:17:41 +00:00
+ + q ;
2019-03-24 18:49:16 +00:00
MOO_ASSERT ( moo , xv & & ! IS_SIGN_DIFF ( xv , ri ) ) ;
2015-11-30 15:17:41 +00:00
}
2015-11-22 14:48:09 +00:00
}
}
2015-11-22 13:32:06 +00:00
if ( rem )
2015-11-20 09:05:55 +00:00
{
2019-03-24 18:49:16 +00:00
MOO_ASSERT ( moo , MOO_IN_SMOOI_RANGE ( ri ) ) ;
* rem = MOO_SMOOI_TO_OOP ( ri ) ;
2015-11-20 09:05:55 +00:00
}
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( ( moo_ooi_t ) q ) ;
2015-11-20 09:05:55 +00:00
}
2015-12-02 15:24:13 +00:00
else
2015-11-20 09:05:55 +00:00
{
2019-03-24 18:49:16 +00:00
moo_oop_t r ;
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-11-20 09:05:55 +00:00
{
2019-03-30 13:43:10 +00:00
moo_ooi_t xv ;
2015-11-30 14:29:57 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-11-30 14:29:57 +00:00
2019-04-01 08:45:21 +00:00
/* divide a small integer by a big integer.
* the dividend is guaranteed to be greater than the divisor
* if both are positive . */
2019-03-30 13:43:10 +00:00
xv = MOO_OOP_TO_SMOOI ( x ) ;
x_neg_sign = ( xv < 0 ) ;
y_neg_sign = MOO_POINTER_IS_NBIGINT ( moo , y ) ;
if ( x_neg_sign = = y_neg_sign | | ! modulo )
2015-12-02 15:24:13 +00:00
{
2019-04-01 08:45:21 +00:00
/* simple. the quotient is zero and the
* dividend becomes the remainder as a whole . */
2019-03-30 13:43:10 +00:00
if ( rem ) * rem = x ;
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-02 15:24:13 +00:00
}
2019-04-01 08:45:21 +00:00
/* carry on to the full bigint division */
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-03-30 13:43:10 +00:00
x = make_bigint_with_ooi ( moo , xv ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-02 15:24:13 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-11-20 09:05:55 +00:00
{
2019-03-24 18:49:16 +00:00
moo_ooi_t yv ;
2015-11-22 13:32:06 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-11-30 14:29:57 +00:00
2019-04-01 08:45:21 +00:00
/* divide a big integer by a small integer. */
2019-03-24 18:49:16 +00:00
yv = MOO_OOP_TO_SMOOI ( y ) ;
switch ( yv )
2015-12-02 15:24:13 +00:00
{
2019-03-22 08:06:14 +00:00
case 0 : /* divide by 0 */
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EDIVBY0 ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-30 14:29:57 +00:00
2019-03-22 08:06:14 +00:00
case 1 : /* divide by 1 */
2019-02-18 08:57:59 +00:00
z = clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( rem ) * rem = MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-02 15:24:13 +00:00
return z ;
2015-12-01 12:13:40 +00:00
2019-03-22 08:06:14 +00:00
case - 1 : /* divide by -1 */
2019-02-18 08:57:59 +00:00
z = clone_bigint_negated ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
if ( rem ) * rem = MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-02 15:24:13 +00:00
return z ;
default :
2019-03-30 05:22:35 +00:00
{
moo_lidw_t dw ;
moo_liw_t carry = 0 ;
moo_liw_t * zw ;
moo_oow_t zs , i ;
2019-03-30 13:43:10 +00:00
moo_ooi_t yv_abs , ri ;
2019-03-30 05:22:35 +00:00
2019-03-30 13:43:10 +00:00
yv_abs = ( yv < 0 ) ? - yv : yv ;
2019-04-01 08:45:21 +00:00
# if (MOO_LIW_BITS < MOO_OOI_BITS)
if ( yv_abs > MOO_TYPE_MAX ( moo_liw_t ) ) break ;
# endif
2019-03-30 13:43:10 +00:00
x_neg_sign = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
y_neg_sign = ( yv < 0 ) ;
z = clone_bigint_to_positive ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-03-30 05:22:35 +00:00
zw = MOO_OBJ_GET_LIWORD_SLOT ( z ) ;
zs = MOO_OBJ_GET_SIZE ( z ) ;
for ( i = zs ; i > 0 ; )
{
- - i ;
dw = ( ( moo_lidw_t ) carry < < MOO_LIW_BITS ) + zw [ i ] ;
/* TODO: optimize it with ASM - no seperate / and % */
2019-04-03 19:19:09 +00:00
zw [ i ] = ( moo_liw_t ) ( dw / yv_abs ) ;
carry = ( moo_liw_t ) ( dw % yv_abs ) ;
2019-03-30 05:22:35 +00:00
}
2019-03-30 13:43:10 +00:00
/*if (zw[zs - 1] == 0) zs--;*/
2019-03-30 05:22:35 +00:00
2019-03-30 13:43:10 +00:00
MOO_ASSERT ( moo , carry < = MOO_SMOOI_MAX ) ;
ri = carry ;
if ( x_neg_sign ) ri = - ri ;
2019-03-24 18:49:16 +00:00
2019-03-30 13:43:10 +00:00
z = normalize_bigint ( moo , z ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-03-24 18:49:16 +00:00
2019-03-30 13:43:10 +00:00
if ( x_neg_sign ! = y_neg_sign )
2019-03-25 11:41:26 +00:00
{
2019-03-30 13:43:10 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
if ( ri & & modulo )
2019-03-24 18:49:16 +00:00
{
2019-03-30 13:43:10 +00:00
z = moo_subints ( moo , z , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-03-30 13:43:10 +00:00
if ( rem )
2019-03-25 11:41:26 +00:00
{
moo_pushvolat ( moo , & z ) ;
2019-03-30 13:43:10 +00:00
r = moo_addints ( moo , MOO_SMOOI_TO_OOP ( ri ) , MOO_SMOOI_TO_OOP ( yv ) ) ;
2019-03-25 11:41:26 +00:00
moo_popvolat ( moo ) ;
if ( ! r ) return MOO_NULL ;
* rem = r ;
}
return z ;
2019-03-24 18:49:16 +00:00
}
2015-12-02 15:24:13 +00:00
}
2019-03-30 13:43:10 +00:00
if ( rem ) * rem = MOO_SMOOI_TO_OOP ( ri ) ;
return z ;
}
2015-12-02 15:24:13 +00:00
}
2015-11-30 14:29:57 +00:00
2019-04-01 08:45:21 +00:00
/* carry on to the full bigint division */
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2019-03-24 18:49:16 +00:00
y = make_bigint_with_ooi ( moo , yv ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2015-12-02 15:24:13 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-02 15:24:13 +00:00
}
2015-11-20 09:05:55 +00:00
}
2019-03-30 13:43:10 +00:00
x_neg_sign = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
y_neg_sign = ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ;
2015-11-30 14:29:57 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2019-02-18 08:57:59 +00:00
z = divide_unsigned_integers ( moo , x , y , & r ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
2019-03-30 13:43:10 +00:00
if ( x_neg_sign )
2015-11-30 14:29:57 +00:00
{
2019-03-30 13:43:10 +00:00
2015-11-30 15:17:41 +00:00
/* the class on r must be set before normalize_bigint()
2015-12-01 12:13:40 +00:00
* because it can get changed to a small integer */
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( r , moo - > _large_negative_integer ) ;
2015-12-01 12:13:40 +00:00
}
2019-03-30 13:43:10 +00:00
if ( x_neg_sign ! = y_neg_sign )
2015-12-01 12:13:40 +00:00
{
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-11-30 15:17:41 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & z ) ;
moo_pushvolat ( moo , & y ) ;
2019-02-20 17:40:34 +00:00
r = normalize_bigint ( moo , r ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2017-01-09 09:54:49 +00:00
if ( ! r ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
2017-01-09 09:54:49 +00:00
if ( r ! = MOO_SMOOI_TO_OOP ( 0 ) & & modulo )
2015-11-30 14:29:57 +00:00
{
2015-11-30 15:17:41 +00:00
if ( rem )
2015-11-30 14:29:57 +00:00
{
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & z ) ;
moo_pushvolat ( moo , & y ) ;
2019-02-18 08:57:59 +00:00
r = moo_addints ( moo , r , y ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2017-01-09 09:54:49 +00:00
if ( ! r ) return MOO_NULL ;
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & r ) ;
2019-02-18 08:57:59 +00:00
z = normalize_bigint ( moo , z ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & r ) ;
2019-02-18 08:57:59 +00:00
z = moo_subints ( moo , z , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-11-30 15:17:41 +00:00
* rem = r ;
2015-11-30 14:29:57 +00:00
return z ;
}
2015-11-30 15:17:41 +00:00
else
{
/* remainder is not needed at all */
/* TODO: subtract 1 without normalization??? */
2019-02-20 17:40:34 +00:00
z = normalize_bigint ( moo , z ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2019-02-18 08:57:59 +00:00
return moo_subints ( moo , z , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2015-11-30 15:17:41 +00:00
}
2015-11-30 14:29:57 +00:00
}
}
2015-11-30 15:17:41 +00:00
else
2015-11-30 14:29:57 +00:00
{
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & z ) ;
2019-02-18 08:57:59 +00:00
r = normalize_bigint ( moo , r ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! r ) return MOO_NULL ;
2015-11-30 14:29:57 +00:00
}
2020-10-25 05:54:54 +00:00
moo_pushvolat ( moo , & r ) ;
z = normalize_bigint ( moo , z ) ;
moo_popvolat ( moo ) ;
if ( z & & rem ) * rem = r ;
return z ;
2015-12-02 15:24:13 +00:00
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-17 14:13:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_negateint ( moo_t * moo , moo_oop_t x )
2015-12-25 05:09:17 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-25 05:09:17 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
v = MOO_OOP_TO_SMOOI ( x ) ;
return MOO_SMOOI_TO_OOP ( - v ) ;
2015-12-25 05:09:17 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return clone_bigint_negated ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-12-25 05:09:17 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameter - %O " , x ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-25 05:09:17 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitatint ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-25 05:09:17 +00:00
{
2016-12-28 13:42:12 +00:00
/* y is 0-based */
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-25 05:09:17 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v1 , v2 , v3 ;
2015-12-26 01:37:33 +00:00
2017-01-09 09:54:49 +00:00
v1 = MOO_OOP_TO_SMOOI ( x ) ;
v2 = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-26 01:37:33 +00:00
2017-01-09 09:54:49 +00:00
if ( v2 < 0 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-26 01:37:33 +00:00
if ( v1 > = 0 )
{
2016-12-28 13:42:12 +00:00
/* the absolute value may be composed of up to
2017-01-09 09:54:49 +00:00
* MOO_SMOOI_BITS - 1 bits as there is a sign bit . */
if ( v2 > = MOO_SMOOI_BITS - 1 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
v3 = ( ( moo_oow_t ) v1 > > v2 ) & 1 ;
2015-12-26 01:37:33 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
if ( v2 > = MOO_SMOOI_BITS - 1 ) return MOO_SMOOI_TO_OOP ( 1 ) ;
v3 = ( ( ~ ( moo_oow_t ) - v1 + 1 ) > > v2 ) & 1 ;
2015-12-26 01:37:33 +00:00
}
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( v3 ) ;
2015-12-25 05:09:17 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-26 05:11:10 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-26 05:11:10 +00:00
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2016-12-28 13:42:12 +00:00
2017-01-09 09:54:49 +00:00
/* y is definitely >= MOO_SMOOI_BITS */
if ( MOO_OOP_TO_SMOOI ( x ) > = 0 )
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-26 05:11:10 +00:00
else
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( 1 ) ;
2015-12-26 05:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-26 05:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
moo_oow_t wp , bp , xs ;
2015-12-26 05:11:10 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
if ( v < 0 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
wp = v / MOO_LIW_BITS ;
bp = v - ( wp * MOO_LIW_BITS ) ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2015-12-26 05:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
if ( wp > = xs ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2019-08-11 14:58:04 +00:00
v = ( MOO_OBJ_GET_LIWORD_VAL ( x , wp ) > > bp ) & 1 ;
2015-12-26 05:11:10 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
moo_oow_t i ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
if ( wp > = xs ) return MOO_SMOOI_TO_OOP ( 1 ) ;
2015-12-26 05:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < = wp ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2015-12-26 05:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
v = ( ( moo_oow_t ) w > > bp ) & 1 ;
2015-12-26 05:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( v ) ;
2015-12-26 05:11:10 +00:00
}
2015-12-25 05:09:17 +00:00
else
{
2017-01-09 09:54:49 +00:00
# if defined(MOO_LIMIT_OBJ_SIZE)
2015-12-26 05:11:10 +00:00
/* nothing */
# else
2017-01-09 09:54:49 +00:00
moo_oow_t w , wp , bp , xs ;
moo_ooi_t v ;
2015-12-26 05:11:10 +00:00
int sign ;
# endif
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
# if defined(MOO_LIMIT_OBJ_SIZE)
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_SIZE_BITS_MAX < = MOO_TYPE_MAX ( moo_oow_t ) ) ;
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2015-12-26 05:11:10 +00:00
{
2019-08-10 16:20:44 +00:00
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-26 05:11:10 +00:00
}
else
{
2019-08-10 16:20:44 +00:00
return MOO_SMOOI_TO_OOP ( 1 ) ;
2015-12-26 05:11:10 +00:00
}
# else
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
2015-12-26 05:11:10 +00:00
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-26 05:11:10 +00:00
2019-11-01 09:15:53 +00:00
sign = bigint_to_oow_noseterr ( moo , y , & w ) ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign > = 0 ) ;
2015-12-26 05:11:10 +00:00
if ( sign > = 1 )
{
2017-01-09 09:54:49 +00:00
wp = w / MOO_LIW_BITS ;
bp = w - ( wp * MOO_LIW_BITS ) ;
2015-12-26 05:11:10 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_t quo , rem ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign = = 0 ) ;
2015-12-26 05:11:10 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2019-08-10 16:20:44 +00:00
quo = moo_divints ( moo , y , MOO_SMOOI_TO_OOP ( MOO_LIW_BITS ) , 0 , & rem ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! quo ) return MOO_NULL ;
2015-12-26 05:11:10 +00:00
2019-11-01 09:15:53 +00:00
sign = integer_to_oow_noseterr ( moo , quo , & wp ) ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign > = 0 ) ;
2015-12-26 05:11:10 +00:00
if ( sign = = 0 )
{
/* too large. set it to xs so that it gets out of
* the valid range */
wp = xs ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OOP_IS_SMOOI ( rem ) ) ;
bp = MOO_OOP_TO_SMOOI ( rem ) ;
MOO_ASSERT ( moo , bp > = 0 & & bp < MOO_LIW_BITS ) ;
2015-12-26 05:11:10 +00:00
}
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2015-12-26 05:11:10 +00:00
{
2017-01-09 09:54:49 +00:00
if ( wp > = xs ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2019-08-11 14:58:04 +00:00
v = ( MOO_OBJ_GET_LIWORD_SLOT ( x , wp ) > > bp ) & 1 ;
2015-12-26 05:11:10 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
moo_oow_t i ;
2015-12-26 05:11:10 +00:00
2017-01-09 09:54:49 +00:00
if ( wp > = xs ) return MOO_SMOOI_TO_OOP ( 1 ) ;
2015-12-26 05:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < = wp ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2015-12-26 05:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
v = ( ( moo_oow_t ) w > > bp ) & 1 ;
2015-12-26 05:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( v ) ;
2015-12-26 05:11:10 +00:00
# endif
2015-12-25 05:09:17 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-25 05:09:17 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitandints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-01 12:13:40 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v1 , v2 , v3 ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
v1 = MOO_OOP_TO_SMOOI ( x ) ;
v2 = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-17 16:11:10 +00:00
v3 = v1 & v2 ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( v3 ) ) return MOO_SMOOI_TO_OOP ( v3 ) ;
return make_bigint_with_ooi ( moo , v3 ) ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-10 14:23:09 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-10 14:23:09 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2020-10-25 05:54:54 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-17 16:11:10 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-10 14:23:09 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2017-01-09 09:54:49 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-10 14:23:09 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i , xs , ys , zs , zalloc ;
2015-12-17 16:11:10 +00:00
int negx , negy ;
2015-12-10 14:23:09 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
bigint_and_bigint :
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
ys = MOO_OBJ_GET_SIZE ( y ) ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
if ( xs < ys )
{
/* make sure that x is greater than or equal to y */
z = x ;
x = y ;
y = z ;
zs = ys ;
ys = xs ;
xs = zs ;
}
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
negy = ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? 1 : 0 ;
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
{
zalloc = xs + 1 ;
zs = xs ;
}
else if ( negx )
{
zalloc = ys ;
zs = ys ;
}
else if ( negy )
{
zalloc = xs ;
zs = xs ;
}
else
{
zalloc = ys ;
zs = ys ;
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , zalloc ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* both are negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w [ 2 ] ;
moo_lidw_t carry [ 2 ] ;
2015-12-17 16:11:10 +00:00
carry [ 0 ] = 1 ;
carry [ 1 ] = 1 ;
/* 2's complement on both x and y and perform bitwise-and */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
w [ 1 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry [ 1 ] ;
2017-01-09 09:54:49 +00:00
carry [ 1 ] = w [ 1 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] & ( moo_liw_t ) w [ 1 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 1 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* 2's complement on the remaining part of x. the lacking part
* in y is treated as if they are all 1 s . */
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 0 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* 2's complement on the final result */
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , zs , ~ ( moo_liw_t ) 0 ) ;
2015-12-17 16:11:10 +00:00
carry [ 0 ] = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 0 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-12-10 14:23:09 +00:00
}
2015-12-17 16:11:10 +00:00
else if ( negx )
{
/* x is negative, y is positive */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w & MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
/* the lacking part in y is all 0's. the remaining part in x is
* just masked out when bitwise - anded with 0. so nothing is done
* to handle the remaining part in x */
}
else if ( negy )
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* x is positive, y is negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-17 16:11:10 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) & ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* handle the longer part in x than y
*
* For example ,
* x = > + 1010 1100
* y = > - 0011
*
* If y is extended to the same length as x ,
* it is a negative 0000 0001.
* 2 ' s complement is performed on this imaginary extension .
* the result is ' 1111 1101 ' ( 1111 1100 + 1 ) .
*
* when y is shorter and negative , the lacking part can be
* treated as all 1 s in the 2 ' s complement format .
*
* the remaining part in x can be just copied to the
* final result ' z ' .
*/
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) ;
2015-12-17 16:11:10 +00:00
}
}
else
{
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) & MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
2015-12-10 14:23:09 +00:00
}
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-10 14:23:09 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-01 12:13:40 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitorints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-01 12:13:40 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v1 , v2 , v3 ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
v1 = MOO_OOP_TO_SMOOI ( x ) ;
v2 = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-17 16:11:10 +00:00
v3 = v1 | v2 ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( v3 ) ) return MOO_SMOOI_TO_OOP ( v3 ) ;
2019-10-26 14:34:19 +00:00
return make_bigint_with_ooi ( moo , v3 ) ;
2015-12-10 14:23:09 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-10 14:23:09 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-10 14:23:09 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-10 14:23:09 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return clone_bigint ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-12-10 14:23:09 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-08-10 16:20:44 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-13 16:08:05 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-13 16:08:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-17 16:11:10 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-12-13 16:08:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2019-08-10 16:20:44 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-13 16:08:05 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i , xs , ys , zs , zalloc ;
2015-12-17 16:11:10 +00:00
int negx , negy ;
2015-12-13 16:08:05 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
bigint_and_bigint :
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
ys = MOO_OBJ_GET_SIZE ( y ) ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
if ( xs < ys )
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* make sure that x is greater than or equal to y */
2015-12-10 14:23:09 +00:00
z = x ;
x = y ;
y = z ;
zs = ys ;
ys = xs ;
xs = zs ;
}
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
negy = ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? 1 : 0 ;
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
{
zalloc = ys + 1 ;
zs = ys ;
}
else if ( negx )
{
zalloc = xs + 1 ;
zs = xs ;
}
else if ( negy )
{
zalloc = ys + 1 ;
zs = ys ;
}
else
{
zalloc = xs ;
zs = xs ;
}
2015-12-21 17:12:57 +00:00
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , zalloc ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* both are negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w [ 2 ] ;
moo_lidw_t carry [ 2 ] ;
2015-12-17 16:11:10 +00:00
carry [ 0 ] = 1 ;
carry [ 1 ] = 1 ;
/* 2's complement on both x and y and perform bitwise-and */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
w [ 1 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry [ 1 ] ;
2017-01-09 09:54:49 +00:00
carry [ 1 ] = w [ 1 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] | ( moo_liw_t ) w [ 1 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 1 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* do nothing about the extra part in x and the lacking part
* in y for the reason shown in [ NOTE ] in the ' else if ' block
* further down . */
adjust_to_negative :
/* 2's complement on the final result */
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , zs , ~ ( moo_liw_t ) 0 ) ;
2015-12-17 16:11:10 +00:00
carry [ 0 ] = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 0 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-12-10 14:23:09 +00:00
}
2015-12-17 16:11:10 +00:00
else if ( negx )
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* x is negative, y is positive */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-17 16:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w | MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
goto adjust_to_negative ;
2015-12-10 14:23:09 +00:00
}
2015-12-17 16:11:10 +00:00
else if ( negy )
{
/* x is positive, y is negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-10 14:23:09 +00:00
2015-12-17 16:11:10 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) | ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* [NOTE]
* in theory , the lacking part in ys is all 1 s when y is
* extended to the width of x . but those 1 s are inverted to
* 0 s when another 2 ' s complement is performed over the final
* result after the jump to ' adjust_to_negative ' .
* setting zs to ' xs + 1 ' and performing the following loop is
* redundant .
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ~ ( moo_liw_t ) 0 ) ;
2015-12-17 16:11:10 +00:00
}
*/
goto adjust_to_negative ;
}
else
2015-12-10 14:23:09 +00:00
{
2015-12-17 16:11:10 +00:00
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) | MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) ;
2015-12-17 16:11:10 +00:00
}
2015-12-10 14:23:09 +00:00
}
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-10 14:23:09 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-01 12:13:40 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitxorints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-01 12:13:40 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-13 16:08:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v1 , v2 , v3 ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
v1 = MOO_OOP_TO_SMOOI ( x ) ;
v2 = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-17 16:11:10 +00:00
v3 = v1 ^ v2 ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( v3 ) ) return MOO_SMOOI_TO_OOP ( v3 ) ;
return make_bigint_with_ooi ( moo , v3 ) ;
2015-12-13 16:08:05 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-13 16:08:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-13 16:08:05 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return clone_bigint ( moo , y , MOO_OBJ_GET_SIZE ( y ) ) ;
2015-12-13 16:08:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2017-01-09 09:54:49 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-13 16:08:05 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-13 16:08:05 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-17 16:11:10 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-12-13 16:08:05 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-12-13 16:08:05 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2017-01-09 09:54:49 +00:00
y = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-17 16:11:10 +00:00
goto bigint_and_bigint ;
2015-12-13 16:08:05 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i , xs , ys , zs , zalloc ;
2015-12-17 16:11:10 +00:00
int negx , negy ;
2015-12-13 16:08:05 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
bigint_and_bigint :
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
ys = MOO_OBJ_GET_SIZE ( y ) ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
if ( xs < ys )
2015-12-13 16:08:05 +00:00
{
2015-12-17 16:11:10 +00:00
/* make sure that x is greater than or equal to y */
2015-12-13 16:08:05 +00:00
z = x ;
x = y ;
y = z ;
zs = ys ;
ys = xs ;
xs = zs ;
}
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
negy = ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? 1 : 0 ;
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
{
zalloc = xs ;
zs = xs ;
}
else if ( negx )
{
zalloc = xs + 1 ;
zs = xs ;
}
else if ( negy )
{
zalloc = xs + 1 ;
zs = xs ;
}
else
{
zalloc = xs ;
zs = xs ;
}
2015-12-21 17:12:57 +00:00
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & y ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , zalloc ) ;
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 2 ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
if ( negx & & negy )
2015-12-13 16:08:05 +00:00
{
2015-12-17 16:11:10 +00:00
/* both are negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w [ 2 ] ;
moo_lidw_t carry [ 2 ] ;
2015-12-17 16:11:10 +00:00
carry [ 0 ] = 1 ;
carry [ 1 ] = 1 ;
/* 2's complement on both x and y and perform bitwise-and */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
w [ 1 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry [ 1 ] ;
2017-01-09 09:54:49 +00:00
carry [ 1 ] = w [ 1 ] > > MOO_LIW_BITS ;
2015-12-17 16:11:10 +00:00
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] ^ ( moo_liw_t ) w [ 1 ] ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 1 ] = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* treat the lacking part in y as all 1s */
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w [ 0 ] = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry [ 0 ] ;
2017-01-09 09:54:49 +00:00
carry [ 0 ] = w [ 0 ] > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w [ 0 ] ^ ( ~ ( moo_liw_t ) 0 ) ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry [ 0 ] = = 0 ) ;
2015-12-13 16:08:05 +00:00
}
2015-12-17 16:11:10 +00:00
else if ( negx )
2015-12-13 16:08:05 +00:00
{
2015-12-17 16:11:10 +00:00
/* x is negative, y is positive */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-17 16:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ^ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
/* treat the lacking part in y as all 0s */
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
adjust_to_negative :
/* 2's complement on the final result */
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , zs , ~ ( moo_liw_t ) 0 ) ;
2015-12-17 16:11:10 +00:00
carry = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-12-13 16:08:05 +00:00
}
2015-12-17 16:11:10 +00:00
else if ( negy )
{
/* x is positive, y is negative */
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-13 16:08:05 +00:00
2015-12-17 16:11:10 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ^ ( moo_liw_t ) w ) ;
2015-12-17 16:11:10 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:11:10 +00:00
/* treat the lacking part in y as all 1s */
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ^ ( ~ ( moo_liw_t ) 0 ) ) ;
2015-12-17 16:11:10 +00:00
}
goto adjust_to_negative ;
}
else
2015-12-13 16:08:05 +00:00
{
2015-12-17 16:11:10 +00:00
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ^ MOO_OBJ_GET_LIWORD_VAL ( y , i ) ) ;
2015-12-17 16:11:10 +00:00
}
/* treat the lacking part in y as all 0s */
for ( ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) ;
2015-12-17 16:11:10 +00:00
}
2015-12-13 16:08:05 +00:00
}
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-13 16:08:05 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-01 12:13:40 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitinvint ( moo_t * moo , moo_oop_t x )
2015-12-17 16:37:26 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-17 16:37:26 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
2015-12-17 16:37:26 +00:00
v = ~ v ;
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( v ) ) return MOO_SMOOI_TO_OOP ( v ) ;
return make_bigint_with_ooi ( moo , v ) ;
2015-12-17 16:37:26 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t i , xs , zs , zalloc ;
2015-12-17 16:37:26 +00:00
int negx ;
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
2015-12-17 16:37:26 +00:00
if ( negx )
{
zalloc = xs ;
zs = xs ;
}
else
{
zalloc = xs + 1 ;
zs = xs ;
}
2015-12-21 17:12:57 +00:00
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-21 17:12:57 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_positive_integer , MOO_NULL , zalloc ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-17 16:37:26 +00:00
if ( negx )
{
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-17 16:37:26 +00:00
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ~ ( moo_liw_t ) w ) ;
2015-12-17 16:37:26 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-17 16:37:26 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_lidw_t w , carry ;
2015-12-17 16:37:26 +00:00
2015-12-23 15:25:29 +00:00
#if 0
2015-12-17 16:37:26 +00:00
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) ;
2015-12-17 16:37:26 +00:00
}
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , zs , ~ ( moo_liw_t ) 0 ) ;
2015-12-17 16:37:26 +00:00
carry = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-17 16:37:26 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-23 15:25:29 +00:00
# else
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-23 15:25:29 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , i = = zs ) ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) carry ) ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( carry > > MOO_LIW_BITS ) = = 0 ) ;
2015-12-23 15:25:29 +00:00
# endif
2015-12-17 16:37:26 +00:00
2017-01-09 09:54:49 +00:00
MOO_OBJ_SET_CLASS ( z , moo - > _large_negative_integer ) ;
2015-12-17 16:37:26 +00:00
}
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-17 16:37:26 +00:00
}
2015-12-18 15:58:45 +00:00
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameter - %O " , x ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-18 15:58:45 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t rshift_negative_bigint ( moo_t * moo , moo_oop_t x , moo_oow_t shift )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_lidw_t w ;
moo_lidw_t carry ;
moo_oow_t i , xs ;
2015-12-24 14:11:04 +00:00
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
2017-01-09 09:54:49 +00:00
xs = MOO_OBJ_GET_SIZE ( x ) ;
2015-12-24 14:11:04 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2015-12-24 14:11:04 +00:00
/* +1 for the second inversion below */
2018-12-08 15:35:26 +00:00
z = moo_instantiate ( moo , moo - > _large_negative_integer , MOO_NULL , xs + 1 ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
/* the following lines roughly for 'z = moo_bitinv (moo, x)' */
2015-12-24 14:11:04 +00:00
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ~ ( moo_liw_t ) w ) ;
2015-12-24 14:11:04 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2015-12-24 14:11:04 +00:00
/* shift to the right */
2018-12-16 17:35:46 +00:00
rshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , xs , shift ) ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
/* the following lines roughly for 'z = moo_bitinv (moo, z)' */
2015-12-24 14:11:04 +00:00
#if 0
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) ;
2015-12-24 14:11:04 +00:00
}
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , xs , ~ ( moo_liw_t ) 0 ) ;
2015-12-24 14:11:04 +00:00
carry = 1 ;
for ( i = 0 ; i < = xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( ( moo_liw_t ) ~ MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-24 14:11:04 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , carry = = 0 ) ;
2019-08-11 14:58:04 +00:00
# elses
2015-12-24 14:11:04 +00:00
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2019-08-11 14:58:04 +00:00
w = ( moo_lidw_t ) ( MOO_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry ;
2017-01-09 09:54:49 +00:00
carry = w > > MOO_LIW_BITS ;
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) w ) ;
2015-12-24 14:11:04 +00:00
}
2019-08-11 14:58:04 +00:00
MOO_OBJ_SET_LIWORD_VAL ( z , i , ( moo_liw_t ) carry ) ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ( carry > > MOO_LIW_BITS ) = = 0 ) ;
2015-12-24 14:11:04 +00:00
# endif
return z ; /* z is not normalized */
}
2017-01-09 09:54:49 +00:00
# if defined(MOO_LIMIT_OBJ_SIZE)
2015-12-24 14:11:04 +00:00
/* nothing */
# else
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t rshift_negative_bigint_and_normalize ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t shift ;
2015-12-24 14:11:04 +00:00
int sign ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , x ) ) ;
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , y ) ) ;
2015-12-24 14:11:04 +00:00
/* for convenience in subtraction below.
2017-01-09 09:54:49 +00:00
* it could be MOO_TYPE_MAX ( moo_oow_t )
2015-12-24 14:11:04 +00:00
* if make_bigint_with_intmax ( ) or something
2017-01-09 09:54:49 +00:00
* similar were used instead of MOO_SMOOI_TO_OOP ( ) . */
shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
do
{
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-08-10 16:20:44 +00:00
z = rshift_negative_bigint ( moo , x , shift ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
/* y is a negative number. use moo_addints() until it becomes 0 */
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & z ) ;
2019-08-10 16:20:44 +00:00
y = moo_addints ( moo , y , MOO_SMOOI_TO_OOP ( shift ) ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
2019-11-01 09:15:53 +00:00
sign = integer_to_oow_noseterr ( moo , y , & shift ) ;
2017-01-09 09:54:49 +00:00
if ( sign = = 0 ) shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
else
{
if ( shift = = 0 )
{
/* no more shift */
2019-08-10 16:20:44 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-24 14:11:04 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign < = - 1 ) ;
2015-12-24 14:11:04 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-08-10 16:20:44 +00:00
x = normalize_bigint ( moo , z ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-24 14:11:04 +00:00
{
/* for normaization above, x can become a small integer */
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
MOO_ASSERT ( moo , v < 0 ) ;
2015-12-24 14:11:04 +00:00
/* normal right shift of a small negative integer */
2017-01-09 09:54:49 +00:00
if ( shift > = MOO_OOI_BITS - 1 )
2015-12-24 14:11:04 +00:00
{
/* when y is still a large integer, this condition is met
2017-01-09 09:54:49 +00:00
* met as MOO_SMOOI_MAX > MOO_OOI_BITS . so i can simly
2015-12-24 14:11:04 +00:00
* terminate the loop after this */
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( - 1 ) ;
2015-12-24 14:11:04 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
v = ( moo_ooi_t ) ( ( ( moo_oow_t ) v > > shift ) | MOO_HBMASK ( moo_oow_t , shift ) ) ;
if ( MOO_IN_SMOOI_RANGE ( v ) )
return MOO_SMOOI_TO_OOP ( v ) ;
2015-12-24 14:11:04 +00:00
else
2017-01-09 09:54:49 +00:00
return make_bigint_with_ooi ( moo , v ) ;
2015-12-24 14:11:04 +00:00
}
}
}
while ( 1 ) ;
/* this part must not be reached */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ! " internal error - must not happen " ) ;
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EINTERN ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-24 14:11:04 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t rshift_positive_bigint_and_normalize ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t zs , shift ;
2015-12-24 14:11:04 +00:00
int sign ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_PBIGINT ( moo , x ) ) ;
MOO_ASSERT ( moo , MOO_POINTER_IS_NBIGINT ( moo , y ) ) ;
2015-12-24 14:11:04 +00:00
2017-01-09 09:54:49 +00:00
zs = MOO_OBJ_GET_SIZE ( x ) ;
2015-12-24 14:11:04 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-03-29 17:44:32 +00:00
z = clone_bigint ( moo , x , zs ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
/* for convenience in subtraction below.
2017-01-09 09:54:49 +00:00
* it could be MOO_TYPE_MAX ( moo_oow_t )
2015-12-24 14:11:04 +00:00
* if make_bigint_with_intmax ( ) or something
2017-01-09 09:54:49 +00:00
* similar were used instead of MOO_SMOOI_TO_OOP ( ) . */
shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
do
{
2018-12-16 17:35:46 +00:00
rshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , zs , shift ) ;
2019-03-29 17:44:32 +00:00
if ( count_effective ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , zs ) = = 1 & &
2019-08-11 14:58:04 +00:00
MOO_OBJ_GET_LIWORD_VAL ( z , 0 ) = = 0 )
2015-12-24 14:11:04 +00:00
{
/* if z is 0, i don't have to go on */
break ;
}
2017-01-09 09:54:49 +00:00
/* y is a negative number. use moo_addints() until it becomes 0 */
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & z ) ;
2019-03-29 17:44:32 +00:00
y = moo_addints ( moo , y , MOO_SMOOI_TO_OOP ( shift ) ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2015-12-24 14:11:04 +00:00
2019-11-01 09:15:53 +00:00
sign = integer_to_oow_noseterr ( moo , y , & shift ) ;
2017-01-09 09:54:49 +00:00
if ( sign = = 0 ) shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
else
{
if ( shift = = 0 ) break ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign < = - 1 ) ;
2015-12-24 14:11:04 +00:00
}
}
while ( 1 ) ;
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-24 14:11:04 +00:00
}
2017-01-09 09:54:49 +00:00
static MOO_INLINE moo_oop_t lshift_bigint_and_normalize ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t wshift , shift ;
2015-12-24 14:11:04 +00:00
int sign ;
2018-12-21 16:25:25 +00:00
MOO_ASSERT ( moo , MOO_POINTER_IS_PBIGINT ( moo , y ) ) ;
2015-12-24 14:11:04 +00:00
/* this loop is very inefficient as shifting is repeated
* with lshift_unsigned_array ( ) . however , this part of the
* code is not likey to be useful because the amount of
* memory available is certainly not enough to support
2017-01-09 09:54:49 +00:00
* huge shifts greater than MOO_TYPE_MAX ( moo_oow_t ) */
shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
do
{
/* for convenience only in subtraction below.
2017-01-09 09:54:49 +00:00
* should it be between MOO_SMOOI_MAX and MOO_TYPE_MAX ( moo_oow_t ) ,
* the second parameter to moo_subints ( ) can ' t be composed
* using MOO_SMOOI_TO_OOP ( ) */
wshift = shift / MOO_LIW_BITS ;
if ( shift > wshift * MOO_LIW_BITS ) wshift + + ;
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-02-20 17:40:34 +00:00
z = expand_bigint ( moo , x , wshift ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
2018-12-16 17:35:46 +00:00
lshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , MOO_OBJ_GET_SIZE ( z ) , shift ) ;
2017-01-09 09:54:49 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2019-02-20 17:40:34 +00:00
x = normalize_bigint ( moo , z ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2017-01-09 09:54:49 +00:00
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
2019-02-20 17:40:34 +00:00
y = moo_subints ( moo , y , MOO_SMOOI_TO_OOP ( shift ) ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2017-01-09 09:54:49 +00:00
if ( ! y ) return MOO_NULL ;
2019-11-01 09:15:53 +00:00
sign = integer_to_oow_noseterr ( moo , y , & shift ) ;
2017-01-09 09:54:49 +00:00
if ( sign = = 0 ) shift = MOO_SMOOI_MAX ;
2015-12-24 14:11:04 +00:00
else
{
if ( shift = = 0 )
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , is_normalized_integer ( moo , x ) ) ;
2015-12-24 14:11:04 +00:00
return x ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign > = 1 ) ;
2015-12-24 14:11:04 +00:00
}
}
while ( 1 ) ;
/* this part must not be reached */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ! " internal error - must not happen " ) ;
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EINTERN ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-24 14:11:04 +00:00
}
# endif
2017-01-09 09:54:49 +00:00
moo_oop_t moo_bitshiftint ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-18 15:58:45 +00:00
{
/* left shift if y is positive,
* right shift if y is negative */
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-18 15:58:45 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v1 , v2 ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
v1 = MOO_OOP_TO_SMOOI ( x ) ;
v2 = MOO_OOP_TO_SMOOI ( y ) ;
2015-12-18 15:58:45 +00:00
if ( v1 = = 0 | | v2 = = 0 )
{
/* return without cloning as x is a small integer */
return x ;
}
if ( v2 > 0 )
{
/* left shift */
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
moo_oow_t wshift ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
wshift = v2 / MOO_LIW_BITS ;
if ( v2 > wshift * MOO_LIW_BITS ) wshift + + ;
2015-12-18 15:58:45 +00:00
2019-02-20 17:40:34 +00:00
z = make_bloated_bigint_with_ooi ( moo , v1 , wshift ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-18 15:58:45 +00:00
2018-12-16 17:35:46 +00:00
lshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , MOO_OBJ_GET_SIZE ( z ) , v2 ) ;
2019-02-20 17:40:34 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-18 15:58:45 +00:00
}
else
{
/* right shift */
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-18 15:58:45 +00:00
2015-12-22 15:50:01 +00:00
v2 = - v2 ;
if ( v1 < 0 )
{
/* guarantee arithmetic shift preserving the sign bit
* regardless of compiler implementation .
*
* binary decimal shifted by
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 10000011 ( - 125 ) 0
* 11000001 ( - 63 ) 1
* 11100000 ( - 32 ) 2
* 11110000 ( - 16 ) 3
* 11111000 ( - 8 ) 4
* 11111100 ( - 4 ) 5
* 11111110 ( - 2 ) 6
* 11111111 ( - 1 ) 7
* 11111111 ( - 1 ) 8
*/
2017-01-09 09:54:49 +00:00
if ( v2 > = MOO_OOI_BITS - 1 ) v = - 1 ;
2015-12-22 15:50:01 +00:00
else
{
2017-01-09 09:54:49 +00:00
/* MOO_HBMASK_SAFE(moo_oow_t, v2 + 1) could also be
2015-12-22 15:50:01 +00:00
* used as a mask . but the sign bit is shifted in .
* so , masking up to ' v2 ' bits is sufficient */
2017-01-09 09:54:49 +00:00
v = ( moo_ooi_t ) ( ( ( moo_oow_t ) v1 > > v2 ) | MOO_HBMASK ( moo_oow_t , v2 ) ) ;
2015-12-22 15:50:01 +00:00
}
}
else
{
2017-01-09 09:54:49 +00:00
if ( v2 > = MOO_OOI_BITS ) v = 0 ;
2015-12-22 15:50:01 +00:00
else v = v1 > > v2 ;
}
2017-01-09 09:54:49 +00:00
if ( MOO_IN_SMOOI_RANGE ( v ) ) return MOO_SMOOI_TO_OOP ( v ) ;
2019-02-20 17:40:34 +00:00
return make_bigint_with_ooi ( moo , v ) ;
2015-12-18 15:58:45 +00:00
}
}
else
{
2015-12-21 17:12:57 +00:00
int sign , negx , negy ;
2017-01-09 09:54:49 +00:00
moo_oow_t shift ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-18 15:58:45 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-24 14:11:04 +00:00
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , y ) )
2015-12-21 17:12:57 +00:00
{
2015-12-24 14:11:04 +00:00
/* right shift - special case.
* x is a small integer . it is just a few bytes long .
* y is a large negative integer . its smallest absolute value
2017-01-09 09:54:49 +00:00
* is MOO_SMOOI_MAX . i know the final answer . */
return ( v < 0 ) ? MOO_SMOOI_TO_OOP ( - 1 ) : MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-21 17:12:57 +00:00
}
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & y ) ;
2020-10-25 05:54:54 +00:00
x = make_bigint_with_ooi ( moo , v ) ;
2018-12-28 08:29:27 +00:00
moo_popvolat ( moo ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2015-12-21 17:12:57 +00:00
2015-12-24 14:11:04 +00:00
goto bigint_and_bigint ;
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-24 14:11:04 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v ;
2015-12-21 17:12:57 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
v = MOO_OOP_TO_SMOOI ( y ) ;
2019-02-20 17:40:34 +00:00
if ( v = = 0 ) return clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2015-12-21 17:12:57 +00:00
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
2015-12-24 14:11:04 +00:00
if ( v > 0 )
{
sign = 1 ;
negy = 0 ;
shift = v ;
goto bigint_and_positive_oow ;
}
else
{
sign = - 1 ;
negy = 1 ;
shift = - v ;
goto bigint_and_negative_oow ;
2015-12-21 17:12:57 +00:00
}
}
2015-12-24 14:11:04 +00:00
else
2015-12-21 17:12:57 +00:00
{
2017-01-09 09:54:49 +00:00
moo_oop_t z ;
2015-12-23 15:25:29 +00:00
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2015-12-21 17:12:57 +00:00
2015-12-24 14:11:04 +00:00
bigint_and_bigint :
2018-12-21 16:25:25 +00:00
negx = ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? 1 : 0 ;
negy = ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? 1 : 0 ;
2015-12-21 17:12:57 +00:00
2019-11-01 09:15:53 +00:00
sign = bigint_to_oow_noseterr ( moo , y , & shift ) ;
2015-12-24 14:11:04 +00:00
if ( sign = = 0 )
{
/* y is too big or too small */
if ( negy )
{
/* right shift */
2017-01-09 09:54:49 +00:00
# if defined(MOO_LIMIT_OBJ_SIZE)
2015-12-24 14:11:04 +00:00
/* the maximum number of bit shifts are guaranteed to be
2017-01-09 09:54:49 +00:00
* small enough to fit into the moo_oow_t type . so i can
2015-12-24 14:11:04 +00:00
* easily assume that all bits are shifted out */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_OBJ_SIZE_BITS_MAX < = MOO_TYPE_MAX ( moo_oow_t ) ) ;
return ( negx ) ? MOO_SMOOI_TO_OOP ( - 1 ) : MOO_SMOOI_TO_OOP ( 0 ) ;
2015-12-24 14:11:04 +00:00
# else
if ( negx )
2019-02-20 17:40:34 +00:00
return rshift_negative_bigint_and_normalize ( moo , x , y ) ;
2015-12-24 14:11:04 +00:00
else
2019-02-20 17:40:34 +00:00
return rshift_positive_bigint_and_normalize ( moo , x , y ) ;
2015-12-24 14:11:04 +00:00
# endif
}
else
{
/* left shift */
2017-01-09 09:54:49 +00:00
# if defined(MOO_LIMIT_OBJ_SIZE)
2015-12-24 14:11:04 +00:00
/* the maximum number of bit shifts are guaranteed to be
2017-01-09 09:54:49 +00:00
* small enough to fit into the moo_oow_t type . so i can
2015-12-24 14:11:04 +00:00
* simply return a failure here becuase it ' s surely too
* large after shifting */
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , MOO_TYPE_MAX ( moo_oow_t ) > = MOO_OBJ_SIZE_BITS_MAX ) ;
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EOOMEM ) ; /* is it a soft failure or a hard failure? is this error code proper? */
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-24 14:11:04 +00:00
# else
2019-02-20 17:40:34 +00:00
return lshift_bigint_and_normalize ( moo , x , y ) ;
2015-12-24 14:11:04 +00:00
# endif
}
}
else if ( sign > = 1 )
2015-12-23 15:25:29 +00:00
{
2015-12-24 14:11:04 +00:00
/* left shift */
2017-01-09 09:54:49 +00:00
moo_oow_t wshift ;
2015-12-23 15:25:29 +00:00
2015-12-24 14:11:04 +00:00
bigint_and_positive_oow :
2017-01-09 09:54:49 +00:00
wshift = shift / MOO_LIW_BITS ;
if ( shift > wshift * MOO_LIW_BITS ) wshift + + ;
2015-12-23 15:25:29 +00:00
2019-03-29 17:44:32 +00:00
z = expand_bigint ( moo , x , wshift ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-23 15:25:29 +00:00
2018-12-16 17:35:46 +00:00
lshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , MOO_OBJ_GET_SIZE ( z ) , shift ) ;
2015-12-24 14:11:04 +00:00
}
else
{
/* right shift */
bigint_and_negative_oow :
2015-12-23 15:25:29 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , sign < = - 1 ) ;
2015-12-23 15:25:29 +00:00
2015-12-24 14:11:04 +00:00
if ( negx )
2015-12-23 15:25:29 +00:00
{
2019-03-29 17:44:32 +00:00
z = rshift_negative_bigint ( moo , x , shift ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2015-12-23 15:25:29 +00:00
}
2015-12-24 14:11:04 +00:00
else
2015-12-23 15:25:29 +00:00
{
2019-03-29 17:44:32 +00:00
z = clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! z ) ) return MOO_NULL ;
2018-12-16 17:35:46 +00:00
rshift_unsigned_array ( MOO_OBJ_GET_LIWORD_SLOT ( z ) , MOO_OBJ_GET_SIZE ( z ) , shift ) ;
2015-12-23 15:25:29 +00:00
}
}
2015-12-18 15:58:45 +00:00
2017-01-09 09:54:49 +00:00
return normalize_bigint ( moo , z ) ;
2015-12-24 14:11:04 +00:00
}
2015-12-18 15:58:45 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " invalid parameters - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-17 16:37:26 +00:00
}
2015-12-17 16:11:10 +00:00
2017-01-09 09:54:49 +00:00
static moo_uint8_t ooch_val_tab [ ] =
2015-11-04 17:32:28 +00:00
{
99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 ,
99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 ,
99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 , 99 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 99 , 99 , 99 , 99 , 99 , 99 ,
99 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 99 , 99 , 99 , 99 , 99 ,
99 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 ,
25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 99 , 99 , 99 , 99 , 99
} ;
2015-11-03 14:08:43 +00:00
2017-01-09 09:54:49 +00:00
moo_oop_t moo_strtoint ( moo_t * moo , const moo_ooch_t * str , moo_oow_t len , int radix )
2015-11-03 14:08:43 +00:00
{
2015-12-02 16:14:37 +00:00
int sign = 1 ;
2017-01-09 09:54:49 +00:00
const moo_ooch_t * ptr , * start , * end ;
moo_lidw_t w , v ;
moo_liw_t hw [ 16 ] , * hwp = MOO_NULL ;
moo_oow_t hwlen , outlen ;
moo_oop_t res ;
2015-11-03 14:08:43 +00:00
2015-11-12 06:57:35 +00:00
if ( radix < 0 )
{
2015-12-02 16:14:37 +00:00
/* when radix is less than 0, it treats it as if '-' is preceeding */
sign = - 1 ;
2015-11-12 06:57:35 +00:00
radix = - radix ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , radix > = 2 & & radix < = 36 ) ;
2015-11-03 14:08:43 +00:00
ptr = str ;
end = str + len ;
if ( ptr < end )
{
if ( * ptr = = ' + ' ) ptr + + ;
else if ( * ptr = = ' - ' )
{
ptr + + ;
2015-12-02 16:14:37 +00:00
sign = - 1 ;
2015-11-03 14:08:43 +00:00
}
}
if ( ptr > = end ) goto oops_einval ; /* no digits */
while ( ptr < end & & * ptr = = ' 0 ' )
{
/* skip leading zeros */
ptr + + ;
}
if ( ptr > = end )
{
/* all zeros */
2017-01-09 09:54:49 +00:00
return MOO_SMOOI_TO_OOP ( 0 ) ;
2015-11-03 14:08:43 +00:00
}
2015-11-04 17:32:28 +00:00
hwlen = 0 ;
start = ptr ; /* this is the real start */
2019-03-24 18:49:16 +00:00
if ( IS_POW2 ( radix ) )
2015-11-03 14:08:43 +00:00
{
unsigned int exp ;
2015-11-04 17:32:28 +00:00
unsigned int bitcnt ;
2015-11-03 14:08:43 +00:00
/* get log2(radix) in a fast way under the fact that
2015-11-04 17:32:28 +00:00
* radix is a power of 2. the exponent acquired is
* the number of bits that a digit of the given radix takes up */
2019-03-24 18:49:16 +00:00
/*exp = LOG2_FOR_POW2(radix);*/
exp = _exp_tab [ radix - 1 ] ;
2015-11-03 14:08:43 +00:00
2015-11-09 02:00:43 +00:00
/* bytes */
2017-01-09 09:54:49 +00:00
outlen = ( ( moo_oow_t ) ( end - str ) * exp + 7 ) / 8 ;
/* number of moo_liw_t */
outlen = ( outlen + MOO_SIZEOF ( hw [ 0 ] ) - 1 ) / MOO_SIZEOF ( hw [ 0 ] ) ;
2015-11-09 02:00:43 +00:00
2017-01-09 09:54:49 +00:00
if ( outlen > MOO_COUNTOF ( hw ) )
2015-11-09 02:00:43 +00:00
{
2019-02-18 17:13:33 +00:00
/* TODO: reuse this buffer? */
2019-05-04 17:53:16 +00:00
hwp = ( moo_liw_t * ) moo_allocmem ( moo , outlen * MOO_SIZEOF ( hw [ 0 ] ) ) ;
2017-01-09 09:54:49 +00:00
if ( ! hwp ) return MOO_NULL ;
2015-11-09 02:00:43 +00:00
}
else
{
hwp = hw ;
}
2015-11-04 17:32:28 +00:00
w = 0 ;
bitcnt = 0 ;
2015-11-03 14:08:43 +00:00
ptr = end - 1 ;
while ( ptr > = start )
{
2017-01-09 09:54:49 +00:00
if ( * ptr < 0 | | * ptr > = MOO_COUNTOF ( ooch_val_tab ) ) goto oops_einval ;
2015-11-04 17:32:28 +00:00
v = ooch_val_tab [ * ptr ] ;
2015-11-03 14:08:43 +00:00
if ( v > = radix ) goto oops_einval ;
2015-11-04 17:32:28 +00:00
w | = ( v < < bitcnt ) ;
bitcnt + = exp ;
2017-01-09 09:54:49 +00:00
if ( bitcnt > = MOO_LIW_BITS )
2015-11-03 14:08:43 +00:00
{
2017-01-09 09:54:49 +00:00
bitcnt - = MOO_LIW_BITS ;
hwp [ hwlen + + ] = w ; /*(moo_liw_t)(w & MOO_LBMASK(moo_lidw_t, MOO_LIW_BITS));*/
w > > = MOO_LIW_BITS ;
2015-11-03 14:08:43 +00:00
}
ptr - - ;
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , w < = MOO_TYPE_MAX ( moo_liw_t ) ) ;
2015-11-09 02:00:43 +00:00
if ( hwlen = = 0 | | w > 0 ) hwp [ hwlen + + ] = w ;
2015-11-03 14:08:43 +00:00
}
else
{
2017-01-09 09:54:49 +00:00
moo_lidw_t r1 , r2 ;
moo_liw_t multiplier ;
2015-11-09 14:26:58 +00:00
int dg , i , safe_ndigits ;
2015-11-04 17:32:28 +00:00
w = 0 ;
ptr = start ;
2017-01-09 09:54:49 +00:00
safe_ndigits = moo - > bigint [ radix ] . safe_ndigits ;
multiplier = ( moo_liw_t ) moo - > bigint [ radix ] . multiplier ;
2015-11-09 14:26:58 +00:00
outlen = ( end - str ) / safe_ndigits + 1 ;
2017-01-09 09:54:49 +00:00
if ( outlen > MOO_COUNTOF ( hw ) )
2015-11-09 02:00:43 +00:00
{
2019-02-18 17:13:33 +00:00
hwp = moo_allocmem ( moo , outlen * MOO_SIZEOF ( moo_liw_t ) ) ;
2017-01-09 09:54:49 +00:00
if ( ! hwp ) return MOO_NULL ;
2015-11-09 02:00:43 +00:00
}
else
{
hwp = hw ;
}
2015-11-04 17:32:28 +00:00
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , ptr < end ) ;
2015-11-04 17:32:28 +00:00
do
{
r1 = 0 ;
2015-11-09 14:26:58 +00:00
for ( dg = 0 ; dg < safe_ndigits ; dg + + )
2015-11-04 17:32:28 +00:00
{
if ( ptr > = end )
{
multiplier = 1 ;
for ( i = 0 ; i < dg ; i + + ) multiplier * = radix ;
break ;
}
2017-01-09 09:54:49 +00:00
if ( * ptr < 0 | | * ptr > = MOO_COUNTOF ( ooch_val_tab ) ) goto oops_einval ;
2015-11-04 17:32:28 +00:00
v = ooch_val_tab [ * ptr ] ;
if ( v > = radix ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
r1 = r1 * radix + ( moo_liw_t ) v ;
2015-11-04 17:32:28 +00:00
ptr + + ;
}
r2 = r1 ;
for ( i = 0 ; i < hwlen ; i + + )
{
2017-01-09 09:54:49 +00:00
moo_liw_t high , low ;
2015-11-04 17:32:28 +00:00
2017-01-09 09:54:49 +00:00
v = ( moo_lidw_t ) hwp [ i ] * multiplier ;
high = ( moo_liw_t ) ( v > > MOO_LIW_BITS ) ;
low = ( moo_liw_t ) ( v /*& MOO_LBMASK(moo_oow_t, MOO_LIW_BITS)*/ ) ;
2015-11-04 17:32:28 +00:00
2015-11-17 14:13:59 +00:00
# if defined(liw_add_overflow)
/* use liw_add_overflow() only if it's compiler-builtin. */
r2 = high + liw_add_overflow ( low , r2 , & low ) ;
2015-11-04 17:32:28 +00:00
# else
2015-11-17 14:13:59 +00:00
/* don't use the fall-back version of liw_add_overflow() */
2015-11-04 17:32:28 +00:00
low + = r2 ;
2017-01-09 09:54:49 +00:00
r2 = ( moo_lidw_t ) high + ( low < r2 ) ;
2015-11-04 17:32:28 +00:00
# endif
2015-11-09 02:00:43 +00:00
hwp [ i ] = low ;
2015-11-04 17:32:28 +00:00
}
2017-01-09 09:54:49 +00:00
if ( r2 ) hwp [ hwlen + + ] = ( moo_liw_t ) r2 ;
2015-11-04 17:32:28 +00:00
}
2015-11-09 14:26:58 +00:00
while ( ptr < end ) ;
2015-11-03 14:08:43 +00:00
}
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , hwlen > = 1 ) ;
2015-12-02 16:14:37 +00:00
2017-01-09 09:54:49 +00:00
# if (MOO_LIW_BITS == MOO_OOW_BITS)
2015-11-11 13:31:05 +00:00
if ( hwlen = = 1 )
{
w = hwp [ 0 ] ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , - MOO_SMOOI_MAX = = MOO_SMOOI_MIN ) ;
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( ( moo_ooi_t ) w * sign ) ;
2015-12-02 16:14:37 +00:00
}
2017-01-09 09:54:49 +00:00
# elif (MOO_LIW_BITS == MOO_OOHW_BITS)
2015-12-02 16:14:37 +00:00
if ( hwlen = = 1 )
{
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , hwp [ 0 ] < = MOO_SMOOI_MAX ) ;
return MOO_SMOOI_TO_OOP ( ( moo_ooi_t ) hwp [ 0 ] * sign ) ;
2015-11-11 13:31:05 +00:00
}
2015-11-03 14:08:43 +00:00
else if ( hwlen = = 2 )
{
2015-11-09 02:00:43 +00:00
w = MAKE_WORD ( hwp [ 0 ] , hwp [ 1 ] ) ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , - MOO_SMOOI_MAX = = MOO_SMOOI_MIN ) ;
if ( w < = MOO_SMOOI_MAX ) return MOO_SMOOI_TO_OOP ( ( moo_ooi_t ) w * sign ) ;
2015-11-03 14:08:43 +00:00
}
2015-12-02 16:14:37 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
2015-11-11 13:31:05 +00:00
# endif
2015-11-03 14:08:43 +00:00
2018-12-08 15:35:26 +00:00
res = moo_instantiate ( moo , ( sign < 0 ? moo - > _large_negative_integer : moo - > _large_positive_integer ) , hwp , hwlen ) ;
2017-01-09 09:54:49 +00:00
if ( hwp & & hw ! = hwp ) moo_freemem ( moo , hwp ) ;
2015-12-17 16:11:10 +00:00
2015-11-09 02:00:43 +00:00
return res ;
2015-11-03 14:08:43 +00:00
oops_einval :
2017-01-09 09:54:49 +00:00
if ( hwp & & hw ! = hwp ) moo_freemem ( moo , hwp ) ;
2019-02-18 17:13:33 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " unable to convert to integer %.*js " , len , str ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-03 14:08:43 +00:00
}
2015-11-09 14:26:58 +00:00
2018-12-21 16:25:25 +00:00
static moo_oow_t oow_to_text ( moo_t * moo , moo_oow_t w , int flagged_radix , moo_ooch_t * buf )
2015-11-09 14:26:58 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooch_t * ptr ;
2018-02-28 15:39:58 +00:00
const char * _digitc ;
2018-12-21 16:25:25 +00:00
int radix ;
2018-02-28 15:39:58 +00:00
2019-04-16 15:43:54 +00:00
radix = flagged_radix & MOO_INTTOSTR_RADIXMASK ;
2018-12-21 16:25:25 +00:00
_digitc = _digitc_array [ ! ! ( flagged_radix & MOO_INTTOSTR_LOWERCASE ) ] ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , radix > = 2 & & radix < = 36 ) ;
2015-12-01 12:13:40 +00:00
ptr = buf ;
do
{
2015-12-18 15:58:45 +00:00
* ptr + + = _digitc [ w % radix ] ;
2015-12-01 12:13:40 +00:00
w / = radix ;
}
2015-12-02 15:24:13 +00:00
while ( w > 0 ) ;
2015-12-01 12:13:40 +00:00
return ptr - buf ;
}
2017-01-09 09:54:49 +00:00
static void reverse_string ( moo_ooch_t * str , moo_oow_t len )
2015-12-02 15:24:13 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooch_t ch ;
moo_ooch_t * start = str ;
moo_ooch_t * end = str + len - 1 ;
2015-12-02 15:24:13 +00:00
while ( start < end )
{
ch = * start ;
* start + + = * end ;
* end - - = ch ;
}
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_eqints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) = = MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) | | MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return moo - > _false ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return is_equal ( moo , x , y ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_neints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) ! = MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) | | MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return moo - > _true ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return ! is_equal ( moo , x , y ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_gtints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) > MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_PBIGINT ( moo , x ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return is_greater ( moo , x , y ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_geints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) > = MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_PBIGINT ( moo , x ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return ( is_greater ( moo , x , y ) | | is_equal ( moo , x , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_ltints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) < MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_PBIGINT ( moo , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return is_less ( moo , x , y ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
moo_oop_t moo_leints ( moo_t * moo , moo_oop_t x , moo_oop_t y )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
if ( MOO_OOP_IS_SMOOI ( x ) & & MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2017-01-09 09:54:49 +00:00
return ( MOO_OOP_TO_SMOOI ( x ) < = MOO_OOP_TO_SMOOI ( y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( x ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_PBIGINT ( moo , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
2017-01-09 09:54:49 +00:00
else if ( MOO_OOP_IS_SMOOI ( y ) )
2015-12-27 18:02:59 +00:00
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) ) goto oops_einval ;
2018-12-21 16:25:25 +00:00
return ( MOO_POINTER_IS_NBIGINT ( moo , x ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
else
{
2019-05-04 17:53:16 +00:00
if ( ! moo_isbigint ( moo , x ) | | ! moo_isbigint ( moo , y ) ) goto oops_einval ;
2017-01-09 09:54:49 +00:00
return ( is_less ( moo , x , y ) | | is_equal ( moo , x , y ) ) ? moo - > _true : moo - > _false ;
2015-12-27 18:02:59 +00:00
}
oops_einval :
2018-04-03 08:11:11 +00:00
moo_seterrbfmt ( moo , MOO_EINVAL , " parameters not integer - %O, %O " , x , y ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-12-27 18:02:59 +00:00
}
2018-04-07 06:29:17 +00:00
moo_oop_t moo_sqrtint ( moo_t * moo , moo_oop_t x )
{
/* TODO: find a faster and more efficient algorithm??? */
moo_oop_t a , b , m , m2 , t ;
int neg ;
if ( ! moo_isint ( moo , x ) )
{
moo_seterrbfmt ( moo , MOO_EINVAL , " parameter not integer - %O " , x ) ;
return MOO_NULL ;
}
a = moo - > _nil ;
b = moo - > _nil ;
m = moo - > _nil ;
m2 = moo - > _nil ;
2018-12-28 08:29:27 +00:00
moo_pushvolat ( moo , & x ) ;
moo_pushvolat ( moo , & a ) ;
moo_pushvolat ( moo , & b ) ;
moo_pushvolat ( moo , & m ) ;
moo_pushvolat ( moo , & m2 ) ;
2018-04-07 06:29:17 +00:00
a = moo_ltints ( moo , x , MOO_SMOOI_TO_OOP ( 0 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! a ) ) goto oops ;
2018-04-07 06:29:17 +00:00
if ( a = = moo - > _true )
{
/* the given number is a negative number.
* i will arrange the return value to be negative . */
x = moo_negateint ( moo , x ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) goto oops ;
2018-04-07 06:29:17 +00:00
neg = 1 ;
}
else neg = 0 ;
a = MOO_SMOOI_TO_OOP ( 1 ) ;
b = moo_bitshiftint ( moo , x , MOO_SMOOI_TO_OOP ( - 5 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! b ) ) goto oops ;
2018-04-07 06:29:17 +00:00
b = moo_addints ( moo , b , MOO_SMOOI_TO_OOP ( 8 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! b ) ) goto oops ;
2018-04-07 06:29:17 +00:00
while ( 1 )
{
t = moo_geints ( moo , b , a ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! t ) ) return MOO_NULL ;
2018-04-07 06:29:17 +00:00
if ( t = = moo - > _false ) break ;
m = moo_addints ( moo , a , b ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! m ) ) goto oops ;
2018-04-07 06:29:17 +00:00
m = moo_bitshiftint ( moo , m , MOO_SMOOI_TO_OOP ( - 1 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! m ) ) goto oops ;
2018-04-07 06:29:17 +00:00
m2 = moo_mulints ( moo , m , m ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! m2 ) ) goto oops ;
2018-04-07 06:29:17 +00:00
t = moo_gtints ( moo , m2 , x ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! t ) ) return MOO_NULL ;
2018-04-07 06:29:17 +00:00
if ( t = = moo - > _true )
{
b = moo_subints ( moo , m , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! b ) ) goto oops ;
2018-04-07 06:29:17 +00:00
}
else
{
a = moo_addints ( moo , m , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! a ) ) goto oops ;
2018-04-07 06:29:17 +00:00
}
}
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 5 ) ;
2018-04-07 06:29:17 +00:00
x = moo_subints ( moo , a , MOO_SMOOI_TO_OOP ( 1 ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! x ) ) return MOO_NULL ;
2018-04-07 06:29:17 +00:00
if ( neg ) x = moo_negateint ( moo , x ) ;
return x ;
oops :
2018-12-28 08:29:27 +00:00
moo_popvolats ( moo , 5 ) ;
2018-04-07 06:29:17 +00:00
return MOO_NULL ;
}
moo_oop_t moo_absint ( moo_t * moo , moo_oop_t x )
{
if ( MOO_OOP_IS_SMOOI ( x ) )
{
moo_ooi_t v ;
v = MOO_OOP_TO_SMOOI ( x ) ;
if ( v < 0 )
{
v = - v ;
x = MOO_SMOOI_TO_OOP ( v ) ;
}
}
2018-12-21 16:25:25 +00:00
else if ( MOO_POINTER_IS_NBIGINT ( moo , x ) )
2018-04-07 06:29:17 +00:00
{
x = _clone_bigint ( moo , x , MOO_OBJ_GET_SIZE ( x ) , moo - > _large_positive_integer ) ;
}
2018-12-21 16:25:25 +00:00
else if ( MOO_POINTER_IS_PBIGINT ( moo , x ) )
2018-04-07 06:29:17 +00:00
{
/* do nothing. return x without change.
* [ THINK ] but do i need to clone a positive bigint ? */
}
else
{
moo_seterrbfmt ( moo , MOO_EINVAL , " parameter not integer - %O " , x ) ;
return MOO_NULL ;
}
return x ;
}
2019-03-29 17:16:03 +00:00
static MOO_INLINE moo_liw_t get_last_digit ( moo_t * moo , moo_liw_t * x , moo_oow_t * xs , int radix )
2019-03-29 07:05:53 +00:00
{
2019-03-29 17:16:03 +00:00
/* this function changes the contents of the large integer word array */
moo_oow_t oxs = * xs ;
moo_liw_t carry = 0 ;
moo_oow_t i ;
moo_lidw_t dw ;
MOO_ASSERT ( moo , oxs > 0 ) ;
for ( i = oxs ; i > 0 ; )
2019-03-29 07:05:53 +00:00
{
- - i ;
2019-03-29 17:16:03 +00:00
dw = ( ( moo_lidw_t ) carry < < MOO_LIW_BITS ) + x [ i ] ;
/* TODO: optimize it with ASM - no seperate / and % */
2019-04-03 19:19:09 +00:00
x [ i ] = ( moo_liw_t ) ( dw / radix ) ;
carry = ( moo_liw_t ) ( dw % radix ) ;
2019-03-29 07:05:53 +00:00
}
2019-03-29 17:16:03 +00:00
if ( /*oxs > 0 &&*/ x [ oxs - 1 ] = = 0 ) * xs = oxs - 1 ;
return carry ;
2019-03-29 07:05:53 +00:00
}
2018-12-21 16:25:25 +00:00
moo_oop_t moo_inttostr ( moo_t * moo , moo_oop_t num , int flagged_radix )
2015-12-01 12:13:40 +00:00
{
2017-01-09 09:54:49 +00:00
moo_ooi_t v = 0 ;
moo_oow_t w ;
2019-03-29 17:16:03 +00:00
moo_oow_t as ;
2017-01-09 09:54:49 +00:00
moo_liw_t * t = MOO_NULL ;
moo_ooch_t * xbuf = MOO_NULL ;
2019-03-29 17:16:03 +00:00
moo_oow_t xlen = 0 , reqcapa ;
2015-12-01 12:13:40 +00:00
2018-12-21 16:25:25 +00:00
int radix ;
2018-02-28 15:39:58 +00:00
const char * _digitc ;
2019-04-16 15:43:54 +00:00
radix = flagged_radix & MOO_INTTOSTR_RADIXMASK ;
2018-12-21 16:25:25 +00:00
_digitc = _digitc_array [ ! ! ( flagged_radix & MOO_INTTOSTR_LOWERCASE ) ] ;
2017-01-09 09:54:49 +00:00
MOO_ASSERT ( moo , radix > = 2 & & radix < = 36 ) ;
2015-12-21 17:12:57 +00:00
2017-01-09 09:54:49 +00:00
if ( ! moo_isint ( moo , num ) ) goto oops_einval ;
2019-11-01 09:15:53 +00:00
v = integer_to_oow_noseterr ( moo , num , & w ) ;
2015-12-02 15:24:13 +00:00
if ( v )
{
2018-02-17 13:32:30 +00:00
/* The largest buffer is required for radix 2.
2015-12-02 15:24:13 +00:00
* For a binary conversion ( radix 2 ) , the number of bits is
* the maximum number of digits that can be produced . + 1 is
* needed for the sign . */
2015-12-01 12:13:40 +00:00
2018-02-17 13:32:30 +00:00
reqcapa = MOO_OOW_BITS + 1 ;
if ( moo - > inttostr . xbuf . capa < reqcapa )
{
2018-12-20 16:08:56 +00:00
xbuf = ( moo_ooch_t * ) moo_reallocmem ( moo , moo - > inttostr . xbuf . ptr , reqcapa * MOO_SIZEOF ( * xbuf ) ) ;
2018-02-17 13:32:30 +00:00
if ( ! xbuf ) return MOO_NULL ;
moo - > inttostr . xbuf . capa = reqcapa ;
moo - > inttostr . xbuf . ptr = xbuf ;
}
else
{
xbuf = moo - > inttostr . xbuf . ptr ;
}
2018-12-21 16:25:25 +00:00
xlen = oow_to_text ( moo , w , flagged_radix , xbuf ) ;
2018-02-17 13:32:30 +00:00
if ( v < 0 ) xbuf [ xlen + + ] = ' - ' ;
2015-12-02 15:24:13 +00:00
2018-02-17 13:32:30 +00:00
reverse_string ( xbuf , xlen ) ;
2018-12-21 16:25:25 +00:00
if ( flagged_radix & MOO_INTTOSTR_NONEWOBJ )
{
/* special case. don't create a new object.
* the caller can use the data left in moo - > inttostr . xbuf */
moo - > inttostr . xbuf . len = xlen ;
return moo - > _nil ;
}
2018-02-17 13:32:30 +00:00
return moo_makestring ( moo , xbuf , xlen ) ;
2015-12-01 12:13:40 +00:00
}
2019-11-01 09:15:53 +00:00
/* the number can't be represented as a single moo_oow_t value.
* mutli - word conversion begins now */
2017-01-09 09:54:49 +00:00
as = MOO_OBJ_GET_SIZE ( num ) ;
2015-12-07 09:40:45 +00:00
2019-03-29 17:16:03 +00:00
reqcapa = as * MOO_LIW_BITS + 1 ;
if ( moo - > inttostr . xbuf . capa < reqcapa )
{
xbuf = ( moo_ooch_t * ) moo_reallocmem ( moo , moo - > inttostr . xbuf . ptr , reqcapa * MOO_SIZEOF ( * xbuf ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! xbuf ) ) return MOO_NULL ;
2019-03-29 17:16:03 +00:00
moo - > inttostr . xbuf . capa = reqcapa ;
moo - > inttostr . xbuf . ptr = xbuf ;
}
else
{
xbuf = moo - > inttostr . xbuf . ptr ;
}
if ( moo - > inttostr . t . capa < as )
{
t = ( moo_liw_t * ) moo_reallocmem ( moo , moo - > inttostr . t . ptr , reqcapa * MOO_SIZEOF ( * t ) ) ;
2020-10-25 05:54:54 +00:00
if ( MOO_UNLIKELY ( ! t ) ) return MOO_NULL ;
2019-03-29 17:16:03 +00:00
moo - > inttostr . t . capa = as ;
moo - > inttostr . t . ptr = t ;
}
else
{
t = moo - > inttostr . t . ptr ;
}
MOO_MEMCPY ( t , MOO_OBJ_GET_LIWORD_SLOT ( num ) , MOO_SIZEOF ( * t ) * as ) ;
do
{
moo_liw_t dv = get_last_digit ( moo , t , & as , radix ) ;
xbuf [ xlen + + ] = _digitc [ dv ] ;
}
while ( as > 0 ) ;
2015-12-07 09:40:45 +00:00
2018-12-21 16:25:25 +00:00
if ( MOO_POINTER_IS_NBIGINT ( moo , num ) ) xbuf [ xlen + + ] = ' - ' ;
2015-12-07 09:40:45 +00:00
reverse_string ( xbuf , xlen ) ;
2018-12-21 16:25:25 +00:00
if ( flagged_radix & MOO_INTTOSTR_NONEWOBJ )
{
/* special case. don't create a new object.
* the caller can use the data left in moo - > inttostr . xbuf */
moo - > inttostr . xbuf . len = xlen ;
return moo - > _nil ;
}
2015-12-07 09:40:45 +00:00
2018-02-17 13:32:30 +00:00
return moo_makestring ( moo , xbuf , xlen ) ;
2015-12-02 15:24:13 +00:00
oops_einval :
2017-05-11 14:59:20 +00:00
moo_seterrnum ( moo , MOO_EINVAL ) ;
2017-01-09 09:54:49 +00:00
return MOO_NULL ;
2015-11-09 14:26:58 +00:00
}