2018-02-05 10:43:25 +00:00
/*
2018-02-07 14:13:13 +00:00
Copyright ( c ) 2016 - 2018 Chung , Hyung - Hwan . All rights reserved .
2018-02-05 10:43:25 +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-22 00:24:57 +09:00
IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
2018-02-05 10:43:25 +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 .
*/
2025-09-02 23:58:15 +09:00
# include "hak-prv.h"
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2018-02-05 10:43:25 +00:00
/* nothing special */
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
# define MAKE_WORD(hw1,hw2) ((hak_oow_t)(hw1) | (hak_oow_t)(hw2) << HAK_LIW_BITS)
2018-02-05 10:43:25 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
# define IS_SIGN_DIFF(x,y) (((x) ^ (y)) < 0)
2019-03-25 13:01:05 +00:00
/*#define IS_POW2(ui) (((ui) > 0) && (((ui) & (~(ui)+ 1)) == (ui)))*/
# define IS_POW2(ui) (((ui) > 0) && ((ui) & ((ui) - 1)) == 0)
2018-02-05 10:43:25 +00:00
/* digit character array */
2024-09-24 19:41:42 +09:00
static const char * _digitc_array [ ] =
2019-04-16 15:46:00 +00:00
{
" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ " ,
" 0123456789abcdefghijklmnopqrstuvwxyz "
} ;
2018-02-05 10:43:25 +00:00
2019-03-25 13:01:05 +00:00
/* exponent table for pow2 between 1 and 32 inclusive. */
2025-09-02 23:58:15 +09:00
static hak_uint8_t _exp_tab [ 32 ] =
2019-03-25 13:01:05 +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
} ;
2025-09-02 23:58:15 +09:00
static const hak_uint8_t debruijn_32 [ 32 ] =
2019-03-25 13:01:05 +00:00
{
0 , 1 , 28 , 2 , 29 , 14 , 24 , 3 ,
2023-11-10 00:03:03 +09:00
30 , 22 , 20 , 15 , 25 , 17 , 4 , 8 ,
2019-03-25 13:01:05 +00:00
31 , 27 , 13 , 23 , 21 , 19 , 16 , 7 ,
26 , 12 , 18 , 6 , 11 , 5 , 10 , 9
} ;
2025-09-02 23:58:15 +09:00
static const hak_uint8_t debruijn_64 [ 64 ] =
2018-02-05 10:43:25 +00:00
{
2019-03-25 13:01:05 +00:00
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
2018-02-05 10:43:25 +00:00
} ;
2025-09-02 23:58:15 +09:00
# define make_pbigint(hak, ptr, len) (hak_instantiate(hak, hak->c_large_positive_integer, ptr, len))
# define make_nbigint(hak, ptr, len) (hak_instantiate(hak, hak->c_large_negative_integer, ptr, len))
2024-09-12 18:06:12 +09:00
2025-09-02 23:58:15 +09:00
# if defined(HAK_HAVE_UINT32_T)
# define LOG2_FOR_POW2_32(x) (debruijn_32[(hak_uint32_t)((hak_uint32_t)(x) * 0x077CB531) >> 27])
2019-03-25 13:01:05 +00:00
# endif
2025-09-02 23:58:15 +09:00
# if defined(HAK_HAVE_UINT64_T)
# define LOG2_FOR_POW2_64(x) (debruijn_64[(hak_uint64_t)((hak_uint64_t)(x) * 0x022fdd63cc95386d) >> 58])
2019-03-25 13:01:05 +00:00
# endif
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
# if defined(HAK_HAVE_UINT32_T) && (HAK_SIZEOF_OOW_T == HAK_SIZEOF_UINT32_T)
2019-03-25 13:01:05 +00:00
# define LOG2_FOR_POW2(x) LOG2_FOR_POW2_32(x)
2025-09-02 23:58:15 +09:00
# elif defined(HAK_HAVE_UINT64_T) && (HAK_SIZEOF_OOW_T == HAK_SIZEOF_UINT64_T)
2019-03-25 13:01:05 +00:00
# define LOG2_FOR_POW2(x) LOG2_FOR_POW2_64(x)
# else
2025-09-02 23:58:15 +09:00
# define LOG2_FOR_POW2(x) hak_get_pos_of_msb_set_pow2(x)
2019-03-25 13:01:05 +00:00
# endif
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_OOW_T == HAK_SIZEOF_INT) && defined(HAK_HAVE_BUILTIN_UADD_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_OOW_T == HAK_SIZEOF_LONG) && defined(HAK_HAVE_BUILTIN_UADDL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_OOW_T == HAK_SIZEOF_LONG_LONG) && defined(HAK_HAVE_BUILTIN_UADDLL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE int oow_add_overflow ( hak_oow_t a , hak_oow_t b , hak_oow_t * c )
2018-02-05 10:43:25 +00:00
{
* c = a + b ;
2025-09-02 23:58:15 +09:00
return b > HAK_TYPE_MAX ( hak_oow_t ) - a ;
2018-02-05 10:43:25 +00:00
}
# endif
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_OOW_T == HAK_SIZEOF_INT) && defined(HAK_HAVE_BUILTIN_UMUL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umul_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_OOW_T == HAK_SIZEOF_LONG) && defined(HAK_HAVE_BUILTIN_UMULL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umull_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_OOW_T == HAK_SIZEOF_LONG_LONG) && defined(HAK_HAVE_BUILTIN_UMULLL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define oow_mul_overflow(a,b,c) __builtin_umulll_overflow(a,b,c)
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE int oow_mul_overflow ( hak_oow_t a , hak_oow_t b , hak_oow_t * c )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T > HAK_SIZEOF_OOW_T)
hak_uintmax_t k ;
k = ( hak_uintmax_t ) a * ( hak_uintmax_t ) b ;
* c = ( hak_oow_t ) k ;
return ( k > > HAK_OOW_BITS ) > 0 ;
/*return k > HAK_TYPE_MAX(hak_oow_t);*/
2018-02-05 10:43:25 +00:00
# else
* c = a * b ;
2025-09-02 23:58:15 +09:00
return b ! = 0 & & a > HAK_TYPE_MAX ( hak_oow_t ) / b ; /* works for unsigned types only */
2018-02-05 10:43:25 +00:00
# endif
}
# endif
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_OOI_T == HAK_SIZEOF_INT) && defined(HAK_HAVE_BUILTIN_SMUL_OVERFLOW)
# define shaki_mul_overflow(hak,a,b,c) __builtin_smul_overflow(a,b,c)
# elif (HAK_SIZEOF_OOI_T == HAK_SIZEOF_LONG) && defined(HAK_HAVE_BUILTIN_SMULL_OVERFLOW)
# define shaki_mul_overflow(hak,a,b,c) __builtin_smull_overflow(a,b,c)
# elif (HAK_SIZEOF_OOI_T == HAK_SIZEOF_LONG_LONG) && defined(HAK_HAVE_BUILTIN_SMULLL_OVERFLOW)
# define shaki_mul_overflow(hak,a,b,c) __builtin_smulll_overflow(a,b,c)
2018-02-05 10:43:25 +00:00
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE int shaki_mul_overflow ( hak_t * hak , hak_ooi_t a , hak_ooi_t b , hak_ooi_t * c )
2018-02-05 10:43:25 +00:00
{
/* take note that this function is not supposed to handle
2025-09-02 23:58:15 +09:00
* the whole hak_ooi_t range . it handles the shaki subrange */
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T > HAK_SIZEOF_OOI_T)
hak_intmax_t k ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( a ) ) ;
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( b ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
k = ( hak_intmax_t ) a * ( hak_intmax_t ) b ;
* c = ( hak_ooi_t ) k ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
return k > HAK_TYPE_MAX ( hak_ooi_t ) | | k < HAK_TYPE_MIN ( hak_ooi_t ) ;
2018-02-05 10:43:25 +00:00
# else
2025-09-02 23:58:15 +09:00
hak_ooi_t ua , ub ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( a ) ) ;
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( b ) ) ;
2018-02-05 10:43:25 +00:00
* c = a * b ;
ub = ( b > = 0 ) ? b : - b ;
ua = ( a > = 0 ) ? a : - a ;
2023-11-10 00:03:03 +09:00
/* though this fomula basically works for unsigned types in principle,
2018-02-05 10:43:25 +00:00
* the values used here are all absolute values and they fall in
* a safe range to apply this fomula . the safe range is guaranteed because
2025-09-02 23:58:15 +09:00
* the sources are supposed to be shakis . */
return ub ! = 0 & & ua > HAK_TYPE_MAX ( hak_ooi_t ) / ub ;
2018-02-05 10:43:25 +00:00
# endif
}
# endif
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_LIW_T == HAK_SIZEOF_INT) && defined(HAK_HAVE_BUILTIN_UADD_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_add_overflow(a,b,c) __builtin_uadd_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_LIW_T == HAK_SIZEOF_LONG) && defined(HAK_HAVE_BUILTIN_UADDL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_add_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_LIW_T == HAK_SIZEOF_LONG_LONG) && defined(HAK_HAVE_BUILTIN_UADDLL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_add_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE int liw_add_overflow ( hak_liw_t a , hak_liw_t b , hak_liw_t * c )
2018-02-05 10:43:25 +00:00
{
* c = a + b ;
2025-09-02 23:58:15 +09:00
return b > HAK_TYPE_MAX ( hak_liw_t ) - a ;
2018-02-05 10:43:25 +00:00
}
# endif
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_LIW_T == HAK_SIZEOF_INT) && defined(HAK_HAVE_BUILTIN_UMUL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_mul_overflow(a,b,c) __builtin_umul_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_LIW_T == HAK_SIZEOF_LONG) && defined(HAK_HAVE_BUILTIN_UMULL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_mul_overflow(a,b,c) __builtin_uaddl_overflow(a,b,c)
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_LIW_T == HAK_SIZEOF_LONG_LONG) && defined(HAK_HAVE_BUILTIN_UMULLL_OVERFLOW)
2018-02-05 10:43:25 +00:00
# define liw_mul_overflow(a,b,c) __builtin_uaddll_overflow(a,b,c)
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE int liw_mul_overflow ( hak_liw_t a , hak_liw_t b , hak_liw_t * c )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T > HAK_SIZEOF_LIW_T)
hak_uintmax_t k ;
k = ( hak_uintmax_t ) a * ( hak_uintmax_t ) b ;
* c = ( hak_liw_t ) k ;
return ( k > > HAK_LIW_BITS ) > 0 ;
/*return k > HAK_TYPE_MAX(hak_liw_t);*/
2018-02-05 10:43:25 +00:00
# else
* c = a * b ;
2025-09-02 23:58:15 +09:00
return b ! = 0 & & a > HAK_TYPE_MAX ( hak_liw_t ) / b ; /* works for unsigned types only */
2018-02-05 10:43:25 +00:00
# endif
}
# endif
2025-09-02 23:58:15 +09:00
static int is_normalized_integer ( hak_t * hak , hak_oop_t oop )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( oop ) ) return 1 ;
if ( HAK_IS_BIGINT ( hak , oop ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t sz ;
sz = HAK_OBJ_GET_SIZE ( oop ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sz > = 1 ) ;
2025-09-02 23:58:15 +09:00
return HAK_OBJ_GET_LIWORD_VAL ( oop , sz - 1 ) ! = 0 ;
2018-02-05 10:43:25 +00:00
}
return 0 ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int bigint_to_oow_noseterr ( hak_t * hak , hak_oop_t num , hak_oow_t * w )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_BIGINT ( hak , num ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_GET_SIZE ( num ) > = 1 ) ;
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_SIZE ( num ) = = 1 )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
* w = HAK_OBJ_GET_WORD_VAL ( num , 0 ) ;
return HAK_IS_NBIGINT ( hak , num ) ? - 1 : 1 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
2018-02-05 10:43:25 +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 . */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_GET_SIZE ( num ) > = 2 ) ;
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_SIZE ( num ) = = 2 )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
* w = MAKE_WORD ( HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) , HAK_OBJ_GET_HALFWORD_VAL ( num , 1 ) ) ;
return HAK_IS_NBIGINT ( hak , num ) ? - 1 : 1 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_SIZE ( num ) = = 1 )
2025-08-05 13:30:33 +09:00
{
/* if someone create a big number with a small integer,
* it can just be one half - word */
2025-09-02 23:58:15 +09:00
* w = HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) ;
return HAK_IS_NBIGINT ( hak , num ) ? - 1 : 1 ;
2025-08-05 13:30:33 +09:00
}
2018-02-05 10:43:25 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
return 0 ; /* not convertable */
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int integer_to_oow_noseterr ( hak_t * hak , hak_oop_t x , hak_oow_t * w )
2018-02-05 10:43:25 +00:00
{
2023-11-10 00:03:03 +09:00
/* return value
2025-09-02 23:58:15 +09:00
* 1 - a positive number including 0 that can fit into hak_oow_t
* - 1 - a negative number whose absolute value can fit into hak_oow_t
2018-02-05 10:43:25 +00:00
* 0 - number too large or too small
*/
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2018-02-05 10:43:25 +00:00
if ( v < 0 )
{
* w = - v ;
return - 1 ;
}
else
{
* w = v ;
return 1 ;
}
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , hak_isbigint ( hak , x ) ) ;
2025-09-02 23:58:15 +09:00
return bigint_to_oow_noseterr ( hak , x , w ) ;
2024-08-10 18:00:33 +09:00
}
2025-09-02 23:58:15 +09:00
int hak_inttooow_noseterr ( hak_t * hak , hak_oop_t x , hak_oow_t * w )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2024-08-10 18:00:33 +09:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2024-08-10 18:00:33 +09:00
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 */
2025-09-02 23:58:15 +09:00
return hak_isbigint ( hak , x ) ? bigint_to_oow_noseterr ( hak , x , w ) : 0 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
int hak_inttooow ( hak_t * hak , hak_oop_t x , hak_oow_t * w )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2018-02-05 10:43:25 +00:00
if ( v < 0 )
{
* w = - v ;
2025-09-16 18:13:12 +09:00
hak_seterrbfmt ( hak , HAK_ERANGE , " negative number - %O " , x ) ;
2018-02-05 10:43:25 +00:00
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2024-08-10 18:00:33 +09:00
{
int n ;
2025-09-05 10:52:02 +09:00
if ( ( n = bigint_to_oow_noseterr ( hak , x , w ) ) < = 0 ) hak_seterrnum ( hak , HAK_ERANGE ) ;
2024-08-10 18:00:33 +09:00
return n ;
}
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O " , x ) ;
2018-04-03 08:11:56 +00:00
return 0 ; /* not convertable - too big, too small, or not integer */
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
int hak_inttoooi_noseterr ( hak_t * hak , hak_oop_t x , hak_ooi_t * i )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
* i = HAK_OOP_TO_SMOOI ( x ) ;
2024-08-10 18:00:33 +09:00
return ( * i < 0 ) ? - 1 : 1 ;
}
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t w ;
2024-08-10 18:00:33 +09:00
int n ;
2025-09-02 23:58:15 +09:00
n = bigint_to_oow_noseterr ( hak , x , & w ) ;
2024-08-10 18:00:33 +09:00
if ( n < 0 )
{
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( HAK_TYPE_MAX ( hak_ooi_t ) + HAK_TYPE_MIN ( hak_ooi_t ) = = - 1 ) ; /* assume 2's complement */
2025-09-02 23:58:15 +09:00
if ( w > ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 ) return 0 ; /* too small */
* i = ( w < = ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) ) ? - ( hak_ooi_t ) w : HAK_TYPE_MIN ( hak_ooi_t ) ; /* negate back */
2024-08-10 18:00:33 +09:00
}
else if ( n > 0 )
{
2025-09-02 23:58:15 +09:00
if ( w > HAK_TYPE_MAX ( hak_ooi_t ) ) return 0 ; /* too big */
2024-08-10 18:00:33 +09:00
* i = w ;
}
return n ;
}
return 0 ; /* not integer */
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
int hak_inttoooi ( hak_t * hak , hak_oop_t x , hak_ooi_t * i )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
* i = HAK_OOP_TO_SMOOI ( x ) ;
2024-08-10 18:00:33 +09:00
return ( * i < 0 ) ? - 1 : 1 ;
}
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2024-08-10 18:00:33 +09:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t w ;
2024-08-10 18:00:33 +09:00
int n ;
2025-09-02 23:58:15 +09:00
n = bigint_to_oow_noseterr ( hak , x , & w ) ;
2024-08-10 18:00:33 +09:00
if ( n < 0 )
{
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( HAK_TYPE_MAX ( hak_ooi_t ) + HAK_TYPE_MIN ( hak_ooi_t ) = = - 1 ) ; /* assume 2's complement */
2025-09-02 23:58:15 +09:00
if ( w > ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 )
2024-08-10 18:00:33 +09:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2024-08-10 18:00:33 +09:00
return 0 ; /* too small */
}
2025-09-02 23:58:15 +09:00
* i = ( w < = ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) ) ? - ( hak_ooi_t ) w : HAK_TYPE_MIN ( hak_ooi_t ) ; /* negate back */
2024-08-10 18:00:33 +09:00
}
else if ( n > 0 )
{
2025-09-02 23:58:15 +09:00
if ( w > HAK_TYPE_MAX ( hak_ooi_t ) )
2024-08-10 18:00:33 +09:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2024-08-10 18:00:33 +09:00
return 0 ; /* too big */
}
* i = w ;
}
else
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2024-08-10 18:00:33 +09:00
}
return n ;
}
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not an integer - %O " , x ) ;
2024-08-10 18:00:33 +09:00
return 0 ; /* not integer */
}
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T == HAK_SIZEOF_OOW_T)
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
/* do nothing. required macros are defined in hak.h */
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
# elif (HAK_SIZEOF_UINTMAX_T == HAK_SIZEOF_OOW_T * 2) || (HAK_SIZEOF_UINTMAX_T == HAK_SIZEOF_OOW_T * 4)
static HAK_INLINE int bigint_to_uintmax_noseterr ( hak_t * hak , hak_oop_t num , hak_uintmax_t * w )
2019-08-13 07:15:12 +00:00
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OOP_IS_POINTER ( num ) ) ;
HAK_ASSERT ( hak , HAK_IS_PBIGINT ( hak , num ) | | HAK_IS_NBIGINT ( hak , num ) ) ;
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_GET_SIZE ( num ) > = 1 ) ;
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
switch ( HAK_OBJ_GET_SIZE ( num ) )
2019-08-13 07:15:12 +00:00
{
case 1 :
2025-09-02 23:58:15 +09:00
* w = ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 0 ) ;
2019-08-13 07:15:12 +00:00
goto done ;
case 2 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 0 ) < < HAK_LIW_BITS ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 1 ) ) ;
2019-08-13 07:15:12 +00:00
goto done ;
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T >= HAK_SIZEOF_OOW_T * 4)
2024-09-20 12:00:18 +09:00
case 3 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 0 ) < < ( HAK_LIW_BITS * 2 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 1 ) < < ( HAK_LIW_BITS * 1 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 2 ) )
2024-09-20 12:00:18 +09:00
goto done ;
case 4 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 0 ) < < ( HAK_LIW_BITS * 3 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 1 ) < < ( HAK_LIW_BITS * 2 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 2 ) < < ( HAK_LIW_BITS * 1 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_WORD_VAL ( num , 3 ) )
2024-09-20 12:00:18 +09:00
goto done ;
# endif
2019-08-13 07:15:12 +00:00
default :
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable */
2019-08-13 07:15:12 +00:00
}
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_GET_SIZE ( num ) > = 2 ) ;
2025-09-02 23:58:15 +09:00
switch ( HAK_OBJ_GET_SIZE ( num ) )
2019-08-13 07:15:12 +00:00
{
case 2 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < HAK_LIW_BITS ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 1 ) ) ;
2019-08-13 07:15:12 +00:00
goto done ;
case 4 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < ( HAK_LIW_BITS * 3 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < ( HAK_LIW_BITS * 2 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < ( HAK_LIW_BITS * 1 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 3 ) ) ;
2024-09-20 12:00:18 +09:00
goto done ;
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T >= HAK_SIZEOF_OOW_T * 4)
2024-09-20 12:00:18 +09:00
case 6 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < ( HAK_LIW_BITS * 5 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < ( HAK_LIW_BITS * 4 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < ( HAK_LIW_BITS * 3 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 3 ) < < ( HAK_LIW_BITS * 2 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 4 ) < < ( HAK_LIW_BITS * 1 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 5 ) ) ;
2019-08-13 07:15:12 +00:00
goto done ;
2024-09-20 12:00:18 +09:00
case 8 :
2025-09-02 23:58:15 +09:00
* w = ( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 0 ) < < ( HAK_LIW_BITS * 7 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 1 ) < < ( HAK_LIW_BITS * 6 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 2 ) < < ( HAK_LIW_BITS * 5 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 3 ) < < ( HAK_LIW_BITS * 4 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 4 ) < < ( HAK_LIW_BITS * 3 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 5 ) < < ( HAK_LIW_BITS * 2 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 6 ) < < ( HAK_LIW_BITS * 1 ) ) |
( ( hak_uintmax_t ) HAK_OBJ_GET_HALFWORD_VAL ( num , 7 ) ) ;
2024-09-20 12:00:18 +09:00
goto done ;
# endif
2019-08-13 07:15:12 +00:00
default :
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable */
2019-08-13 07:15:12 +00:00
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
done :
2025-09-02 23:58:15 +09:00
return ( HAK_IS_NBIGINT ( hak , num ) ) ? - 1 : 1 ;
2025-08-05 22:36:08 +09:00
}
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
int hak_inttouintmax_noseterr ( hak_t * hak , hak_oop_t x , hak_uintmax_t * w )
2025-08-05 22:36:08 +09:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2025-08-05 22:36:08 +09:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2025-08-05 22:36:08 +09:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2025-08-05 22:36:08 +09:00
if ( v < 0 )
{
* w = - v ;
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) ) return bigint_to_uintmax_noseterr ( hak , x , w ) ;
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable - too big, too small, or not an integer */
2019-08-13 07:15:12 +00:00
}
2025-09-02 23:58:15 +09:00
int hak_inttouintmax ( hak_t * hak , hak_oop_t x , hak_uintmax_t * w )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2019-08-13 07:15:12 +00:00
if ( v < 0 )
{
* w = - v ;
return - 1 ; /* negative number negated - kind of an error */
}
else
{
* w = v ;
return 1 ; /* zero or positive number */
}
}
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2025-08-05 22:36:08 +09:00
{
int n ;
2025-09-02 23:58:15 +09:00
n = bigint_to_uintmax_noseterr ( hak , x , w ) ;
if ( n < = 0 ) hak_seterrnum ( hak , HAK_ERANGE ) ;
2025-08-05 22:36:08 +09:00
return n ;
}
2019-08-13 07:15:12 +00:00
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not an integer - %O " , x ) ;
2019-08-13 07:15:12 +00:00
return 0 ; /* not convertable - too big, too small, or not an integer */
}
2025-09-02 23:58:15 +09:00
int hak_inttointmax_noseterr ( hak_t * hak , hak_oop_t x , hak_intmax_t * i )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2025-08-05 22:36:08 +09:00
{
2025-09-02 23:58:15 +09:00
* i = HAK_OOP_TO_SMOOI ( x ) ;
2025-08-05 22:36:08 +09:00
return ( * i < 0 ) ? - 1 : 1 ;
}
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2019-08-13 07:15:12 +00:00
{
2025-08-05 22:36:08 +09:00
int n ;
2025-09-02 23:58:15 +09:00
hak_uintmax_t w ;
2025-08-05 22:36:08 +09:00
2025-09-02 23:58:15 +09:00
n = bigint_to_uintmax_noseterr ( hak , x , & w ) ;
2025-08-05 22:36:08 +09:00
if ( n < 0 )
2019-08-13 07:15:12 +00:00
{
2025-08-05 22:36:08 +09:00
/* negative number negated to a positve number */
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( HAK_TYPE_MAX ( hak_intmax_t ) + HAK_TYPE_MIN ( hak_intmax_t ) = = - 1 ) ; /* assume 2's complement */
2025-09-02 23:58:15 +09:00
if ( w > ( hak_uintmax_t ) HAK_TYPE_MAX ( hak_intmax_t ) + 1 ) return 0 ; /* not convertable - too small */
* i = ( w < = ( hak_uintmax_t ) HAK_TYPE_MAX ( hak_intmax_t ) ) ? - ( hak_intmax_t ) w : HAK_TYPE_MIN ( hak_intmax_t ) ; /* negate back */
2019-08-13 07:15:12 +00:00
}
2025-08-05 22:36:08 +09:00
else if ( n > 0 )
{
2025-09-02 23:58:15 +09:00
if ( w > HAK_TYPE_MAX ( hak_intmax_t ) ) return 0 ; /* not convertable - too big */
2025-08-05 22:36:08 +09:00
* i = w ;
}
return n ;
2019-08-13 07:15:12 +00:00
}
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable - not an integer */
}
2025-09-02 23:58:15 +09:00
int hak_inttointmax ( hak_t * hak , hak_oop_t x , hak_intmax_t * i )
2025-08-05 22:36:08 +09:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
* i = HAK_OOP_TO_SMOOI ( x ) ;
2025-08-05 22:36:08 +09:00
return ( * i < 0 ) ? - 1 : 1 ;
}
2025-09-02 23:58:15 +09:00
if ( hak_isbigint ( hak , x ) )
2025-08-05 22:36:08 +09:00
{
int n ;
2025-09-02 23:58:15 +09:00
hak_uintmax_t w ;
2025-08-05 22:36:08 +09:00
2025-09-02 23:58:15 +09:00
n = bigint_to_uintmax_noseterr ( hak , x , & w ) ;
2025-08-05 22:36:08 +09:00
if ( n < 0 )
{
/* negative number negated to a positve number */
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( HAK_TYPE_MAX ( hak_intmax_t ) + HAK_TYPE_MIN ( hak_intmax_t ) = = - 1 ) ; /* assume 2's complement */
2025-09-02 23:58:15 +09:00
if ( w > ( hak_uintmax_t ) HAK_TYPE_MAX ( hak_intmax_t ) + 1 )
2025-08-05 22:36:08 +09:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable. too small */
}
2025-09-02 23:58:15 +09:00
* i = ( w < = ( hak_uintmax_t ) HAK_TYPE_MAX ( hak_intmax_t ) ) ? - ( hak_intmax_t ) w : HAK_TYPE_MIN ( hak_intmax_t ) ; /* negate back */
2025-08-05 22:36:08 +09:00
}
else if ( n > 0 )
{
2025-09-02 23:58:15 +09:00
if ( w > HAK_TYPE_MAX ( hak_intmax_t ) )
2025-08-05 22:36:08 +09:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable. too big */
}
* i = w ;
}
else
2019-08-13 07:15:12 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_ERANGE ) ;
2019-08-13 07:15:12 +00:00
}
2025-08-05 22:36:08 +09:00
return n ;
2019-08-13 07:15:12 +00:00
}
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not an integer - %O " , x ) ;
2025-08-05 22:36:08 +09:00
return 0 ; /* not convertable - too big, too small, or not an integer */
2019-08-13 07:15:12 +00:00
}
# else
# error UNSUPPORTED UINTMAX SIZE
# endif
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t make_bigint_with_oow ( hak_t * hak , hak_oow_t w )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_SIZEOF ( hak_oow_t ) = = HAK_SIZEOF ( hak_liw_t ) ) ;
2025-09-02 23:58:15 +09:00
return make_pbigint ( hak , & w , 1 ) ;
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
hak_liw_t hw [ 2 ] ;
hw [ 0 ] = w /*& HAK_LBMASK(hak_oow_t,HAK_LIW_BITS)*/ ;
hw [ 1 ] = w > > HAK_LIW_BITS ;
return make_pbigint ( hak , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2018-02-05 10:43:25 +00:00
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t make_bigint_with_ooi ( hak_t * hak , hak_ooi_t i )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
hak_oow_t w ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( hak , HAK_SIZEOF ( hak_oow_t ) = = HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
if ( i > = 0 )
{
w = i ;
2025-09-02 23:58:15 +09:00
return make_pbigint ( hak , & w , 1 ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
w = ( i = = HAK_TYPE_MIN ( hak_ooi_t ) ) ? ( ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 ) : - i ;
return make_nbigint ( hak , & w , 1 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
hak_liw_t hw [ 2 ] ;
hak_oow_t w ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_STATIC_ASSERT ( HAK_SIZEOF ( hak_oohw_t ) = = HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
if ( i > = 0 )
{
w = i ;
2025-09-02 23:58:15 +09:00
hw [ 0 ] = w /*& HAK_LBMASK(hak_oow_t,HAK_LIW_BITS)*/ ;
hw [ 1 ] = w > > HAK_LIW_BITS ;
return make_pbigint ( hak , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
w = ( i = = HAK_TYPE_MIN ( hak_ooi_t ) ) ? ( ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 ) : - i ;
hw [ 0 ] = w /*& HAK_LBMASK(hak_oow_t,HAK_LIW_BITS)*/ ;
hw [ 1 ] = w > > HAK_LIW_BITS ;
return make_nbigint ( hak , hw , ( hw [ 1 ] > 0 ? 2 : 1 ) ) ;
2018-02-05 10:43:25 +00:00
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t make_bloated_bigint_with_ooi ( hak_t * hak , hak_ooi_t i , hak_oow_t extra )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
hak_oow_t w ;
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , extra < = HAK_OBJ_SIZE_MAX - 1 ) ;
HAK_STATIC_ASSERT ( hak , HAK_SIZEOF ( hak_oow_t ) = = HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
if ( i > = 0 )
{
w = i ;
2025-09-02 23:58:15 +09:00
z = make_pbigint ( hak , HAK_NULL , 1 + extra ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
w = ( i = = HAK_TYPE_MIN ( hak_ooi_t ) ) ? ( ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 ) : - i ;
z = make_nbigint ( hak , HAK_NULL , 1 + extra ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
HAK_OBJ_SET_LIWORD_VAL ( z , 0 , w ) ;
2018-02-05 10:43:25 +00:00
return z ;
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
hak_liw_t hw [ 2 ] ;
hak_oow_t w ;
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , extra < = HAK_OBJ_SIZE_MAX - 2 ) ;
2018-02-05 10:43:25 +00:00
if ( i > = 0 )
{
w = i ;
2025-09-02 23:58:15 +09:00
hw [ 0 ] = w /*& HAK_LBMASK(hak_oow_t,HAK_LIW_BITS)*/ ;
hw [ 1 ] = w > > HAK_LIW_BITS ;
z = make_pbigint ( hak , HAK_NULL , ( hw [ 1 ] > 0 ? 2 : 1 ) + extra ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
w = ( i = = HAK_TYPE_MIN ( hak_ooi_t ) ) ? ( ( hak_oow_t ) HAK_TYPE_MAX ( hak_ooi_t ) + 1 ) : - i ;
hw [ 0 ] = w /*& HAK_LBMASK(hak_oow_t,HAK_LIW_BITS)*/ ;
hw [ 1 ] = w > > HAK_LIW_BITS ;
z = make_nbigint ( hak , HAK_NULL , ( hw [ 1 ] > 0 ? 2 : 1 ) + extra ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
HAK_OBJ_SET_LIWORD_VAL ( z , 0 , hw [ 0 ] ) ;
if ( hw [ 1 ] > 0 ) HAK_OBJ_SET_LIWORD_VAL ( z , 1 , hw [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
return z ;
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t make_bigint_with_intmax ( hak_t * hak , hak_intmax_t v )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t len ;
hak_liw_t buf [ HAK_SIZEOF_INTMAX_T / HAK_SIZEOF_LIW_T ] ;
hak_uintmax_t ui ;
hak_oop_class_t _class ;
2018-02-05 10:43:25 +00:00
2023-11-10 00:03:03 +09:00
/* this is not a generic function. it can't handle v
2025-09-02 23:58:15 +09:00
* if it ' s HAK_TYPE_MIN ( hak_intmax_t ) */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , v > HAK_TYPE_MIN ( hak_intmax_t ) ) ;
2018-02-05 10:43:25 +00:00
2019-08-13 07:15:12 +00:00
if ( v > = 0 )
{
ui = v ;
2025-09-02 23:58:15 +09:00
_class = hak - > c_large_positive_integer ;
2019-08-13 07:15:12 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
ui = ( v = = HAK_TYPE_MIN ( hak_intmax_t ) ) ? ( ( hak_uintmax_t ) HAK_TYPE_MAX ( hak_intmax_t ) + 1 ) : - v ;
_class = hak - > c_large_negative_integer ;
2019-08-13 07:15:12 +00:00
}
len = 0 ;
do
{
2025-09-02 23:58:15 +09:00
buf [ len + + ] = ( hak_liw_t ) ui ;
ui = ui > > HAK_LIW_BITS ;
2019-08-13 07:15:12 +00:00
}
while ( ui > 0 ) ;
2025-09-02 23:58:15 +09:00
return hak_instantiate ( hak , _class , buf , len ) ;
2019-08-13 07:15:12 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t make_bigint_with_uintmax ( hak_t * hak , hak_uintmax_t ui )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t len ;
hak_liw_t buf [ HAK_SIZEOF_INTMAX_T / HAK_SIZEOF_LIW_T ] ;
2019-08-13 07:15:12 +00:00
2018-02-05 10:43:25 +00:00
len = 0 ;
do
{
2025-09-02 23:58:15 +09:00
buf [ len + + ] = ( hak_liw_t ) ui ;
ui = ui > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
while ( ui > 0 ) ;
2025-09-02 23:58:15 +09:00
return make_pbigint ( hak , buf , len ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_oowtoint ( hak_t * hak , hak_oow_t w )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_TYPE_IS_UNSIGNED ( hak_oow_t ) ) ;
2025-09-02 23:58:15 +09:00
/*if (HAK_IN_SMOOI_RANGE(w))*/
if ( w < = HAK_SMOOI_MAX )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( w ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
return make_bigint_with_oow ( hak , w ) ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_ooitoint ( hak_t * hak , hak_ooi_t i )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( i ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( i ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
return make_bigint_with_ooi ( hak , i ) ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_UINTMAX_T == HAK_SIZEOF_OOW_T)
/* do nothing. required macros are defined in hak.h */
2021-03-25 16:53:05 +00:00
# else
2025-09-02 23:58:15 +09:00
hak_oop_t hak_intmaxtoint ( hak_t * hak , hak_intmax_t i )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( i ) )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( i ) ;
2019-08-13 07:15:12 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
return make_bigint_with_intmax ( hak , i ) ;
2019-08-13 07:15:12 +00:00
}
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_uintmaxtoint ( hak_t * hak , hak_uintmax_t i )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( i ) )
2019-08-13 07:15:12 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( i ) ;
2019-08-13 07:15:12 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
return make_bigint_with_uintmax ( hak , i ) ;
2019-08-13 07:15:12 +00:00
}
}
2021-03-25 16:53:05 +00:00
# endif
2019-08-13 07:15:12 +00:00
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t expand_bigint ( hak_t * hak , hak_oop_t oop , hak_oow_t inc )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i ;
hak_oow_t count ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OOP_IS_POINTER ( oop ) ) ;
2025-09-02 23:58:15 +09:00
count = HAK_OBJ_GET_SIZE ( oop ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( inc > HAK_OBJ_SIZE_MAX - count )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EOOMEM , " unable to expand bigint %O by %zu liwords " , oop , inc ) ; /* TODO: is it a soft failure or a hard failure? is this error code proper? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & oop ) ;
z = hak_instantiate ( hak , ( hak_oop_class_t ) HAK_OBJ_GET_CLASS ( oop ) , HAK_NULL , count + inc ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) )
2024-09-12 18:06:12 +09:00
{
2025-09-02 23:58:15 +09:00
const hak_ooch_t * orgmsg = hak_backuperrmsg ( hak ) ;
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_ERRNUM ( hak ) , " unable to clone bigint %O for expansion - %s " , oop , orgmsg ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2024-09-12 18:06:12 +09:00
}
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < count ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) oop ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
return z ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t _clone_bigint ( hak_t * hak , hak_oop_t oop , hak_oow_t count , hak_oop_class_t _class )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OOP_IS_POINTER ( oop ) ) ;
2025-09-02 23:58:15 +09:00
if ( count < = 0 ) count = HAK_OBJ_GET_SIZE ( oop ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & oop ) ;
z = hak_instantiate ( hak , _class , HAK_NULL , count ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < count ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) oop ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
return z ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t clone_bigint ( hak_t * hak , hak_oop_t oop , hak_oow_t count )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return _clone_bigint ( hak , oop , count , ( hak_oop_class_t ) HAK_OBJ_GET_CLASS ( oop ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t clone_bigint_negated ( hak_t * hak , hak_oop_t oop , hak_oow_t count )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_class_t _class ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_BIGINT ( hak , oop ) ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( HAK_IS_PBIGINT ( hak , oop ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
_class = hak - > c_large_negative_integer ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , oop ) ) ;
2025-09-02 23:58:15 +09:00
_class = hak - > c_large_positive_integer ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return _clone_bigint ( hak , oop , count , _class ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t clone_bigint_to_positive ( hak_t * hak , hak_oop_t oop , hak_oow_t count )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return _clone_bigint ( hak , oop , count , hak - > c_large_positive_integer ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oow_t count_effective ( hak_liw_t * x , hak_oow_t xs )
2018-02-05 10:43:25 +00:00
{
#if 0
while ( xs > 1 & & x [ xs - 1 ] = = 0 ) xs - - ;
return xs ;
# else
while ( xs > 1 ) { if ( x [ - - xs ] ) return xs + 1 ; }
return 1 ;
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oow_t count_effective_digits ( hak_oop_t oop )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
for ( i = HAK_OBJ_GET_SIZE ( oop ) ; i > 1 ; )
2018-02-05 10:43:25 +00:00
{
- - i ;
2025-09-02 23:58:15 +09:00
if ( ( ( hak_oop_liword_t ) oop ) - > slot [ i ] ) return i + 1 ;
2018-02-05 10:43:25 +00:00
}
return 1 ;
}
2025-09-02 23:58:15 +09:00
static hak_oop_t normalize_bigint ( hak_t * hak , hak_oop_t oop )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t count ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OOP_IS_POINTER ( oop ) ) ;
2024-09-20 12:00:18 +09:00
count = count_effective_digits ( oop ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2018-02-05 10:43:25 +00:00
if ( count = = 1 ) /* 1 word */
{
2025-09-02 23:58:15 +09:00
hak_oow_t w ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
w = ( ( hak_oop_liword_t ) oop ) - > slot [ 0 ] ;
if ( HAK_IS_PBIGINT ( hak , oop ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( w ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , - HAK_SMOOI_MAX = = HAK_SMOOI_MIN ) ;
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , oop ) ) ;
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( - ( hak_ooi_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
2018-02-05 10:43:25 +00:00
if ( count = = 1 ) /* 1 half-word */
{
2025-09-02 23:58:15 +09:00
if ( HAK_IS_PBIGINT ( hak , oop ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( ( ( hak_oop_liword_t ) oop ) - > slot [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , oop ) ) ;
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( - ( hak_ooi_t ) ( ( hak_oop_liword_t ) oop ) - > slot [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
}
}
else if ( count = = 2 ) /* 2 half-words */
{
2025-09-02 23:58:15 +09:00
hak_oow_t w ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
w = MAKE_WORD ( ( ( hak_oop_liword_t ) oop ) - > slot [ 0 ] , ( ( hak_oop_liword_t ) oop ) - > slot [ 1 ] ) ;
if ( HAK_IS_PBIGINT ( hak , oop ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( w ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , - HAK_SMOOI_MAX = = HAK_SMOOI_MIN ) ;
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , oop ) ) ;
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( - ( hak_ooi_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_SIZE ( oop ) = = count )
2018-02-05 10:43:25 +00:00
{
/* no compaction is needed. return it as it is */
return oop ;
}
2025-09-02 23:58:15 +09:00
return clone_bigint ( hak , oop , count ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_less_unsigned_array ( const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_less_unsigned ( hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
return is_less_unsigned_array (
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_less ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_CLASS ( x ) ! = HAK_OBJ_GET_CLASS ( y ) ) return HAK_IS_NBIGINT ( hak , x ) ;
if ( HAK_IS_PBIGINT ( hak , x ) ) return is_less_unsigned ( x , y ) ;
2024-09-20 03:14:48 +09:00
return is_less_unsigned ( y , x ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_greater_unsigned_array ( const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_greater_unsigned ( hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
return is_greater_unsigned_array (
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_greater ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_CLASS ( x ) ! = HAK_OBJ_GET_CLASS ( y ) ) return HAK_IS_NBIGINT ( hak , y ) ;
if ( HAK_IS_PBIGINT ( hak , x ) ) return is_greater_unsigned ( x , y ) ;
2024-09-20 03:14:48 +09:00
return is_greater_unsigned ( y , x ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_equal_unsigned_array ( const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys )
2019-02-20 17:38:56 +00:00
{
2025-09-02 23:58:15 +09:00
return xs = = ys & & HAK_MEMCMP ( x , y , xs * HAK_SIZEOF ( * x ) ) = = 0 ;
2019-02-20 17:38:56 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_equal_unsigned ( hak_oop_t x , hak_oop_t y )
2019-02-20 17:38:56 +00:00
{
return is_equal_unsigned_array (
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ) ;
2019-02-20 17:38:56 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE int is_equal ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
/* check if two large integers are equal to each other */
2025-09-02 23:58:15 +09:00
/*return HAK_OBJ_GET_CLASS(x) == HAK_OBJ_GET_CLASS(y) && HAK_OBJ_GET_SIZE(x) == HAK_OBJ_GET_SIZE(y) &&
HAK_MEMCMP ( ( ( hak_oop_liword_t ) x ) - > slot , ( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( x ) * HAK_SIZEOF ( hak_liw_t ) ) = = 0 ; */
return HAK_OBJ_GET_CLASS ( x ) = = HAK_OBJ_GET_CLASS ( y ) & & HAK_OBJ_GET_SIZE ( x ) = = HAK_OBJ_GET_SIZE ( y ) & & is_equal_unsigned ( x , y ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static void complement2_unsigned_array ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , hak_liw_t * z )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
hak_lidw_t w ;
hak_lidw_t carry ;
2018-02-05 10:43:25 +00:00
/* get 2's complement (~x + 1) */
2023-11-10 00:03:03 +09:00
carry = 1 ;
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ~ x [ i ] ) + carry ;
/*w = (hak_lidw_t)(x[i] ^ (~(hak_liw_t)0)) + carry;*/
carry = w > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +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
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +00:00
* this function is not designed to handle such a case .
2023-11-10 00:03:03 +09:00
* in fact , 0 is a small integer and it must not stand a change
2018-02-05 10:43:25 +00:00
* to be given to this function */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oow_t add_unsigned_array ( const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * z )
2018-02-05 10:43:25 +00:00
{
# if 1
2025-09-02 23:58:15 +09:00
register hak_oow_t i ;
hak_lidw_t w ;
2018-02-05 10:43:25 +00:00
if ( xs < ys )
{
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2025-09-02 23:58:15 +09:00
i = ( hak_oow_t ) x ;
2018-02-05 10:43:25 +00:00
x = y ;
2025-09-02 23:58:15 +09:00
y = ( hak_liw_t * ) i ;
2018-02-05 10:43:25 +00:00
}
w = 0 ;
i = 0 ;
while ( i < ys )
{
2025-09-02 23:58:15 +09:00
w + = ( hak_lidw_t ) x [ i ] + ( hak_lidw_t ) y [ i ] ;
z [ i + + ] = w & HAK_LBMASK ( hak_lidw_t , HAK_LIW_BITS ) ;
w > > = HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
while ( w & & i < xs )
{
w + = x [ i ] ;
2025-09-02 23:58:15 +09:00
z [ i + + ] = w & HAK_LBMASK ( hak_lidw_t , HAK_LIW_BITS ) ;
w > > = HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
while ( i < xs )
{
z [ i ] = x [ i ] ;
i + + ;
}
2025-09-02 23:58:15 +09:00
if ( w ) z [ i + + ] = w & HAK_LBMASK ( hak_lidw_t , HAK_LIW_BITS ) ;
2018-02-05 10:43:25 +00:00
return i ;
# else
2025-09-02 23:58:15 +09:00
register hak_oow_t i ;
hak_lidw_t w ;
hak_liw_t carry = 0 ;
2018-02-05 10:43:25 +00:00
if ( xs < ys )
{
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2025-09-02 23:58:15 +09:00
i = ( hak_oow_t ) x ;
2018-02-05 10:43:25 +00:00
x = y ;
2025-09-02 23:58:15 +09:00
y = ( hak_liw_t * ) i ;
2018-02-05 10:43:25 +00:00
}
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) x [ i ] + ( hak_lidw_t ) y [ i ] + carry ;
carry = w > > HAK_LIW_BITS ;
z [ i ] = w /*& HAK_LBMASK(hak_lidw_t, HAK_LIW_BITS) */ ;
2018-02-05 10:43:25 +00:00
}
if ( x = = z )
{
for ( ; carry & & i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) x [ i ] + carry ;
carry = w > > HAK_LIW_BITS ;
z [ i ] = w /*& HAK_LBMASK(hak_lidw_t, HAK_LIW_BITS) */ ;
2018-02-05 10:43:25 +00:00
}
i = xs ;
}
else
{
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) x [ i ] + carry ;
carry = w > > HAK_LIW_BITS ;
z [ i ] = w /*& HAK_LBMASK(hak_lidw_t, HAK_LIW_BITS)*/ ;
2018-02-05 10:43:25 +00:00
}
}
if ( carry ) z [ i + + ] = carry ;
return i ; /* the number of effective digits in the result */
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oow_t subtract_unsigned_array ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * z )
2018-02-05 10:43:25 +00:00
{
# if 1
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
hak_lidi_t w = 0 ;
2018-02-05 10:43:25 +00:00
if ( x = = y )
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xs = = ys ) ;
2018-02-05 10:43:25 +00:00
z [ 0 ] = 0 ;
return 1 ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! is_less_unsigned_array ( x , xs , y , ys ) ) ;
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w + = ( hak_lidi_t ) x [ i ] - ( hak_lidi_t ) y [ i ] ;
z [ i ] = w & HAK_LBMASK ( hak_lidw_t , HAK_LIW_BITS ) ;
w > > = HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
while ( w & & i < xs )
{
w + = x [ i ] ;
2025-09-02 23:58:15 +09:00
z [ i + + ] = w & HAK_LBMASK ( hak_lidw_t , HAK_LIW_BITS ) ;
w > > = HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
while ( i < xs )
{
z [ i ] = x [ i ] ;
i + + ;
}
while ( i > 1 & & z [ i - 1 ] = = 0 ) i - - ;
return i ;
# else
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
hak_lidw_t w ;
hak_lidw_t borrow = 0 ;
hak_lidw_t borrowed_word ;
2018-02-05 10:43:25 +00:00
if ( x = = y )
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xs = = ys ) ;
2018-02-05 10:43:25 +00:00
z [ 0 ] = 0 ;
return 1 ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! is_less_unsigned_array ( x , xs , y , ys ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
borrowed_word = ( hak_lidw_t ) 1 < < HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) y [ i ] + borrow ;
if ( ( hak_lidw_t ) x [ i ] > = w )
2018-02-05 10:43:25 +00:00
{
z [ i ] = x [ i ] - w ;
borrow = 0 ;
}
else
{
2025-09-02 23:58:15 +09:00
z [ i ] = ( borrowed_word + ( hak_lidw_t ) x [ i ] ) - w ;
2018-02-05 10:43:25 +00:00
borrow = 1 ;
}
}
for ( ; i < xs ; i + + )
{
2023-11-10 00:03:03 +09:00
if ( x [ i ] > = borrow )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
z [ i ] = x [ i ] - ( hak_liw_t ) borrow ;
2018-02-05 10:43:25 +00:00
borrow = 0 ;
}
else
{
2025-09-02 23:58:15 +09:00
z [ i ] = ( borrowed_word + ( hak_lidw_t ) x [ i ] ) - borrow ;
2018-02-05 10:43:25 +00:00
borrow = 1 ;
}
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , borrow = = 0 ) ;
2018-02-05 10:43:25 +00:00
while ( i > 1 & & z [ i - 1 ] = = 0 ) i - - ;
return i ; /* the number of effective digits in the result */
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE void multiply_unsigned_array ( const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * z )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_lidw_t v ;
hak_oow_t pa ;
2018-02-05 10:43:25 +00:00
if ( xs < ys )
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2025-09-02 23:58:15 +09:00
i = ( hak_oow_t ) x ;
2018-02-05 10:43:25 +00:00
x = y ;
2025-09-02 23:58:15 +09:00
y = ( hak_liw_t * ) i ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
if ( ys = = 1 )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
hak_oow_t i ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
z [ i ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
z [ i ] = carry ;
return ;
}
2018-02-05 10:43:25 +00:00
pa = xs ;
2025-09-02 23:58:15 +09:00
if ( pa < = ( ( hak_oow_t ) 1 < < ( HAK_LIDW_BITS - ( HAK_LIW_BITS * 2 ) ) ) )
2018-02-05 10:43:25 +00:00
{
/* Comba(column-array) multiplication */
/* 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 . */
2025-09-02 23:58:15 +09:00
hak_oow_t pa , ix , iy , iz , tx , ty ;
2018-02-05 10:43:25 +00:00
pa = xs + ys ;
v = 0 ;
for ( ix = 0 ; ix < pa ; ix + + )
{
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 + + )
{
2025-09-02 23:58:15 +09:00
v = v + ( hak_lidw_t ) x [ tx + iz ] * ( hak_lidw_t ) y [ ty - iz ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
z [ ix ] = ( hak_liw_t ) v ;
v = v > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
}
else
{
2025-09-02 23:58:15 +09:00
hak_oow_t i , j ;
hak_liw_t carry ;
2018-02-05 10:43:25 +00:00
for ( i = 0 ; i < xs ; i + + )
{
if ( x [ i ] = = 0 )
{
z [ i + ys ] = 0 ;
}
else
{
carry = 0 ;
for ( j = 0 ; j < ys ; j + + )
{
2025-09-02 23:58:15 +09:00
v = ( hak_lidw_t ) x [ i ] * ( hak_lidw_t ) y [ j ] + ( hak_lidw_t ) carry + ( hak_lidw_t ) z [ i + j ] ;
z [ i + j ] = ( hak_liw_t ) v ;
carry = ( hak_liw_t ) ( v > > HAK_LIW_BITS ) ;
2018-02-05 10:43:25 +00:00
}
z [ i + j ] = carry ;
}
}
}
}
/* KARATSUBA MULTIPLICATION
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +00:00
* 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 ) ) =
2023-11-10 00:03:03 +09:00
* A6FE0000 + 14 CC800 + 9 B5A = 9848635 A
2018-02-05 10:43:25 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* 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 .
2025-09-02 23:58:15 +09:00
* DIGIT_BITS in this implementation is HAK_LIW_BITS
* B = > 2 ^ HAK_LIW_BITS
* X * B ^ n = > X < < ( HAK_LIW_BITS * n )
* X * B ^ 2 n = > X < < ( HAK_LIW_BITS * n * 2 )
2018-02-05 10:43:25 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
# if defined(HAK_BUILD_DEBUG)
# define CANNOT_KARATSUBA(hak,xs,ys) \
2025-09-05 22:41:45 +09:00
( ( xs ) < ( hak ) - > option . karatsuba_cutoff | | ( ys ) < ( hak ) - > option . karatsuba_cutoff | | \
2018-02-05 10:43:25 +00:00
( ( xs ) > ( ys ) & & ( ys ) < = ( ( ( xs ) + 1 ) / 2 ) ) | | \
( ( xs ) < ( ys ) & & ( xs ) < = ( ( ( ys ) + 1 ) / 2 ) ) )
# else
2025-09-02 23:58:15 +09:00
# define CANNOT_KARATSUBA(hak,xs,ys) \
( ( xs ) < HAK_KARATSUBA_CUTOFF | | ( ys ) < HAK_KARATSUBA_CUTOFF | | \
2018-02-05 10:43:25 +00:00
( ( xs ) > ( ys ) & & ( ys ) < = ( ( ( xs ) + 1 ) / 2 ) ) | | \
( ( xs ) < ( ys ) & & ( xs ) < = ( ( ( ys ) + 1 ) / 2 ) ) )
# endif
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oow_t multiply_unsigned_array_karatsuba ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * z )
2018-02-05 10:43:25 +00:00
{
# if 1
2025-09-02 23:58:15 +09:00
hak_lidw_t nshifts ;
hak_lidw_t ndigits_xh , ndigits_xl ;
hak_lidw_t ndigits_yh , ndigits_yl ;
hak_liw_t * tmp [ 2 ] = { HAK_NULL , HAK_NULL } ;
hak_liw_t * zsp ;
hak_oow_t tmplen [ 2 ] ;
hak_oow_t xlen , zcapa ;
2018-02-05 10:43:25 +00:00
zcapa = xs + ys ; /* the caller ensures this capacity for z at the minimum*/
if ( xs < ys )
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2025-09-02 23:58:15 +09:00
i = ( hak_oow_t ) x ;
2018-02-05 10:43:25 +00:00
x = y ;
2025-09-02 23:58:15 +09:00
y = ( hak_liw_t * ) i ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
if ( ys = = 1 )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
hak_oow_t i ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
z [ i ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
z [ i ] = carry ;
return count_effective ( z , xs + 1 ) ;
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
/* calculate value of nshifts, that is 2^(HAK_LIW_BITS*nshifts) */
2018-02-05 10:43:25 +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 */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ndigits_xl > = ndigits_xh ) ;
HAK_ASSERT ( hak , ndigits_yl > = ndigits_yh ) ;
2018-02-05 10:43:25 +00:00
/* make a temporary buffer for (b0 + b1) and (a1 * b1) */
tmplen [ 0 ] = ndigits_xh + ndigits_yh ;
2023-11-10 00:03:03 +09:00
tmplen [ 1 ] = ndigits_yl + ndigits_yh + 1 ;
2018-02-05 10:43:25 +00:00
if ( tmplen [ 1 ] < tmplen [ 0 ] ) tmplen [ 1 ] = tmplen [ 0 ] ;
2025-09-02 23:58:15 +09:00
tmp [ 1 ] = ( hak_liw_t * ) hak_callocmem ( hak , HAK_SIZEOF ( hak_liw_t ) * tmplen [ 1 ] ) ; /* TODO: should i use the object memory? if not, reuse the buffer and minimize memory allocation */
if ( HAK_UNLIKELY ( ! tmp [ 1 ] ) ) goto oops ;
2018-02-05 10:43:25 +00:00
/* make a temporary for (a0 + a1) and (a0 * b0) */
tmplen [ 0 ] = ndigits_xl + ndigits_yl + 1 ;
2025-09-02 23:58:15 +09:00
tmp [ 0 ] = ( hak_liw_t * ) hak_callocmem ( hak , HAK_SIZEOF ( hak_liw_t ) * tmplen [ 0 ] ) ;
if ( HAK_UNLIKELY ( ! tmp [ 0 ] ) ) goto oops ;
2018-02-05 10:43:25 +00:00
/* tmp[0] = a0 + a1 */
2019-04-16 09:06:30 +00:00
tmplen [ 0 ] = add_unsigned_array ( x , ndigits_xl , x + nshifts , ndigits_xh , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
/* tmp[1] = b0 + b1 */
2019-04-16 09:06:30 +00:00
tmplen [ 1 ] = add_unsigned_array ( y , ndigits_yl , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
/*HAK_DEBUG6 (hak, "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);*/
/*HAK_DEBUG5 (hak, "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));*/
2018-02-05 10:43:25 +00:00
/* place (a0 + a1) * (b0 + b1) at the shifted position */
zsp = z + nshifts ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , tmplen [ 0 ] , tmplen [ 1 ] ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2019-04-16 09:06:30 +00:00
xlen = count_effective ( zsp , tmplen [ 0 ] + tmplen [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
xlen = multiply_unsigned_array_karatsuba ( hak , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2018-02-05 10:43:25 +00:00
if ( xlen = = 0 ) goto oops ;
}
/* tmp[0] = a0 * b0 */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( tmp [ 0 ] , 0 , sizeof ( hak_liw_t ) * tmplen [ 0 ] ) ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , ndigits_xl , ndigits_yl ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
tmplen [ 0 ] = count_effective ( tmp [ 0 ] , tmplen [ 0 ] ) ;
}
else
{
2025-09-02 23:58:15 +09:00
tmplen [ 0 ] = multiply_unsigned_array_karatsuba ( hak , x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
if ( tmplen [ 0 ] < = 0 ) goto oops ;
}
/* tmp[1] = a1 * b1 */
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( tmp [ 1 ] , 0 , sizeof ( hak_liw_t ) * tmplen [ 1 ] ) ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , ndigits_xh , ndigits_yh ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2019-04-16 09:06:30 +00:00
tmplen [ 1 ] = count_effective ( tmp [ 1 ] , tmplen [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
tmplen [ 1 ] = multiply_unsigned_array_karatsuba ( hak , x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
if ( tmplen [ 1 ] < = 0 ) goto oops ;
}
/* (a0+a1)*(b0+b1) -(a0*b0) */
2025-09-02 23:58:15 +09:00
xlen = subtract_unsigned_array ( hak , zsp , xlen , tmp [ 0 ] , tmplen [ 0 ] , zsp ) ;
2018-02-05 10:43:25 +00:00
/* (a0+a1)*(b0+b1) - (a0*b0) - (a1*b1) */
2025-09-02 23:58:15 +09:00
xlen = subtract_unsigned_array ( hak , zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2018-02-05 10:43:25 +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-16 09:06:30 +00:00
xlen = add_unsigned_array ( zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2018-02-05 10:43:25 +00:00
/* z = z + a0b0. a0b0 is in tmp[0] */
xlen = add_unsigned_array ( z , zcapa , tmp [ 0 ] , tmplen [ 0 ] , z ) ;
2025-09-05 10:52:02 +09:00
hak_freemem ( hak , tmp [ 1 ] ) ;
hak_freemem ( hak , tmp [ 0 ] ) ;
2024-09-20 12:00:18 +09:00
return count_effective ( z , xlen ) ;
2018-02-05 10:43:25 +00:00
oops :
2025-09-05 10:52:02 +09:00
if ( tmp [ 1 ] ) hak_freemem ( hak , tmp [ 1 ] ) ;
if ( tmp [ 0 ] ) hak_freemem ( hak , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
return 0 ;
# else
2025-09-02 23:58:15 +09:00
hak_lidw_t nshifts ;
hak_lidw_t ndigits_xh , ndigits_xl ;
hak_lidw_t ndigits_yh , ndigits_yl ;
hak_liw_t * tmp [ 3 ] = { HAK_NULL , HAK_NULL , HAK_NULL } ;
hak_liw_t * zsp ;
hak_oow_t tmplen [ 3 ] ;
hak_oow_t xlen , zcapa ;
2018-02-05 10:43:25 +00:00
zcapa = xs + ys ; /* the caller ensures this capacity for z at the minimum*/
if ( xs < ys )
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
/* swap x and y */
i = xs ;
xs = ys ;
ys = i ;
2025-09-02 23:58:15 +09:00
i = ( hak_oow_t ) x ;
2018-02-05 10:43:25 +00:00
x = y ;
2025-09-02 23:58:15 +09:00
y = ( hak_liw_t * ) i ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
if ( ys = = 1 )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
hak_oow_t i ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) x [ i ] * y [ 0 ] ) + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
z [ i ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
z [ i ] = carry ;
return ;
}
2025-09-02 23:58:15 +09:00
/* calculate value of nshifts, that is 2^(HAK_LIW_BITS*nshifts) */
2018-02-05 10:43:25 +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 */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ndigits_xl > = ndigits_xh ) ;
HAK_ASSERT ( hak , ndigits_yl > = ndigits_yh ) ;
2018-02-05 10:43:25 +00:00
/* make a temporary buffer for (b0 + b1) and (a1 * b1) */
2023-11-10 00:03:03 +09:00
tmplen [ 0 ] = ndigits_yl + ndigits_yh + 1 ;
2018-02-05 10:43:25 +00:00
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
if ( tmplen [ 1 ] < tmplen [ 0 ] ) tmplen [ 1 ] = tmplen [ 0 ] ;
2025-09-02 23:58:15 +09:00
tmp [ 1 ] = ( hak_liw_t * ) hak_callocmem ( hak , HAK_SIZEOF ( hak_liw_t ) * tmplen [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
if ( ! tmp [ 1 ] ) goto oops ;
/* make a temporary for (a0 + a1) and (a0 * b0) */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2025-09-02 23:58:15 +09:00
tmp [ 0 ] = ( hak_liw_t * ) hak_callocmem ( hak , HAK_SIZEOF ( hak_liw_t ) * tmplen [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
if ( ! tmp [ 0 ] ) goto oops ;
/* tmp[0] = a0 + a1 */
2019-04-16 09:06:30 +00:00
tmplen [ 0 ] = add_unsigned_array ( x , ndigits_xl , x + nshifts , ndigits_xh , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
/* tmp[1] = b0 + b1 */
2019-04-16 09:06:30 +00:00
tmplen [ 1 ] = add_unsigned_array ( y , ndigits_yl , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
/* tmp[2] = (a0 + a1) * (b0 + b1) */
2023-11-10 00:03:03 +09:00
tmplen [ 2 ] = tmplen [ 0 ] + tmplen [ 1 ] ;
2025-09-02 23:58:15 +09:00
tmp [ 2 ] = ( hak_liw_t * ) hak_callocmem ( hak , HAK_SIZEOF ( hak_liw_t ) * tmplen [ 2 ] ) ;
2018-02-05 10:43:25 +00:00
if ( ! tmp [ 2 ] ) goto oops ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , tmplen [ 0 ] , tmplen [ 1 ] ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , tmp [ 2 ] ) ;
2019-04-16 09:06:30 +00:00
xlen = count_effective ( tmp [ 2 ] , tmplen [ 2 ] ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
xlen = multiply_unsigned_array_karatsuba ( hak , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 1 ] , tmplen [ 1 ] , tmp [ 2 ] ) ;
2018-02-05 10:43:25 +00:00
if ( xlen = = 0 ) goto oops ;
}
/* tmp[0] = a0 * b0 */
tmplen [ 0 ] = ndigits_xl + ndigits_yl ;
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( tmp [ 0 ] , 0 , sizeof ( hak_liw_t ) * tmplen [ 0 ] ) ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , ndigits_xl , ndigits_yl ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
tmplen [ 0 ] = count_effective ( tmp [ 0 ] , tmplen [ 0 ] ) ;
}
else
{
2025-09-02 23:58:15 +09:00
tmplen [ 0 ] = multiply_unsigned_array_karatsuba ( hak , x , ndigits_xl , y , ndigits_yl , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
if ( tmplen [ 0 ] < = 0 ) goto oops ;
}
/* tmp[1] = a1 * b1 */
tmplen [ 1 ] = ndigits_xh + ndigits_yh ;
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( tmp [ 1 ] , 0 , sizeof ( hak_liw_t ) * tmplen [ 1 ] ) ;
2025-09-02 23:58:15 +09:00
if ( CANNOT_KARATSUBA ( hak , ndigits_xh , ndigits_yh ) )
2018-02-05 10:43:25 +00:00
{
multiply_unsigned_array ( x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2019-04-16 09:06:30 +00:00
tmplen [ 1 ] = count_effective ( tmp [ 1 ] , tmplen [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
tmplen [ 1 ] = multiply_unsigned_array_karatsuba ( hak , x + nshifts , ndigits_xh , y + nshifts , ndigits_yh , tmp [ 1 ] ) ;
2018-02-05 10:43:25 +00:00
if ( tmplen [ 1 ] < = 0 ) goto oops ;
}
/* w = w - tmp[0] */
2025-09-02 23:58:15 +09:00
xlen = subtract_unsigned_array ( hak , tmp [ 2 ] , xlen , tmp [ 0 ] , tmplen [ 0 ] , tmp [ 2 ] ) ;
2018-02-05 10:43:25 +00:00
/* r = w - tmp[1] */
zsp = z + nshifts ; /* emulate shifting for "* B^n" */
2025-09-02 23:58:15 +09:00
xlen = subtract_unsigned_array ( hak , tmp [ 2 ] , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2018-02-05 10:43:25 +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-16 09:06:30 +00:00
xlen = add_unsigned_array ( zsp , xlen , tmp [ 1 ] , tmplen [ 1 ] , zsp ) ;
2018-02-05 10:43:25 +00:00
/* z = z + a0b0. a0b0 is in tmp[0] */
xlen = add_unsigned_array ( z , zcapa , tmp [ 0 ] , tmplen [ 0 ] , z ) ;
2025-09-05 10:52:02 +09:00
hak_freemem ( hak , tmp [ 2 ] ) ;
hak_freemem ( hak , tmp [ 1 ] ) ;
hak_freemem ( hak , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
2019-04-16 09:06:30 +00:00
return count_effective ( z , xlen ) ;
2018-02-05 10:43:25 +00:00
oops :
2025-09-05 10:52:02 +09:00
if ( tmp [ 2 ] ) hak_freemem ( hak , tmp [ 2 ] ) ;
if ( tmp [ 1 ] ) hak_freemem ( hak , tmp [ 1 ] ) ;
if ( tmp [ 0 ] ) hak_freemem ( hak , tmp [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
return 0 ;
# endif
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE void lshift_unsigned_array ( hak_liw_t * x , hak_oow_t xs , hak_oow_t bits )
2018-02-05 10:43:25 +00:00
{
/* this function doesn't grow/shrink the array. Shifting is performed
* over the given array */
2025-09-02 23:58:15 +09:00
hak_oow_t word_shifts , bit_shifts , bit_shifts_right ;
hak_oow_t si , di ;
2018-02-05 10:43:25 +00:00
/* get how many words to shift */
2025-09-02 23:58:15 +09:00
word_shifts = bits / HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
if ( word_shifts > = xs )
{
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( x , 0 , xs * HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
return ;
}
/* get how many remaining bits to shift */
2025-09-02 23:58:15 +09:00
bit_shifts = bits % HAK_LIW_BITS ;
bit_shifts_right = HAK_LIW_BITS - bit_shifts ;
2018-02-05 10:43:25 +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 )
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( x , 0 , word_shifts * HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE void rshift_unsigned_array ( hak_liw_t * x , hak_oow_t xs , hak_oow_t bits )
2018-02-05 10:43:25 +00:00
{
/* this function doesn't grow/shrink the array. Shifting is performed
* over the given array */
2025-09-02 23:58:15 +09:00
hak_oow_t word_shifts , bit_shifts , bit_shifts_left ;
hak_oow_t si , di , bound ;
2018-02-05 10:43:25 +00:00
/* get how many words to shift */
2025-09-02 23:58:15 +09:00
word_shifts = bits / HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
if ( word_shifts > = xs )
{
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( x , 0 , xs * HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
return ;
}
/* get how many remaining bits to shift */
2025-09-02 23:58:15 +09:00
bit_shifts = bits % HAK_LIW_BITS ;
bit_shifts_left = HAK_LIW_BITS - bit_shifts ;
2018-02-05 10:43:25 +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 )
2025-09-05 10:52:02 +09:00
HAK_MEMSET ( & x [ xs - word_shifts ] , 0 , word_shifts * HAK_SIZEOF ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static void divide_unsigned_array ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * q , hak_liw_t * r )
2018-02-05 10:43:25 +00:00
{
2023-11-10 00:03:03 +09:00
/* TODO: this function needs to be rewritten for performance improvement.
2018-02-05 10:43:25 +00:00
* the binary long division is extremely slow for a big number */
/* Perform binary long division.
* http : //en.wikipedia.org/wiki/Division_algorithm
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Q : = 0 initialize quotient and remainder to zero
2023-11-10 00:03:03 +09:00
* R : = 0
2018-02-05 10:43:25 +00:00
* for i = n - 1. . .0 do where n is number of bits in N
2023-11-10 00:03:03 +09:00
* R : = R < < 1 left - shift R by 1 bit
2018-02-05 10:43:25 +00:00
* R ( 0 ) : = X ( i ) set the least - significant bit of R equal to bit i of the numerator
* if R > = Y then
2023-11-10 00:03:03 +09:00
* R = R - Y
2018-02-05 10:43:25 +00:00
* Q ( i ) : = 1
* end
2023-11-10 00:03:03 +09:00
* end
2018-02-05 10:43:25 +00:00
*/
2025-09-02 23:58:15 +09:00
hak_oow_t rs , rrs , i , j ;
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xs > = ys ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +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 */
2025-09-05 10:52:02 +09:00
/*HAK_MEMSET(q, 0, HAK_SIZEOF(*q) * xs);
HAK_MEMSET ( r , 0 , HAK_SIZEOF ( * q ) * ys ) ; */
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
rrs = ys + 1 ;
2018-02-05 10:43:25 +00:00
for ( i = xs ; i > 0 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
for ( j = HAK_LIW_BITS ; j > 0 ; )
2018-02-05 10:43:25 +00:00
{
- - j ;
2023-11-10 00:03:03 +09:00
/* the value of the remainder 'r' may get bigger than the
2019-04-16 09:06:30 +00:00
* divisor ' y ' temporarily until subtraction is performed
* below . so ys + 1 ( kept in rrs ) is needed for shifting here . */
2023-11-10 00:03:03 +09:00
lshift_unsigned_array ( r , rrs , 1 ) ;
2025-09-02 23:58:15 +09:00
HAK_SETBITS ( hak_liw_t , r [ 0 ] , 0 , 1 , HAK_GETBITS ( hak_liw_t , x [ i ] , j , 1 ) ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
rs = count_effective ( r , rrs ) ;
if ( ! is_less_unsigned_array ( r , rs , y , ys ) )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
subtract_unsigned_array ( hak , r , rs , y , ys , r ) ;
2025-09-02 23:58:15 +09:00
HAK_SETBITS ( hak_liw_t , q [ i ] , j , 1 , 1 ) ;
2018-02-05 10:43:25 +00:00
}
}
}
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_liw_t calculate_remainder ( hak_t * hak , hak_liw_t * qr , hak_liw_t * y , hak_liw_t quo , int qr_start , int stop )
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t b , c , c2 , qyk ;
hak_oow_t j , k ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( b = 0 , c = 0 , c2 = 0 , j = qr_start , k = 0 ; k < stop ; j + + , k + + )
{
2025-09-02 23:58:15 +09:00
dw = ( hak_lidw_t ) qr [ j ] - b ;
b = ( hak_liw_t ) ( ( dw > > HAK_LIW_BITS ) & 1 ) ; /* b = -(dw mod BASE) */
qr [ j ] = ( hak_liw_t ) dw ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) y [ k ] * quo ) + c ;
c = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
qyk = ( hak_liw_t ) dw ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
dw = ( hak_lidw_t ) qr [ j ] - qyk ;
c2 = ( hak_liw_t ) ( ( dw > > HAK_LIW_BITS ) & 1 ) ;
qr [ j ] = ( hak_liw_t ) dw ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
dw = ( hak_lidw_t ) b + c2 + c ;
c = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
b = ( hak_liw_t ) dw ;
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , c = = 0 ) ;
2019-04-16 09:06:30 +00:00
}
return b ;
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
static void divide_unsigned_array2 ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * q , hak_liw_t * r )
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t i ;
hak_liw_t d , y1 , y2 ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* the caller must ensure:
2023-11-10 00:03:03 +09:00
* - q can hold ' xs + 1 ' words and r can hold ' ys ' words .
2019-04-16 09:06:30 +00:00
* - q and r are set to all zeros . */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xs > = ys ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
if ( ys = = 1 )
{
/* the divisor has a single word only. perform simple division */
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
2019-04-16 09:06:30 +00:00
for ( i = xs ; i > 0 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) carry < < HAK_LIW_BITS ) + x [ i ] ;
q [ i ] = ( hak_liw_t ) ( dw / y [ 0 ] ) ;
carry = ( hak_liw_t ) ( dw % y [ 0 ] ) ;
2019-04-16 09:06:30 +00:00
}
r [ 0 ] = carry ;
return ;
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +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 */
for ( i = 0 ; i < ys ; i + + ) r [ i ] = y [ i ] ; /* copy y to r */
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
y1 = r [ ys - 1 ] ; /* highest divisor word */
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
/*d = (y1 == HAK_TYPE_MAX(hak_liw_t)? ((hak_liw_t)1): ((hak_liw_t)(((hak_lidw_t)1 << HAK_LIW_BITS) / (y1 + 1))));*/
d = ( hak_liw_t ) ( ( ( hak_lidw_t ) 1 < < HAK_LIW_BITS ) / ( ( hak_lidw_t ) y1 + 1 ) ) ;
2019-04-16 09:06:30 +00:00
if ( d > 1 )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* shift the divisor such that its high-order bit is on.
* shift the dividend the same amount as the previous step */
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* r = r * d */
for ( carry = 0 , i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) r [ i ] * d ) + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
r [ i ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* q = q * d */
for ( carry = 0 , i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) q [ i ] * d ) + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
q [ i ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
q [ xs ] = carry ;
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
y1 = r [ ys - 1 ] ;
y2 = r [ ys - 2 ] ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = xs ; i > = ys ; - - i )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw , quo , rem ;
hak_liw_t b , xhi , xlo ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* ---------------------------------------------------------- */
/* estimate the quotient.
* 2 - current - dividend - words / 2 - most - significant - divisor - words */
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
xhi = q [ i ] ;
xlo = q [ i - 1 ] ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* adjust the quotient if over-estimated */
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) xhi < < HAK_LIW_BITS ) + xlo ;
2019-04-16 09:06:30 +00:00
/* TODO: optimize it with ASM - no seperate / and % */
quo = dw / y1 ;
rem = dw % y1 ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
adjust_quotient :
2025-09-02 23:58:15 +09:00
if ( quo > HAK_TYPE_MAX ( hak_liw_t ) | | ( quo * y2 ) > ( ( rem < < HAK_LIW_BITS ) + q [ i - 2 ] ) )
2019-04-16 09:06:30 +00:00
{
- - quo ;
rem + = y1 ;
2025-09-02 23:58:15 +09:00
if ( rem < = HAK_TYPE_MAX ( hak_liw_t ) ) goto adjust_quotient ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* ---------------------------------------------------------- */
2025-09-02 23:58:15 +09:00
b = calculate_remainder ( hak , q , r , quo , i - ys , ys ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
b = ( hak_liw_t ) ( ( ( ( hak_lidw_t ) xhi - b ) > > HAK_LIW_BITS ) & 1 ) ; /* is the sign bit set? */
2019-04-16 09:06:30 +00:00
if ( b )
{
/* yes. underflow */
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry ;
hak_oow_t j , k ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( carry = 0 , j = i - ys , k = 0 ; k < ys ; j + + , k + + )
{
2025-09-02 23:58:15 +09:00
dw = ( hak_lidw_t ) q [ j ] + r [ k ] + carry ;
carry = ( hak_liw_t ) ( dw > > HAK_LIW_BITS ) ;
q [ j ] = ( hak_liw_t ) dw ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 1 ) ;
2019-04-16 09:06:30 +00:00
q [ i ] = quo - 1 ;
}
else
{
q [ i ] = quo ;
}
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
if ( d > 1 )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry ;
2019-04-16 09:06:30 +00:00
for ( carry = 0 , i = ys ; i > 0 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) carry < < HAK_LIW_BITS ) + q [ i ] ;
2019-04-16 09:06:30 +00:00
/* TODO: optimize it with ASM - no seperate / and % */
2025-09-02 23:58:15 +09:00
q [ i ] = ( hak_liw_t ) ( dw / d ) ;
carry = ( hak_liw_t ) ( dw % d ) ;
2019-04-16 09:06:30 +00:00
}
}
2023-11-10 00:03:03 +09:00
/* split quotient and remainder held in q to q and r respectively
2019-04-16 09:06:30 +00:00
* 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 ; }
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
static void divide_unsigned_array3 ( hak_t * hak , const hak_liw_t * x , hak_oow_t xs , const hak_liw_t * y , hak_oow_t ys , hak_liw_t * q , hak_liw_t * r )
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t s , i , j , g , k ;
hak_lidw_t dw , qhat , rhat ;
hak_lidi_t di , ci ;
hak_liw_t * qq , y1 , y2 ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* the caller must ensure:
2023-11-10 00:03:03 +09:00
* - q can hold ' xs + 1 ' words and r can hold ' ys ' words .
2019-04-16 09:06:30 +00:00
* - q and r are set to all zeros . */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xs > = ys ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
if ( ys = = 1 )
{
/* the divisor has a single word only. perform simple division */
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
2019-04-16 09:06:30 +00:00
for ( i = xs ; i > 0 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) carry < < HAK_LIW_BITS ) + x [ i ] ;
q [ i ] = ( hak_liw_t ) ( dw / y [ 0 ] ) ;
carry = ( hak_liw_t ) ( dw % y [ 0 ] ) ;
2019-04-16 09:06:30 +00:00
}
r [ 0 ] = carry ;
return ;
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
# define SHARED_QQ
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
# 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 */
2025-09-02 23:58:15 +09:00
if ( hak - > inttostr . t . capa < = xs )
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
hak_liw_t * t ;
hak_oow_t reqcapa ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
reqcapa = HAK_ALIGN_POW2 ( xs + 1 , 32 ) ;
t = ( hak_liw_t * ) hak_reallocmem ( hak , hak - > inttostr . t . ptr , reqcapa * HAK_SIZEOF ( * t ) ) ;
2019-04-16 09:06:30 +00:00
/* TODO: TODO: TODO: ERROR HANDLING
if ( ! t ) return - 1 ; */
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
hak - > inttostr . t . capa = xs + 1 ;
hak - > inttostr . t . ptr = t ;
2019-04-16 09:06:30 +00:00
}
2025-09-02 23:58:15 +09:00
qq = hak - > inttostr . t . ptr ;
2019-04-16 09:06:30 +00:00
# endif
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
y1 = y [ ys - 1 ] ;
2025-09-02 23:58:15 +09:00
/*s = HAK_LIW_BITS - ((y1 == 0)? -1: hak_get_pos_of_msb_set(y1)) - 1;*/
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , y1 > 0 ) ; /* the highest word can't be non-zero in the context where this function is called */
2025-09-02 23:58:15 +09:00
s = HAK_LIW_BITS - hak_get_pos_of_msb_set ( y1 ) - 1 ;
2019-04-16 09:06:30 +00:00
for ( i = ys ; i > 1 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
r [ i ] = ( y [ i ] < < s ) | ( ( hak_lidw_t ) y [ i - 1 ] > > ( HAK_LIW_BITS - s ) ) ;
2019-04-16 09:06:30 +00:00
}
r [ 0 ] = y [ 0 ] < < s ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
qq [ xs ] = ( hak_lidw_t ) x [ xs - 1 ] > > ( HAK_LIW_BITS - s ) ;
2019-04-16 09:06:30 +00:00
for ( i = xs ; i > 1 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
qq [ i ] = ( x [ i ] < < s ) | ( ( hak_lidw_t ) x [ i - 1 ] > > ( HAK_LIW_BITS - s ) ) ;
2019-04-16 09:06:30 +00:00
}
qq [ 0 ] = x [ 0 ] < < s ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
y1 = r [ ys - 1 ] ;
y2 = r [ ys - 2 ] ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( j = xs ; j > = ys ; - - j )
{
g = j - ys ; /* position where remainder begins in qq */
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* estimate */
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) qq [ j ] < < HAK_LIW_BITS ) + qq [ j - 1 ] ;
2019-04-16 09:06:30 +00:00
qhat = dw / y1 ;
rhat = dw - ( qhat * y1 ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
adjust_quotient :
2025-09-02 23:58:15 +09:00
if ( qhat > HAK_TYPE_MAX ( hak_liw_t ) | | ( qhat * y2 ) > ( ( rhat < < HAK_LIW_BITS ) + qq [ j - 2 ] ) )
2019-04-16 09:06:30 +00:00
{
qhat = qhat - 1 ;
rhat = rhat + y1 ;
2025-09-02 23:58:15 +09:00
if ( rhat < = HAK_TYPE_MAX ( hak_liw_t ) ) goto adjust_quotient ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* multiply and subtract */
for ( ci = 0 , i = g , k = 0 ; k < ys ; i + + , k + + )
{
dw = qhat * r [ k ] ;
2025-09-02 23:58:15 +09:00
di = qq [ i ] - ci - ( dw & HAK_TYPE_MAX ( hak_liw_t ) ) ;
ci = ( dw > > HAK_LIW_BITS ) - ( di > > HAK_LIW_BITS ) ;
qq [ i ] = ( hak_liw_t ) di ;
2019-04-16 09:06:30 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , i = = j ) ;
2019-04-16 09:06:30 +00:00
di = qq [ i ] - ci ;
qq [ i ] = di ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* test remainder */
if ( di < 0 )
{
for ( ci = 0 , i = g , k = 0 ; k < ys ; i + + , k + + )
{
2025-09-02 23:58:15 +09:00
di = ( hak_lidw_t ) qq [ i ] + r [ k ] + ci ;
ci = ( hak_liw_t ) ( di > > HAK_LIW_BITS ) ;
qq [ i ] = ( hak_liw_t ) di ;
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , i = = j ) ;
/*HAK_ASSERT(hak, ci == 1);*/
2019-04-16 09:06:30 +00:00
qq [ i ] + = ci ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
# if defined(SHARED_QQ)
/* store the quotient word right after the remainder in q */
q [ i + 1 ] = qhat - 1 ;
# else
q [ g ] = qhat - 1 ;
# endif
}
else
{
# if defined(SHARED_QQ)
/* store the quotient word right after the remainder in q */
q [ i + 1 ] = qhat ;
# else
q [ g ] = qhat ;
# endif
}
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = 0 ; i < ys - 1 ; i + + )
{
2025-09-02 23:58:15 +09:00
r [ i ] = ( qq [ i ] > > s ) | ( ( hak_lidw_t ) qq [ i + 1 ] < < ( HAK_LIW_BITS - s ) ) ;
2019-04-16 09:06:30 +00:00
}
r [ i ] = qq [ i ] > > s ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +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 ; }
# endif
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* ======================================================================== */
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
static hak_oop_t add_unsigned_integers ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oow_t as , bs , zs ;
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
as = HAK_OBJ_GET_SIZE ( x ) ;
bs = HAK_OBJ_GET_SIZE ( y ) ;
2018-02-05 10:43:25 +00:00
zs = ( as > = bs ? as : bs ) ;
2025-09-02 23:58:15 +09:00
if ( zs > = HAK_OBJ_SIZE_MAX )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* TOOD: is it a soft failure or hard failure? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
zs + + ;
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = hak_instantiate ( hak , ( hak_oop_class_t ) HAK_OBJ_GET_CLASS ( x ) , HAK_NULL , zs ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
add_unsigned_array (
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , as ,
( ( hak_oop_liword_t ) y ) - > slot , bs ,
( ( hak_oop_liword_t ) z ) - > slot
2018-02-05 10:43:25 +00:00
) ;
return z ;
}
2025-09-02 23:58:15 +09:00
static hak_oop_t subtract_unsigned_integers ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! is_less_unsigned ( x , y ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( x ) ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
subtract_unsigned_array ( hak ,
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ,
( ( hak_oop_liword_t ) z ) - > slot ) ;
2018-02-05 10:43:25 +00:00
return z ;
}
2025-09-02 23:58:15 +09:00
static hak_oop_t multiply_unsigned_integers ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t xs , ys ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
ys = HAK_OBJ_GET_SIZE ( y ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ys > HAK_OBJ_SIZE_MAX - xs )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* TOOD: is it a soft failure or hard failure? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = make_pbigint ( hak , HAK_NULL , xs + ys ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if defined(HAK_ENABLE_KARATSUBA)
if ( CANNOT_KARATSUBA ( hak , xs , ys ) )
2018-02-05 10:43:25 +00:00
{
# endif
multiply_unsigned_array (
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ,
( ( hak_oop_liword_t ) z ) - > slot ) ;
# if defined(HAK_ENABLE_KARATSUBA)
2018-02-05 10:43:25 +00:00
}
else
{
if ( multiply_unsigned_array_karatsuba (
2025-09-02 23:58:15 +09:00
hak ,
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ,
( ( hak_oop_liword_t ) z ) - > slot ) = = 0 ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
# endif
return z ;
}
2025-09-02 23:58:15 +09:00
static hak_oop_t divide_unsigned_integers ( hak_t * hak , hak_oop_t x , hak_oop_t y , hak_oop_t * r )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t qq , rr ;
2018-02-05 10:43:25 +00:00
2019-02-20 17:38:56 +00:00
if ( is_less_unsigned ( x , y ) )
{
2025-09-02 23:58:15 +09:00
rr = clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
if ( HAK_UNLIKELY ( ! rr ) ) return HAK_NULL ;
2019-02-20 17:38:56 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & rr ) ;
qq = make_bigint_with_ooi ( hak , 0 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
hak_popvolat ( hak ) ;
2019-02-20 17:38:56 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_LIKELY ( qq ) ) * r = rr ;
2019-02-20 17:38:56 +00:00
return qq ;
}
else if ( is_equal_unsigned ( x , y ) )
{
2025-09-02 23:58:15 +09:00
rr = make_bigint_with_ooi ( hak , 0 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
if ( HAK_UNLIKELY ( ! rr ) ) return HAK_NULL ;
2019-02-20 17:38:56 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & rr ) ;
qq = make_bigint_with_ooi ( hak , 1 ) ; /* TODO: inefficient. no need to create a bigint object for zero. */
hak_popvolat ( hak ) ;
2019-02-20 17:38:56 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_LIKELY ( qq ) ) * r = rr ;
2019-02-20 17:38:56 +00:00
return qq ;
}
2018-02-05 10:43:25 +00:00
/* the caller must ensure that x >= y */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! is_less_unsigned ( x , y ) ) ;
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
2019-04-16 09:06:30 +00:00
# define USE_DIVIDE_UNSIGNED_ARRAY2
/*#define USE_DIVIDE_UNSIGNED_ARRAY3*/
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
2025-09-02 23:58:15 +09:00
qq = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( x ) + 2 ) ;
2019-04-16 09:06:30 +00:00
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
2025-09-02 23:58:15 +09:00
qq = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( x ) + 1 ) ;
2019-04-16 09:06:30 +00:00
# else
2025-09-02 23:58:15 +09:00
qq = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( x ) ) ;
2019-04-16 09:06:30 +00:00
# endif
2025-09-02 23:58:15 +09:00
if ( HAK_UNLIKELY ( ! qq ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_popvolats ( hak , 2 ) ;
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & qq ) ;
2019-04-16 09:06:30 +00:00
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
2025-09-02 23:58:15 +09:00
rr = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( y ) ) ;
2019-04-16 09:06:30 +00:00
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
2025-09-02 23:58:15 +09:00
rr = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( y ) ) ;
2019-04-16 09:06:30 +00:00
# else
2025-09-02 23:58:15 +09:00
rr = make_pbigint ( hak , HAK_NULL , HAK_OBJ_GET_SIZE ( y ) + 1 ) ;
2019-04-16 09:06:30 +00:00
# endif
2025-09-02 23:58:15 +09:00
hak_popvolats ( hak , 3 ) ;
if ( HAK_UNLIKELY ( ! rr ) ) return HAK_NULL ;
2019-04-16 09:06:30 +00:00
# if defined(USE_DIVIDE_UNSIGNED_ARRAY3)
2025-09-02 23:58:15 +09:00
divide_unsigned_array3 ( hak ,
2019-04-16 09:06:30 +00:00
# elif defined(USE_DIVIDE_UNSIGNED_ARRAY2)
2025-09-02 23:58:15 +09:00
divide_unsigned_array2 ( hak ,
2019-04-16 09:06:30 +00:00
# else
2025-09-05 10:52:02 +09:00
divide_unsigned_array ( hak ,
2019-04-16 09:06:30 +00:00
# endif
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) x ) - > slot , HAK_OBJ_GET_SIZE ( x ) ,
( ( hak_oop_liword_t ) y ) - > slot , HAK_OBJ_GET_SIZE ( y ) ,
( ( hak_oop_liword_t ) qq ) - > slot , ( ( hak_oop_liword_t ) rr ) - > slot
2024-09-20 12:00:18 +09:00
) ;
2018-02-05 10:43:25 +00:00
* r = rr ;
return qq ;
}
2019-04-16 09:06:30 +00:00
/* ======================================================================== */
2025-09-02 23:58:15 +09:00
hak_oop_t hak_addints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t i ;
2018-02-05 10:43:25 +00:00
/* no integer overflow/underflow must occur as the possible integer
* range is narrowed by the tag bits used */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_SMOOI_MAX + HAK_SMOOI_MAX < HAK_TYPE_MAX ( hak_ooi_t ) ) ;
HAK_ASSERT ( hak , HAK_SMOOI_MIN + HAK_SMOOI_MIN > HAK_TYPE_MIN ( hak_ooi_t ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
i = HAK_OOP_TO_SMOOI ( x ) + HAK_OOP_TO_SMOOI ( y ) ;
if ( HAK_IN_SMOOI_RANGE ( i ) ) return HAK_SMOOI_TO_OOP ( i ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
return make_bigint_with_ooi ( hak , i ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return clone_bigint ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
y = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! y ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_CLASS ( x ) ! = HAK_OBJ_GET_CLASS ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_IS_NBIGINT ( hak , x ) )
2018-02-05 10:43:25 +00:00
{
/* x is negative, y is positive */
2024-09-20 12:00:18 +09:00
if ( is_less_unsigned ( x , y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
z = subtract_unsigned_integers ( hak , y , x ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
z = subtract_unsigned_integers ( hak , x , y ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
}
else
{
/* x is positive, y is negative */
2024-09-20 03:14:48 +09:00
if ( is_less_unsigned ( x , y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
z = subtract_unsigned_integers ( hak , y , x ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
z = subtract_unsigned_integers ( hak , x , y ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
}
}
else
{
int neg ;
/* both are positive or negative */
2025-09-02 23:58:15 +09:00
neg = HAK_IS_NBIGINT ( hak , x ) ;
z = add_unsigned_integers ( hak , x , y ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( neg ) HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_subints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t i ;
2018-02-05 10:43:25 +00:00
/* no integer overflow/underflow must occur as the possible integer
* range is narrowed by the tag bits used */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_SMOOI_MAX - HAK_SMOOI_MIN < HAK_TYPE_MAX ( hak_ooi_t ) ) ;
HAK_ASSERT ( hak , HAK_SMOOI_MIN - HAK_SMOOI_MAX > HAK_TYPE_MIN ( hak_ooi_t ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
i = HAK_OOP_TO_SMOOI ( x ) - HAK_OOP_TO_SMOOI ( y ) ;
if ( HAK_IN_SMOOI_RANGE ( i ) ) return HAK_SMOOI_TO_OOP ( i ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
return make_bigint_with_ooi ( hak , i ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
int neg ;
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2023-11-10 00:03:03 +09:00
if ( v = = 0 )
2018-02-05 10:43:25 +00:00
{
/* switch the sign to the opposite and return it */
2025-09-02 23:58:15 +09:00
return clone_bigint_negated ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
y = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! y ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_OBJ_GET_CLASS ( x ) ! = HAK_OBJ_GET_CLASS ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
neg = HAK_IS_NBIGINT ( hak , x ) ;
z = add_unsigned_integers ( hak , x , y ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( neg ) HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else
{
/* both are positive or negative */
2024-09-20 03:14:48 +09:00
if ( is_less_unsigned ( x , y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
neg = HAK_IS_NBIGINT ( hak , x ) ;
z = subtract_unsigned_integers ( hak , y , x ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( ! neg ) HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
neg = HAK_IS_NBIGINT ( hak , x ) ;
z = subtract_unsigned_integers ( hak , x , y ) ; /* take x's sign */
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( neg ) HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
}
}
2025-09-05 10:52:02 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_mulints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
# if (HAK_SIZEOF_INTMAX_T > HAK_SIZEOF_OOI_T)
hak_intmax_t i ;
i = ( hak_intmax_t ) HAK_OOP_TO_SMOOI ( x ) * ( hak_intmax_t ) HAK_OOP_TO_SMOOI ( y ) ;
if ( HAK_IN_SMOOI_RANGE ( i ) ) return HAK_SMOOI_TO_OOP ( ( hak_ooi_t ) i ) ;
return make_bigint_with_intmax ( hak , i ) ;
2018-02-05 10:43:25 +00:00
# else
2025-09-02 23:58:15 +09:00
hak_ooi_t i ;
hak_ooi_t xv , yv ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
xv = HAK_OOP_TO_SMOOI ( x ) ;
yv = HAK_OOP_TO_SMOOI ( y ) ;
if ( shaki_mul_overflow ( hak , xv , yv , & i ) )
2018-02-05 10:43:25 +00:00
{
/* overflowed - convert x and y normal objects and carry on */
2025-09-02 23:58:15 +09:00
/* no need to call hak_pushvolat before creating x because
2018-02-05 10:43:25 +00:00
* xv and yv contains actual values needed */
2025-09-02 23:58:15 +09:00
x = make_bigint_with_ooi ( hak , xv ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ; /* protect x made above */
y = make_bigint_with_ooi ( hak , yv ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! y ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2019-04-16 09:06:30 +00:00
goto full_multiply ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( i ) ) return HAK_SMOOI_TO_OOP ( i ) ;
return make_bigint_with_ooi ( hak , i ) ;
2018-02-05 10:43:25 +00:00
}
# endif
}
else
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-12-28 08:09:01 +00:00
int neg ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2018-02-05 10:43:25 +00:00
switch ( v )
{
case 0 :
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
case 1 :
2025-09-02 23:58:15 +09:00
return clone_bigint ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
case - 1 :
2025-09-02 23:58:15 +09:00
return clone_bigint_negated ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
switch ( v )
{
case 0 :
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
case 1 :
2025-09-02 23:58:15 +09:00
return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
case - 1 :
2025-09-02 23:58:15 +09:00
return clone_bigint_negated ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
2025-09-05 10:52:02 +09:00
y = make_bigint_with_ooi ( hak , v ) ;
2025-09-02 23:58:15 +09:00
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! y ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
full_multiply :
2025-09-02 23:58:15 +09:00
neg = ( HAK_OBJ_GET_CLASS ( x ) ! = HAK_OBJ_GET_CLASS ( y ) ) ;
z = multiply_unsigned_integers ( hak , x , y ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( neg ) HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_divints ( hak_t * hak , hak_oop_t x , hak_oop_t y , int modulo , hak_oop_t * rem )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z , r ;
2019-04-16 09:06:30 +00:00
int x_neg_sign , y_neg_sign ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t xv , yv , q , ri ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
xv = HAK_OOP_TO_SMOOI ( x ) ;
yv = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
if ( yv = = 0 )
{
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EDIVBY0 ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
if ( xv = = 0 )
{
2025-09-02 23:58:15 +09:00
if ( rem ) * rem = HAK_SMOOI_TO_OOP ( 0 ) ;
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
}
/* In C89, integer division with a negative number is
* implementation dependent . In C99 , it truncates towards zero .
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +00:00
* http : //python-history.blogspot.kr/2010/08/why-pythons-integer-division-floors.html
2023-11-10 00:03:03 +09:00
* The integer division operation ( //) and its sibling,
2018-02-05 10:43:25 +00:00
* the modulo operation ( % ) , go together and satisfy a nice
* mathematical relationship ( all variables are integers ) :
* a / b = q with remainder r
* such that
* b * q + r = a and 0 < = r < b ( assuming - a and b are > = 0 ) .
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +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
2023-11-10 00:03:03 +09:00
* towards negative infinity , and the invariant remains 0 < = r < b .
2018-02-05 10:43:25 +00:00
*/
q = xv / yv ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( q ) ) ;
2018-02-05 10:43:25 +00:00
2019-03-25 13:01:05 +00:00
ri = xv - yv * q ; /* xv % yv; */
if ( ri )
2018-02-05 10:43:25 +00:00
{
if ( modulo )
{
/* modulo */
/*
xv yv q r
- - - - - - - - - - - - - - - - - - - - - - - - -
7 3 2 1
- 7 3 - 3 2
7 - 3 - 3 - 2
- 7 - 3 2 - 1
*/
2023-11-10 00:03:03 +09:00
/* r must be floored. that is, it rounds away from zero
2018-02-05 10:43:25 +00:00
* and towards negative infinity */
2019-03-25 13:01:05 +00:00
if ( IS_SIGN_DIFF ( yv , ri ) )
2018-02-05 10:43:25 +00:00
{
/* if the divisor has a different sign from r,
* change the sign of r to the divisor ' s sign */
2019-03-25 13:01:05 +00:00
ri + = yv ;
2018-02-05 10:43:25 +00:00
- - q ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ri & & ! IS_SIGN_DIFF ( yv , ri ) ) ;
2018-02-05 10:43:25 +00:00
}
}
else
{
/* remainder */
/*
xv yv q r
- - - - - - - - - - - - - - - - - - - - - - - - -
7 3 2 1
- 7 3 - 2 - 1
7 - 3 - 2 1
- 7 - 3 2 - 1
*/
2023-11-10 00:03:03 +09:00
if ( xv & & IS_SIGN_DIFF ( xv , ri ) )
2018-02-05 10:43:25 +00:00
{
/* if the dividend has a different sign from r,
* 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-25 13:01:05 +00:00
ri - = yv ;
2018-02-05 10:43:25 +00:00
+ + q ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , xv & & ! IS_SIGN_DIFF ( xv , ri ) ) ;
2018-02-05 10:43:25 +00:00
}
}
}
if ( rem )
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IN_SMOOI_RANGE ( ri ) ) ;
2025-09-02 23:58:15 +09:00
* rem = HAK_SMOOI_TO_OOP ( ri ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( ( hak_ooi_t ) q ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t xv ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2023-11-10 00:03:03 +09:00
/* divide a small integer by a big integer.
2019-04-16 09:06:30 +00:00
* the dividend is guaranteed to be greater than the divisor
* if both are positive . */
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
xv = HAK_OOP_TO_SMOOI ( x ) ;
2019-04-16 09:06:30 +00:00
x_neg_sign = ( xv < 0 ) ;
2025-09-02 23:58:15 +09:00
y_neg_sign = HAK_IS_NBIGINT ( hak , y ) ;
2019-04-16 09:06:30 +00:00
if ( x_neg_sign = = y_neg_sign | | ! modulo )
2018-02-05 10:43:25 +00:00
{
2019-04-16 09:06:30 +00:00
/* simple. the quotient is zero and the
* dividend becomes the remainder as a whole . */
if ( rem ) * rem = x ;
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
/* carry on to the full bigint division */
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , xv ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t yv ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2019-04-16 09:06:30 +00:00
/* divide a big integer by a small integer. */
2025-09-02 23:58:15 +09:00
yv = HAK_OOP_TO_SMOOI ( y ) ;
2019-03-25 13:01:05 +00:00
switch ( yv )
2018-02-05 10:43:25 +00:00
{
case 0 :
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EDIVBY0 ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
case 1 :
2025-09-02 23:58:15 +09:00
z = clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( rem ) * rem = HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
return z ;
case - 1 :
2025-09-02 23:58:15 +09:00
z = clone_bigint_negated ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
if ( rem ) * rem = HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
return z ;
default :
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
hak_lidw_t dw ;
hak_liw_t carry = 0 ;
hak_liw_t * zw ;
hak_oow_t zs , i ;
hak_ooi_t yv_abs , ri ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
yv_abs = ( yv < 0 ) ? - yv : yv ;
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS < HAK_OOI_BITS)
if ( yv_abs > HAK_TYPE_MAX ( hak_liw_t ) ) break ;
2019-04-16 09:06:30 +00:00
# endif
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
x_neg_sign = ( HAK_IS_NBIGINT ( hak , x ) ) ;
2019-04-16 09:06:30 +00:00
y_neg_sign = ( yv < 0 ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
z = clone_bigint_to_positive ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
zw = ( ( hak_oop_liword_t ) z ) - > slot ;
zs = HAK_OBJ_GET_SIZE ( z ) ;
2019-04-16 09:06:30 +00:00
for ( i = zs ; i > 0 ; )
2018-02-05 10:43:25 +00:00
{
2019-04-16 09:06:30 +00:00
- - i ;
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) carry < < HAK_LIW_BITS ) + zw [ i ] ;
2019-04-16 09:06:30 +00:00
/* TODO: optimize it with ASM - no seperate / and % */
2025-09-02 23:58:15 +09:00
zw [ i ] = ( hak_liw_t ) ( dw / yv_abs ) ;
carry = ( hak_liw_t ) ( dw % yv_abs ) ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
/*if (zw[zs - 1] == 0) zs--;*/
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry < = HAK_SMOOI_MAX ) ;
2019-04-16 09:06:30 +00:00
ri = carry ;
if ( x_neg_sign ) ri = - ri ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
z = normalize_bigint ( hak , z ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
if ( x_neg_sign ! = y_neg_sign )
2019-03-25 13:01:05 +00:00
{
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2019-04-16 09:06:30 +00:00
if ( ri & & modulo )
2019-03-25 13:01:05 +00:00
{
2025-09-02 23:58:15 +09:00
z = hak_subints ( hak , z , HAK_SMOOI_TO_OOP ( 1 ) ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2019-04-16 09:06:30 +00:00
if ( rem )
2019-03-25 13:01:05 +00:00
{
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & z ) ;
r = hak_addints ( hak , HAK_SMOOI_TO_OOP ( ri ) , HAK_SMOOI_TO_OOP ( yv ) ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! r ) ) return HAK_NULL ;
2019-03-25 13:01:05 +00:00
* rem = r ;
}
return z ;
}
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( rem ) * rem = HAK_SMOOI_TO_OOP ( ri ) ;
2019-04-16 09:06:30 +00:00
return z ;
}
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
/* carry on to the full bigint division */
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
y = make_bigint_with_ooi ( hak , yv ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! y ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
x_neg_sign = HAK_IS_NBIGINT ( hak , x ) ;
y_neg_sign = HAK_IS_NBIGINT ( hak , y ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = divide_unsigned_integers ( hak , x , y , & r ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2023-11-10 00:03:03 +09:00
if ( x_neg_sign )
2018-02-05 10:43:25 +00:00
{
2023-11-10 00:03:03 +09:00
/* the class on r must be set before normalize_bigint()
2018-02-05 10:43:25 +00:00
* because it can get changed to a small integer */
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( r , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
2019-04-16 09:06:30 +00:00
if ( x_neg_sign ! = y_neg_sign )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & z ) ;
hak_pushvolat ( hak , & y ) ;
r = normalize_bigint ( hak , r ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! r ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( r ! = HAK_SMOOI_TO_OOP ( 0 ) & & modulo )
2018-02-05 10:43:25 +00:00
{
if ( rem )
{
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & z ) ;
hak_pushvolat ( hak , & y ) ;
r = hak_addints ( hak , r , y ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! r ) ) return HAK_NULL ;
hak_pushvolat ( hak , & r ) ;
z = normalize_bigint ( hak , z ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
hak_pushvolat ( hak , & r ) ;
z = hak_subints ( hak , z , HAK_SMOOI_TO_OOP ( 1 ) ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
* rem = r ;
return z ;
}
else
{
/* remainder is not needed at all */
/* TODO: subtract 1 without normalization??? */
2025-09-02 23:58:15 +09:00
z = normalize_bigint ( hak , z ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
return hak_subints ( hak , z , HAK_SMOOI_TO_OOP ( 1 ) ) ;
2018-02-05 10:43:25 +00:00
}
}
}
else
{
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & z ) ;
r = normalize_bigint ( hak , r ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! r ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & r ) ;
z = normalize_bigint ( hak , z ) ;
hak_popvolat ( hak ) ;
2020-10-25 05:51:44 +00:00
if ( z & & rem ) * rem = r ;
return z ;
2018-02-05 10:43:25 +00:00
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_negateint ( hak_t * hak , hak_oop_t x )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
v = HAK_OOP_TO_SMOOI ( x ) ;
return HAK_SMOOI_TO_OOP ( - v ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2025-09-05 10:52:02 +09:00
return clone_bigint_negated ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O " , x ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitatint ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
/* y is 0-based */
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v1 , v2 , v3 ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v1 = HAK_OOP_TO_SMOOI ( x ) ;
v2 = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( v2 < 0 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
if ( v1 > = 0 )
{
2023-11-10 00:03:03 +09:00
/* the absolute value may be composed of up to
2025-09-02 23:58:15 +09:00
* HAK_SMOOI_BITS - 1 bits as there is a sign bit . */
if ( v2 > = HAK_SMOOI_BITS - 1 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
v3 = ( ( hak_oow_t ) v1 > > v2 ) & 1 ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
if ( v2 > = HAK_SMOOI_BITS - 1 ) return HAK_SMOOI_TO_OOP ( 1 ) ;
v3 = ( ( ~ ( hak_oow_t ) - v1 + 1 ) > > v2 ) & 1 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( v3 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_IS_NBIGINT ( hak , y ) ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
/* y is definitely >= HAK_SMOOI_BITS */
if ( HAK_OOP_TO_SMOOI ( x ) > = 0 )
return HAK_SMOOI_TO_OOP ( 0 ) ;
2023-11-10 00:03:03 +09:00
else
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 1 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
hak_oow_t wp , bp , xs ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
v = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( v < 0 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
wp = v / HAK_LIW_BITS ;
bp = v - ( wp * HAK_LIW_BITS ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
if ( HAK_IS_PBIGINT ( hak , x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( wp > = xs ) return HAK_SMOOI_TO_OOP ( 0 ) ;
v = ( ( ( hak_oop_liword_t ) x ) - > slot [ wp ] > > bp ) & 1 ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( wp > = xs ) return HAK_SMOOI_TO_OOP ( 1 ) ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < = wp ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
v = ( ( hak_oow_t ) w > > bp ) & 1 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( v ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
# if defined(HAK_LIMIT_OBJ_SIZE)
2018-02-05 10:43:25 +00:00
/* nothing */
# else
2025-09-02 23:58:15 +09:00
hak_oow_t w , wp , bp , xs ;
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
int sign ;
# endif
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if defined(HAK_LIMIT_OBJ_SIZE)
if ( HAK_IS_NBIGINT ( hak , y ) ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_SIZE_BITS_MAX < = HAK_TYPE_MAX ( hak_oow_t ) ) ;
2025-09-02 23:58:15 +09:00
if ( HAK_IS_PBIGINT ( hak , x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 1 ) ;
2018-02-05 10:43:25 +00:00
}
# else
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_IS_NBIGINT ( hak , y ) ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
sign = bigint_to_oow_noseterr ( hak , y , & w ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign > = 0 ) ;
2018-02-05 10:43:25 +00:00
if ( sign > = 1 )
{
2025-09-02 23:58:15 +09:00
wp = w / HAK_LIW_BITS ;
bp = w - ( wp * HAK_LIW_BITS ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t quo , rem ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign = = 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
quo = hak_divints ( hak , y , HAK_SMOOI_TO_OOP ( HAK_LIW_BITS ) , 0 , & rem ) ;
hak_popvolat ( hak ) ;
if ( ! quo ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
sign = integer_to_oow_noseterr ( hak , quo , & wp ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign > = 0 ) ;
2018-02-05 10:43:25 +00:00
if ( sign = = 0 )
{
/* too large. set it to xs so that it gets out of
* the valid range */
wp = xs ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OOP_IS_SMOOI ( rem ) ) ;
2025-09-02 23:58:15 +09:00
bp = HAK_OOP_TO_SMOOI ( rem ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , bp > = 0 & & bp < HAK_LIW_BITS ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
if ( HAK_IS_PBIGINT ( hak , x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( wp > = xs ) return HAK_SMOOI_TO_OOP ( 0 ) ;
v = ( ( ( hak_oop_liword_t ) x ) - > slot [ wp ] > > bp ) & 1 ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
hak_oow_t i ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( wp > = xs ) return HAK_SMOOI_TO_OOP ( 1 ) ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < = wp ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
v = ( ( hak_oow_t ) w > > bp ) & 1 ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( v ) ;
2018-02-05 10:43:25 +00:00
# endif
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitandints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v1 , v2 , v3 ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v1 = HAK_OOP_TO_SMOOI ( x ) ;
v2 = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
v3 = v1 & v2 ;
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( v3 ) ) return HAK_SMOOI_TO_OOP ( v3 ) ;
2025-09-05 10:52:02 +09:00
return make_bigint_with_ooi ( hak , v3 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
2025-09-05 10:52:02 +09:00
y = make_bigint_with_ooi ( hak , v ) ;
2025-09-02 23:58:15 +09:00
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i , xs , ys , zs , zalloc ;
2018-02-05 10:43:25 +00:00
int negx , negy ;
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
bigint_and_bigint :
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
ys = HAK_OBJ_GET_SIZE ( y ) ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
negx = HAK_IS_NBIGINT ( hak , x ) ;
negy = HAK_IS_NBIGINT ( hak , y ) ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = make_pbigint ( hak , HAK_NULL , zalloc ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
if ( negx & & negy )
{
/* both are negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w [ 2 ] ;
hak_lidw_t carry [ 2 ] ;
2018-02-05 10:43:25 +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 + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
w [ 1 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry [ 1 ] ;
carry [ 1 ] = w [ 1 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] & ( hak_liw_t ) w [ 1 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 1 ] = = 0 ) ;
2018-02-05 10:43:25 +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 + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 0 ] = = 0 ) ;
2018-02-05 10:43:25 +00:00
/* 2's complement on the final result */
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ zs ] = ~ ( hak_liw_t ) 0 ;
2018-02-05 10:43:25 +00:00
carry [ 0 ] = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) z ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 0 ] = = 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else if ( negx )
{
/* x is negative, y is positive */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w & ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +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 )
{
/* x is positive, y is negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] & ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
/* handle the longer part in x than y
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +00:00
* For example ,
* x = > + 1010 1100
* y = > - 0011
2023-11-10 00:03:03 +09:00
*
* If y is extended to the same length as x ,
* it is a negative 0000 0001.
2018-02-05 10:43:25 +00:00
* 2 ' s complement is performed on this imaginary extension .
* the result is ' 1111 1101 ' ( 1111 1100 + 1 ) .
2023-11-10 00:03:03 +09:00
*
2018-02-05 10:43:25 +00:00
* when y is shorter and negative , the lacking part can be
* treated as all 1 s in the 2 ' s complement format .
2023-11-10 00:03:03 +09:00
*
* the remaining part in x can be just copied to the
2018-02-05 10:43:25 +00:00
* final result ' z ' .
*/
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
}
else
{
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] & ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitorints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v1 , v2 , v3 ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v1 = HAK_OOP_TO_SMOOI ( x ) ;
v2 = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
v3 = v1 | v2 ;
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( v3 ) ) return HAK_SMOOI_TO_OOP ( v3 ) ;
return make_bigint_with_ooi ( hak , v3 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return clone_bigint ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
y = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i , xs , ys , zs , zalloc ;
2018-02-05 10:43:25 +00:00
int negx , negy ;
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
bigint_and_bigint :
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
ys = HAK_OBJ_GET_SIZE ( y ) ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
negx = HAK_IS_NBIGINT ( hak , x ) ;
negy = HAK_IS_NBIGINT ( hak , y ) ;
2018-02-05 10:43:25 +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 ;
}
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = make_pbigint ( hak , HAK_NULL , zalloc ) ;
hak_popvolats ( hak , 2 ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
if ( negx & & negy )
{
/* both are negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w [ 2 ] ;
hak_lidw_t carry [ 2 ] ;
2018-02-05 10:43:25 +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 + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
w [ 1 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry [ 1 ] ;
carry [ 1 ] = w [ 1 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] | ( hak_liw_t ) w [ 1 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 1 ] = = 0 ) ;
2018-02-05 10:43:25 +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 */
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ zs ] = ~ ( hak_liw_t ) 0 ;
2018-02-05 10:43:25 +00:00
carry [ 0 ] = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) z ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 0 ] = = 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else if ( negx )
{
/* x is negative, y is positive */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w | ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
goto adjust_to_negative ;
}
else if ( negy )
{
/* x is positive, y is negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] | ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +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 ' .
2023-11-10 00:03:03 +09:00
* setting zs to ' xs + 1 ' and performing the following loop is
2018-02-05 10:43:25 +00:00
* redundant .
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ~ ( hak_liw_t ) 0 ;
2018-02-05 10:43:25 +00:00
}
*/
goto adjust_to_negative ;
}
else
{
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] | ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitxorints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v1 , v2 , v3 ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v1 = HAK_OOP_TO_SMOOI ( x ) ;
v2 = HAK_OOP_TO_SMOOI ( y ) ;
2018-02-05 10:43:25 +00:00
v3 = v1 ^ v2 ;
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( v3 ) ) return HAK_SMOOI_TO_OOP ( v3 ) ;
2025-09-05 10:52:02 +09:00
return make_bigint_with_ooi ( hak , v3 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return clone_bigint ( hak , y , HAK_OBJ_GET_SIZE ( y ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
2025-09-05 10:52:02 +09:00
x = make_bigint_with_ooi ( hak , v ) ;
2025-09-02 23:58:15 +09:00
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
2025-09-05 10:52:02 +09:00
y = make_bigint_with_ooi ( hak , v ) ;
2025-09-02 23:58:15 +09:00
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i , xs , ys , zs , zalloc ;
2018-02-05 10:43:25 +00:00
int negx , negy ;
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
bigint_and_bigint :
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
ys = HAK_OBJ_GET_SIZE ( y ) ;
2018-02-05 10:43:25 +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 ;
}
2025-09-02 23:58:15 +09:00
negx = HAK_IS_NBIGINT ( hak , x ) ;
negy = HAK_IS_NBIGINT ( hak , y ) ;
2018-02-05 10:43:25 +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 ;
}
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & y ) ;
z = make_pbigint ( hak , HAK_NULL , zalloc ) ;
hak_popvolats ( hak , 2 ) ;
if ( ! z ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
if ( negx & & negy )
{
/* both are negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w [ 2 ] ;
hak_lidw_t carry [ 2 ] ;
2018-02-05 10:43:25 +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 + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
w [ 1 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry [ 1 ] ;
carry [ 1 ] = w [ 1 ] > > HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] ^ ( hak_liw_t ) w [ 1 ] ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 1 ] = = 0 ) ;
2018-02-05 10:43:25 +00:00
/* treat the lacking part in y as all 1s */
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w [ 0 ] = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry [ 0 ] ;
carry [ 0 ] = w [ 0 ] > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w [ 0 ] ^ ( ~ ( hak_liw_t ) 0 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry [ 0 ] = = 0 ) ;
2018-02-05 10:43:25 +00:00
}
else if ( negx )
{
/* x is negative, y is positive */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w ^ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
/* treat the lacking part in y as all 0s */
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
adjust_to_negative :
/* 2's complement on the final result */
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ zs ] = ~ ( hak_liw_t ) 0 ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) z ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
else if ( negy )
{
/* x is positive, y is negative */
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
/* x & 2's complement on y up to ys */
carry = 1 ;
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ^ ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
/* treat the lacking part in y as all 1s */
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ^ ( ~ ( hak_liw_t ) 0 ) ;
2018-02-05 10:43:25 +00:00
}
goto adjust_to_negative ;
}
else
{
/* both are positive */
for ( i = 0 ; i < ys ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ^ ( ( hak_oop_liword_t ) y ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
/* treat the lacking part in y as all 0s */
for ( ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( ( hak_oop_liword_t ) x ) - > slot [ i ] ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitinvint ( hak_t * hak , hak_oop_t x )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2018-02-05 10:43:25 +00:00
v = ~ v ;
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( v ) ) return HAK_SMOOI_TO_OOP ( v ) ;
2025-09-05 10:52:02 +09:00
return make_bigint_with_ooi ( hak , v ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t i , xs , zs , zalloc ;
2018-02-05 10:43:25 +00:00
int negx ;
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
negx = HAK_IS_NBIGINT ( hak , x ) ;
2018-02-05 10:43:25 +00:00
if ( negx )
{
zalloc = xs ;
zs = xs ;
}
else
{
zalloc = xs + 1 ;
zs = xs ;
}
if ( zalloc < zs )
{
/* overflow in zalloc calculation above */
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* TODO: is it a soft failure or hard failure? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
z = make_pbigint ( hak , HAK_NULL , zalloc ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
if ( negx )
{
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ HAK_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
carry = w > > HAK_LIW_BITS ;
HAK_OBJ_SET_LIWORD_VAL ( z , i , ~ ( hak_liw_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
hak_lidw_t w , carry ;
2018-02-05 10:43:25 +00:00
#if 0
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , i , ~ HAK_OBJ_GET_LIWORD_VAL ( x , i ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , zs , ~ ( hak_liw_t ) 0 ) ;
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < = zs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ HAK_OBJ_GET_LIWORD_VAL ( z , i ) ) + carry ;
carry = w > > HAK_LIW_BITS ;
HAK_OBJ_SET_LIWORD_VAL ( z , i , ( hak_liw_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
# else
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( HAK_OBJ_GET_LIWORD_VAL ( x , i ) ) + carry ;
carry = w > > HAK_LIW_BITS ;
HAK_OBJ_SET_LIWORD_VAL ( z , i , ( hak_liw_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , i = = zs ) ;
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , i , ( hak_liw_t ) carry ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ( carry > > HAK_LIW_BITS ) = = 0 ) ;
2018-02-05 10:43:25 +00:00
# endif
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_CLASS ( z , ( hak_oop_t ) hak - > c_large_negative_integer ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O " , x ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t rshift_negative_bigint ( hak_t * hak , hak_oop_t x , hak_oow_t shift )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_lidw_t w ;
hak_lidw_t carry ;
hak_oow_t i , xs ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , x ) ) ;
2025-09-02 23:58:15 +09:00
xs = HAK_OBJ_GET_SIZE ( x ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
2018-02-05 10:43:25 +00:00
/* +1 for the second inversion below */
2025-09-02 23:58:15 +09:00
z = make_nbigint ( hak , HAK_NULL , xs + 1 ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
/* the following lines roughly for 'z = hak_bitinv(hak, x)' */
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) x ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
HAK_OBJ_SET_LIWORD_VAL ( z , i , ~ ( hak_liw_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
/* shift to the right */
2025-09-02 23:58:15 +09:00
rshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , xs , shift ) ;
2018-02-05 10:43:25 +00:00
2025-09-05 10:52:02 +09:00
/* the following lines roughly for 'z = hak_bitinv(hak, z)' */
2018-02-05 10:43:25 +00:00
#if 0
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , i , ~ HAK_OBJ_GET_LIWORD_VAL ( z , i ) ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , xs , ~ ( hak_liw_t ) 0 ) ;
2019-08-13 07:15:12 +00:00
2018-02-05 10:43:25 +00:00
carry = 1 ;
for ( i = 0 ; i < = xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( hak_liw_t ) ~ ( ( hak_oop_liword_t ) z ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
HAK_OBJ_SET_LIWORD_VAL ( z , i , ( hak_liw_t ) w ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , carry = = 0 ) ;
2018-02-05 10:43:25 +00:00
# else
carry = 1 ;
for ( i = 0 ; i < xs ; i + + )
{
2025-09-02 23:58:15 +09:00
w = ( hak_lidw_t ) ( ( ( hak_oop_liword_t ) z ) - > slot [ i ] ) + carry ;
carry = w > > HAK_LIW_BITS ;
( ( hak_oop_liword_t ) z ) - > slot [ i ] = ( hak_liw_t ) w ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
HAK_OBJ_SET_LIWORD_VAL ( z , i , ( hak_liw_t ) carry ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ( carry > > HAK_LIW_BITS ) = = 0 ) ;
2018-02-05 10:43:25 +00:00
# endif
return z ; /* z is not normalized */
}
2025-09-02 23:58:15 +09:00
# if defined(HAK_LIMIT_OBJ_SIZE)
2018-02-05 10:43:25 +00:00
/* nothing */
# else
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t rshift_negative_bigint_and_normalize ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t shift ;
2018-02-05 10:43:25 +00:00
int sign ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , x ) ) ;
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , y ) ) ;
2018-02-05 10:43:25 +00:00
2023-11-10 00:03:03 +09:00
/* for convenience in subtraction below.
2025-09-02 23:58:15 +09:00
* it could be HAK_TYPE_MAX ( hak_oow_t )
2018-02-05 10:43:25 +00:00
* if make_bigint_with_intmax ( ) or something
2025-09-02 23:58:15 +09:00
* similar were used instead of HAK_SMOOI_TO_OOP ( ) . */
shift = HAK_SMOOI_MAX ;
2018-02-05 10:43:25 +00:00
do
{
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
z = rshift_negative_bigint ( hak , x , shift ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
/* y is a negative number. use hak_addints() until it becomes 0 */
hak_pushvolat ( hak , & z ) ;
y = hak_addints ( hak , y , HAK_SMOOI_TO_OOP ( shift ) ) ;
hak_popvolat ( hak ) ;
if ( ! y ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
sign = integer_to_oow_noseterr ( hak , y , & shift ) ;
if ( sign = = 0 ) shift = HAK_SMOOI_MAX ;
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
if ( shift = = 0 )
{
/* no more shift */
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign < = - 1 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = normalize_bigint ( hak , z ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
/* for normaization above, x can become a small integer */
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , v < 0 ) ;
2018-02-05 10:43:25 +00:00
/* normal right shift of a small negative integer */
2025-09-02 23:58:15 +09:00
if ( shift > = HAK_OOI_BITS - 1 )
2018-02-05 10:43:25 +00:00
{
/* when y is still a large integer, this condition is met
2025-09-02 23:58:15 +09:00
* met as HAK_SMOOI_MAX > HAK_OOI_BITS . so i can simly
2018-02-05 10:43:25 +00:00
* terminate the loop after this */
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( - 1 ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
v = ( hak_ooi_t ) ( ( ( hak_oow_t ) v > > shift ) | HAK_HBMASK ( hak_oow_t , shift ) ) ;
if ( HAK_IN_SMOOI_RANGE ( v ) )
return HAK_SMOOI_TO_OOP ( v ) ;
2023-11-10 00:03:03 +09:00
else
2025-09-05 10:52:02 +09:00
return make_bigint_with_ooi ( hak , v ) ;
2018-02-05 10:43:25 +00:00
}
}
}
while ( 1 ) ;
/* this part must not be reached */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! " internal error - must not happen " ) ;
hak_seterrnum ( hak , HAK_EINTERN ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t rshift_positive_bigint_and_normalize ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t zs , shift ;
2018-02-05 10:43:25 +00:00
int sign ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_PBIGINT ( hak , x ) ) ;
HAK_ASSERT ( hak , HAK_IS_NBIGINT ( hak , y ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
zs = HAK_OBJ_GET_SIZE ( x ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
z = clone_bigint ( hak , x , zs ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2023-11-10 00:03:03 +09:00
/* for convenience in subtraction below.
2025-09-02 23:58:15 +09:00
* it could be HAK_TYPE_MAX ( hak_oow_t )
2018-02-05 10:43:25 +00:00
* if make_bigint_with_intmax ( ) or something
2025-09-02 23:58:15 +09:00
* similar were used instead of HAK_SMOOI_TO_OOP ( ) . */
shift = HAK_SMOOI_MAX ;
2018-02-05 10:43:25 +00:00
do
{
2025-09-02 23:58:15 +09:00
rshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , zs , shift ) ;
if ( count_effective ( ( ( hak_oop_liword_t ) z ) - > slot , zs ) = = 1 & &
HAK_OBJ_GET_LIWORD_VAL ( z , 0 ) = = 0 )
2018-02-05 10:43:25 +00:00
{
/* if z is 0, i don't have to go on */
break ;
}
2025-09-02 23:58:15 +09:00
/* y is a negative number. use hak_addints() until it becomes 0 */
hak_pushvolat ( hak , & z ) ;
y = hak_addints ( hak , y , HAK_SMOOI_TO_OOP ( shift ) ) ;
hak_popvolat ( hak ) ;
if ( ! y ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
sign = integer_to_oow_noseterr ( hak , y , & shift ) ;
if ( sign = = 0 ) shift = HAK_SMOOI_MAX ;
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
if ( shift = = 0 ) break ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign < = - 1 ) ;
2018-02-05 10:43:25 +00:00
}
}
while ( 1 ) ;
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_oop_t lshift_bigint_and_normalize ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t wshift , shift ;
2018-02-05 10:43:25 +00:00
int sign ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_IS_PBIGINT ( hak , y ) ) ;
2018-02-05 10:43:25 +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
2023-11-10 00:03:03 +09:00
* memory available is certainly not enough to support
2025-09-02 23:58:15 +09:00
* huge shifts greater than HAK_TYPE_MAX ( hak_oow_t ) */
shift = HAK_SMOOI_MAX ;
2018-02-05 10:43:25 +00:00
do
{
2023-11-10 00:03:03 +09:00
/* for convenience only in subtraction below.
2025-09-02 23:58:15 +09:00
* should it be between HAK_SMOOI_MAX and HAK_TYPE_MAX ( hak_oow_t ) ,
* the second parameter to hak_subints ( ) can ' t be composed
* using HAK_SMOOI_TO_OOP ( ) */
wshift = shift / HAK_LIW_BITS ;
if ( shift > wshift * HAK_LIW_BITS ) wshift + + ;
hak_pushvolat ( hak , & y ) ;
z = expand_bigint ( hak , x , wshift ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
lshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , HAK_OBJ_GET_SIZE ( z ) , shift ) ;
hak_pushvolat ( hak , & y ) ;
x = normalize_bigint ( hak , z ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
hak_pushvolat ( hak , & x ) ;
y = hak_subints ( hak , y , HAK_SMOOI_TO_OOP ( shift ) ) ;
hak_popvolat ( hak ) ;
if ( ! y ) return HAK_NULL ;
sign = integer_to_oow_noseterr ( hak , y , & shift ) ;
if ( sign = = 0 ) shift = HAK_SMOOI_MAX ;
2018-02-05 10:43:25 +00:00
else
{
2023-11-10 00:03:03 +09:00
if ( shift = = 0 )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , is_normalized_integer ( hak , x ) ) ;
2018-02-05 10:43:25 +00:00
return x ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign > = 1 ) ;
2018-02-05 10:43:25 +00:00
}
}
while ( 1 ) ;
/* this part must not be reached */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ! " internal error - must not happen " ) ;
hak_seterrnum ( hak , HAK_EINTERN ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
# endif
2025-09-02 23:58:15 +09:00
hak_oop_t hak_bitshiftint ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
/* left shift if y is positive,
* right shift if y is negative */
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v1 , v2 ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v1 = HAK_OOP_TO_SMOOI ( x ) ;
v2 = HAK_OOP_TO_SMOOI ( y ) ;
2023-11-10 00:03:03 +09:00
if ( v1 = = 0 | | v2 = = 0 )
2018-02-05 10:43:25 +00:00
{
/* return without cloning as x is a small integer */
2023-11-10 00:03:03 +09:00
return x ;
2018-02-05 10:43:25 +00:00
}
if ( v2 > 0 )
{
/* left shift */
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
hak_oow_t wshift ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
wshift = v2 / HAK_LIW_BITS ;
if ( v2 > wshift * HAK_LIW_BITS ) wshift + + ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
z = make_bloated_bigint_with_ooi ( hak , v1 , wshift ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
lshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , HAK_OBJ_GET_SIZE ( z ) , v2 ) ;
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
else
{
/* right shift */
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +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
*/
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( v2 > = HAK_OOI_BITS - 1 ) v = - 1 ;
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
/* HAK_HBMASK_SAFE(hak_oow_t, v2 + 1) could also be
2023-11-10 00:03:03 +09:00
* used as a mask . but the sign bit is shifted in .
2018-02-05 10:43:25 +00:00
* so , masking up to ' v2 ' bits is sufficient */
2025-09-02 23:58:15 +09:00
v = ( hak_ooi_t ) ( ( ( hak_oow_t ) v1 > > v2 ) | HAK_HBMASK ( hak_oow_t , v2 ) ) ;
2018-02-05 10:43:25 +00:00
}
}
else
{
2025-09-02 23:58:15 +09:00
if ( v2 > = HAK_OOI_BITS ) v = 0 ;
2018-02-05 10:43:25 +00:00
else v = v1 > > v2 ;
}
2025-09-02 23:58:15 +09:00
if ( HAK_IN_SMOOI_RANGE ( v ) ) return HAK_SMOOI_TO_OOP ( v ) ;
2025-09-05 10:52:02 +09:00
return make_bigint_with_ooi ( hak , v ) ;
2018-02-05 10:43:25 +00:00
}
}
else
{
int sign , negx , negy ;
2025-09-02 23:58:15 +09:00
hak_oow_t shift ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( x ) ;
if ( v = = 0 ) return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( HAK_IS_NBIGINT ( hak , y ) )
2018-02-05 10:43:25 +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
2025-09-02 23:58:15 +09:00
* is HAK_SMOOI_MAX . i know the final answer . */
return ( v < 0 ) ? HAK_SMOOI_TO_OOP ( - 1 ) : HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & y ) ;
x = make_bigint_with_ooi ( hak , v ) ;
hak_popvolat ( hak ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
goto bigint_and_bigint ;
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = HAK_OOP_TO_SMOOI ( y ) ;
if ( v = = 0 ) return clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
negx = HAK_IS_NBIGINT ( hak , x ) ;
2018-02-05 10:43:25 +00:00
if ( v > 0 )
{
sign = 1 ;
negy = 0 ;
shift = v ;
goto bigint_and_positive_oow ;
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
sign = - 1 ;
negy = 1 ;
shift = - v ;
goto bigint_and_negative_oow ;
}
}
else
{
2025-09-02 23:58:15 +09:00
hak_oop_t z ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
bigint_and_bigint :
2025-09-02 23:58:15 +09:00
negx = HAK_IS_NBIGINT ( hak , x ) ;
negy = HAK_IS_NBIGINT ( hak , y ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
sign = bigint_to_oow_noseterr ( hak , y , & shift ) ;
2018-02-05 10:43:25 +00:00
if ( sign = = 0 )
{
/* y is too big or too small */
if ( negy )
{
/* right shift */
2025-09-02 23:58:15 +09:00
# if defined(HAK_LIMIT_OBJ_SIZE)
2018-02-05 10:43:25 +00:00
/* the maximum number of bit shifts are guaranteed to be
2025-09-02 23:58:15 +09:00
* small enough to fit into the hak_oow_t type . so i can
2018-02-05 10:43:25 +00:00
* easily assume that all bits are shifted out */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_OBJ_SIZE_BITS_MAX < = HAK_TYPE_MAX ( hak_oow_t ) ) ;
2025-09-02 23:58:15 +09:00
return ( negx ) ? HAK_SMOOI_TO_OOP ( - 1 ) : HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
# else
if ( negx )
2025-09-02 23:58:15 +09:00
return rshift_negative_bigint_and_normalize ( hak , x , y ) ;
2018-02-05 10:43:25 +00:00
else
2025-09-02 23:58:15 +09:00
return rshift_positive_bigint_and_normalize ( hak , x , y ) ;
2018-02-05 10:43:25 +00:00
# endif
}
else
{
/* left shift */
2025-09-02 23:58:15 +09:00
# if defined(HAK_LIMIT_OBJ_SIZE)
2018-02-05 10:43:25 +00:00
/* the maximum number of bit shifts are guaranteed to be
2025-09-02 23:58:15 +09:00
* small enough to fit into the hak_oow_t type . so i can
2023-11-10 00:03:03 +09:00
* simply return a failure here becuase it ' s surely too
2018-02-05 10:43:25 +00:00
* large after shifting */
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , HAK_TYPE_MAX ( hak_oow_t ) > = HAK_OBJ_SIZE_BITS_MAX ) ;
hak_seterrnum ( hak , HAK_EOOMEM ) ; /* is it a soft failure or a hard failure? is this error code proper? */
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
# else
2025-09-02 23:58:15 +09:00
return lshift_bigint_and_normalize ( hak , x , y ) ;
2018-02-05 10:43:25 +00:00
# endif
}
}
else if ( sign > = 1 )
{
/* left shift */
2025-09-02 23:58:15 +09:00
hak_oow_t wshift ;
2018-02-05 10:43:25 +00:00
bigint_and_positive_oow :
2025-09-02 23:58:15 +09:00
wshift = shift / HAK_LIW_BITS ;
if ( shift > wshift * HAK_LIW_BITS ) wshift + + ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
z = expand_bigint ( hak , x , wshift ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
lshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , HAK_OBJ_GET_SIZE ( z ) , shift ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
/* right shift */
bigint_and_negative_oow :
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , sign < = - 1 ) ;
2018-02-05 10:43:25 +00:00
if ( negx )
{
2025-09-02 23:58:15 +09:00
z = rshift_negative_bigint ( hak , x , shift ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
z = clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) ) ;
if ( HAK_UNLIKELY ( ! z ) ) return HAK_NULL ;
rshift_unsigned_array ( ( ( hak_oop_liword_t ) z ) - > slot , HAK_OBJ_GET_SIZE ( z ) , shift ) ;
2018-02-05 10:43:25 +00:00
}
}
2025-09-02 23:58:15 +09:00
return normalize_bigint ( hak , z ) ;
2018-02-05 10:43:25 +00:00
}
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static hak_uint8_t ooch_val_tab [ ] =
2018-02-05 10:43:25 +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
} ;
2025-09-02 23:58:15 +09:00
hak_oop_t hak_strtoint ( hak_t * hak , const hak_ooch_t * str , hak_oow_t len , int radix )
2018-02-05 10:43:25 +00:00
{
int sign = 1 ;
2025-09-02 23:58:15 +09:00
const hak_ooch_t * ptr , * start , * end ;
hak_lidw_t w , v ;
hak_liw_t hw [ 16 ] , * hwp = HAK_NULL ;
hak_oow_t hwlen , outlen ;
hak_oop_t res ;
2018-02-05 10:43:25 +00:00
2023-11-10 00:03:03 +09:00
if ( radix < 0 )
2018-02-05 10:43:25 +00:00
{
/* when radix is less than 0, it treats it as if '-' is preceeding */
sign = - 1 ;
radix = - radix ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , radix > = 2 & & radix < = 36 ) ;
2018-02-05 10:43:25 +00:00
ptr = str ;
end = str + len ;
if ( ptr < end )
{
if ( * ptr = = ' + ' ) ptr + + ;
2023-11-10 00:03:03 +09:00
else if ( * ptr = = ' - ' )
2018-02-05 10:43:25 +00:00
{
2023-11-10 00:03:03 +09:00
ptr + + ;
2018-02-05 10:43:25 +00:00
sign = - 1 ;
}
}
if ( ptr > = end ) goto oops_einval ; /* no digits */
2023-11-10 00:03:03 +09:00
while ( ptr < end & & * ptr = = ' 0 ' )
2018-02-05 10:43:25 +00:00
{
/* skip leading zeros */
ptr + + ;
}
if ( ptr > = end )
{
/* all zeros */
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( 0 ) ;
2018-02-05 10:43:25 +00:00
}
hwlen = 0 ;
start = ptr ; /* this is the real start */
2019-03-25 13:01:05 +00:00
if ( IS_POW2 ( radix ) )
2018-02-05 10:43:25 +00:00
{
unsigned int exp ;
unsigned int bitcnt ;
/* get log2(radix) in a fast way under the fact that
* radix is a power of 2. the exponent acquired is
* the number of bits that a digit of the given radix takes up */
2019-05-04 17:56:45 +00:00
/*exp = LOG2_FOR_POW2(radix);*/
2019-03-25 13:01:05 +00:00
exp = _exp_tab [ radix - 1 ] ;
2018-02-05 10:43:25 +00:00
/* bytes */
2025-09-02 23:58:15 +09:00
outlen = ( ( hak_oow_t ) ( end - str ) * exp + 7 ) / 8 ;
/* number of hak_liw_t */
outlen = ( outlen + HAK_SIZEOF ( hw [ 0 ] ) - 1 ) / HAK_SIZEOF ( hw [ 0 ] ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
if ( outlen > HAK_COUNTOF ( hw ) )
2018-02-05 10:43:25 +00:00
{
2024-09-20 12:00:18 +09:00
/* TODO: reuse this buffer? */
2025-09-02 23:58:15 +09:00
hwp = ( hak_liw_t * ) hak_allocmem ( hak , outlen * HAK_SIZEOF ( hw [ 0 ] ) ) ;
if ( ! hwp ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
hwp = hw ;
}
w = 0 ;
bitcnt = 0 ;
ptr = end - 1 ;
while ( ptr > = start )
{
2025-09-02 23:58:15 +09:00
if ( * ptr < 0 | | * ptr > = HAK_COUNTOF ( ooch_val_tab ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
v = ooch_val_tab [ * ptr ] ;
if ( v > = radix ) goto oops_einval ;
w | = ( v < < bitcnt ) ;
bitcnt + = exp ;
2025-09-02 23:58:15 +09:00
if ( bitcnt > = HAK_LIW_BITS )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
bitcnt - = HAK_LIW_BITS ;
hwp [ hwlen + + ] = w ; /*(hak_liw_t)(w & HAK_LBMASK(hak_lidw_t, HAK_LIW_BITS));*/
w > > = HAK_LIW_BITS ;
2018-02-05 10:43:25 +00:00
}
ptr - - ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , w < = HAK_TYPE_MAX ( hak_liw_t ) ) ;
2018-02-05 10:43:25 +00:00
if ( hwlen = = 0 | | w > 0 ) hwp [ hwlen + + ] = w ;
}
else
{
2025-09-02 23:58:15 +09:00
hak_lidw_t r1 , r2 ;
hak_liw_t multiplier ;
2018-02-05 10:43:25 +00:00
int dg , i , safe_ndigits ;
w = 0 ;
ptr = start ;
2025-09-02 23:58:15 +09:00
safe_ndigits = hak - > bigint [ radix ] . safe_ndigits ;
multiplier = ( hak_liw_t ) hak - > bigint [ radix ] . multiplier ;
2018-02-05 10:43:25 +00:00
outlen = ( end - str ) / safe_ndigits + 1 ;
2025-09-02 23:58:15 +09:00
if ( outlen > HAK_COUNTOF ( hw ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hwp = ( hak_liw_t * ) hak_allocmem ( hak , outlen * HAK_SIZEOF ( hak_liw_t ) ) ;
2025-09-18 01:09:04 +09:00
if ( HAK_UNLIKELY ( ! hwp ) ) return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
else
{
hwp = hw ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , ptr < end ) ;
2018-02-05 10:43:25 +00:00
do
{
r1 = 0 ;
for ( dg = 0 ; dg < safe_ndigits ; dg + + )
{
2023-11-10 00:03:03 +09:00
if ( ptr > = end )
2018-02-05 10:43:25 +00:00
{
multiplier = 1 ;
for ( i = 0 ; i < dg ; i + + ) multiplier * = radix ;
break ;
}
2025-09-02 23:58:15 +09:00
if ( * ptr < 0 | | * ptr > = HAK_COUNTOF ( ooch_val_tab ) ) goto oops_einval ;
2018-02-05 10:43:25 +00:00
v = ooch_val_tab [ * ptr ] ;
if ( v > = radix ) goto oops_einval ;
2025-09-02 23:58:15 +09:00
r1 = r1 * radix + ( hak_liw_t ) v ;
2018-02-05 10:43:25 +00:00
ptr + + ;
}
r2 = r1 ;
for ( i = 0 ; i < hwlen ; i + + )
{
2025-09-02 23:58:15 +09:00
hak_liw_t high , low ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
v = ( hak_lidw_t ) hwp [ i ] * multiplier ;
high = ( hak_liw_t ) ( v > > HAK_LIW_BITS ) ;
low = ( hak_liw_t ) ( v /*& HAK_LBMASK(hak_oow_t, HAK_LIW_BITS)*/ ) ;
2018-02-05 10:43:25 +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 ) ;
# else
/* don't use the fall-back version of liw_add_overflow() */
low + = r2 ;
2025-09-02 23:58:15 +09:00
r2 = ( hak_lidw_t ) high + ( low < r2 ) ;
2018-02-05 10:43:25 +00:00
# endif
hwp [ i ] = low ;
}
2025-09-02 23:58:15 +09:00
if ( r2 ) hwp [ hwlen + + ] = ( hak_liw_t ) r2 ;
2018-02-05 10:43:25 +00:00
}
while ( ptr < end ) ;
}
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , hwlen > = 1 ) ;
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
# if (HAK_LIW_BITS == HAK_OOW_BITS)
2023-11-10 00:03:03 +09:00
if ( hwlen = = 1 )
2018-02-05 10:43:25 +00:00
{
w = hwp [ 0 ] ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , - HAK_SMOOI_MAX = = HAK_SMOOI_MIN ) ;
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( ( hak_ooi_t ) w * sign ) ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
# elif (HAK_LIW_BITS == HAK_OOHW_BITS)
2023-11-10 00:03:03 +09:00
if ( hwlen = = 1 )
2018-02-05 10:43:25 +00:00
{
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , hwp [ 0 ] < = HAK_SMOOI_MAX ) ;
2025-09-02 23:58:15 +09:00
return HAK_SMOOI_TO_OOP ( ( hak_ooi_t ) hwp [ 0 ] * sign ) ;
2018-02-05 10:43:25 +00:00
}
else if ( hwlen = = 2 )
{
w = MAKE_WORD ( hwp [ 0 ] , hwp [ 1 ] ) ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , - HAK_SMOOI_MAX = = HAK_SMOOI_MIN ) ;
2025-09-02 23:58:15 +09:00
if ( w < = HAK_SMOOI_MAX ) return HAK_SMOOI_TO_OOP ( ( hak_ooi_t ) w * sign ) ;
2018-02-05 10:43:25 +00:00
}
# else
# error UNSUPPORTED LIW BIT SIZE
# endif
2025-09-02 23:58:15 +09:00
res = hak_instantiate ( hak , ( sign < 0 ? hak - > c_large_negative_integer : hak - > c_large_positive_integer ) , hwp , hwlen ) ;
2025-09-05 10:52:02 +09:00
if ( hwp & & hw ! = hwp ) hak_freemem ( hak , hwp ) ;
2018-02-05 10:43:25 +00:00
return res ;
oops_einval :
2025-09-05 10:52:02 +09:00
if ( hwp & & hw ! = hwp ) hak_freemem ( hak , hwp ) ;
hak_seterrbfmt ( hak , HAK_EINVAL , " unable to convert '%.*js' to integer " , len , str ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
static hak_oow_t oow_to_text ( hak_t * hak , hak_oow_t w , int flagged_radix , hak_ooch_t * buf )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooch_t * ptr ;
2018-02-28 15:57:19 +00:00
const char * _digitc ;
2019-04-16 15:46:00 +00:00
int radix ;
2018-02-28 15:57:19 +00:00
2025-09-02 23:58:15 +09:00
radix = flagged_radix & HAK_INTTOSTR_RADIXMASK ;
_digitc = _digitc_array [ ! ! ( flagged_radix & HAK_INTTOSTR_LOWERCASE ) ] ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , radix > = 2 & & radix < = 36 ) ;
2018-02-05 10:43:25 +00:00
ptr = buf ;
do
{
* ptr + + = _digitc [ w % radix ] ;
w / = radix ;
}
while ( w > 0 ) ;
return ptr - buf ;
}
2025-09-02 23:58:15 +09:00
static void reverse_string ( hak_ooch_t * str , hak_oow_t len )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooch_t ch ;
hak_ooch_t * start = str ;
hak_ooch_t * end = str + len - 1 ;
2018-02-05 10:43:25 +00:00
while ( start < end )
{
ch = * start ;
* start + + = * end ;
* end - - = ch ;
}
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_eqints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) = = HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) | | HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return is_equal ( hak , x , y ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_neints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) ! = HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) | | HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return hak - > _true ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ! is_equal ( hak , x , y ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_gtints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) > HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( HAK_IS_NBIGINT ( hak , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
return ( HAK_IS_PBIGINT ( hak , x ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return is_greater ( hak , x , y ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_geints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) > = HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( HAK_IS_NBIGINT ( hak , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
return ( HAK_IS_PBIGINT ( hak , x ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( is_greater ( hak , x , y ) | | is_equal ( hak , x , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_ltints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) < HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( HAK_IS_PBIGINT ( hak , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
return ( HAK_IS_NBIGINT ( hak , x ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return is_less ( hak , x , y ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_leints ( hak_t * hak , hak_oop_t x , hak_oop_t y )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) & & HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
return ( HAK_OOP_TO_SMOOI ( x ) < = HAK_OOP_TO_SMOOI ( y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( x ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( HAK_IS_PBIGINT ( hak , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_OOP_IS_SMOOI ( y ) )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) ) goto oops_einval ;
return ( HAK_IS_NBIGINT ( hak , x ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
if ( ! hak_isbigint ( hak , x ) | | ! hak_isbigint ( hak , y ) ) goto oops_einval ;
return ( is_less ( hak , x , y ) | | is_equal ( hak , x , y ) ) ? hak - > _true : hak - > _false ;
2018-02-05 10:43:25 +00:00
}
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O, %O " , x , y ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_sqrtint ( hak_t * hak , hak_oop_t x )
2018-04-03 14:02:40 +00:00
{
/* TODO: find a faster and more efficient algorithm??? */
2025-09-02 23:58:15 +09:00
hak_oop_t a , b , m , m2 , t ;
2018-04-04 04:41:23 +00:00
int neg ;
2025-09-02 23:58:15 +09:00
if ( ! hak_isint ( hak , x ) )
2018-04-04 04:41:23 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O " , x ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-04-04 04:41:23 +00:00
}
2025-09-02 23:58:15 +09:00
a = hak - > _nil ;
b = hak - > _nil ;
m = hak - > _nil ;
m2 = hak - > _nil ;
2018-04-03 14:02:40 +00:00
2025-09-02 23:58:15 +09:00
hak_pushvolat ( hak , & x ) ;
hak_pushvolat ( hak , & a ) ;
hak_pushvolat ( hak , & b ) ;
hak_pushvolat ( hak , & m ) ;
hak_pushvolat ( hak , & m2 ) ;
2018-04-04 04:41:23 +00:00
2025-09-02 23:58:15 +09:00
a = hak_ltints ( hak , x , HAK_SMOOI_TO_OOP ( 0 ) ) ;
if ( HAK_UNLIKELY ( ! a ) ) goto oops ;
if ( a = = hak - > _true )
2018-04-04 04:41:23 +00:00
{
/* the given number is a negative number.
* i will arrange the return value to be negative . */
2025-09-02 23:58:15 +09:00
x = hak_negateint ( hak , x ) ;
if ( HAK_UNLIKELY ( ! x ) ) goto oops ;
2018-04-04 04:41:23 +00:00
neg = 1 ;
}
else neg = 0 ;
2025-09-02 23:58:15 +09:00
a = HAK_SMOOI_TO_OOP ( 1 ) ;
b = hak_bitshiftint ( hak , x , HAK_SMOOI_TO_OOP ( - 5 ) ) ;
if ( HAK_UNLIKELY ( ! b ) ) goto oops ;
b = hak_addints ( hak , b , HAK_SMOOI_TO_OOP ( 8 ) ) ;
if ( HAK_UNLIKELY ( ! b ) ) goto oops ;
2018-04-03 14:02:40 +00:00
while ( 1 )
{
2025-09-02 23:58:15 +09:00
t = hak_geints ( hak , b , a ) ;
if ( HAK_UNLIKELY ( ! t ) ) return HAK_NULL ;
if ( t = = hak - > _false ) break ;
2018-04-03 14:02:40 +00:00
2025-09-02 23:58:15 +09:00
m = hak_addints ( hak , a , b ) ;
if ( HAK_UNLIKELY ( ! m ) ) goto oops ;
m = hak_bitshiftint ( hak , m , HAK_SMOOI_TO_OOP ( - 1 ) ) ;
if ( HAK_UNLIKELY ( ! m ) ) goto oops ;
m2 = hak_mulints ( hak , m , m ) ;
if ( HAK_UNLIKELY ( ! m2 ) ) goto oops ;
t = hak_gtints ( hak , m2 , x ) ;
if ( HAK_UNLIKELY ( ! t ) ) return HAK_NULL ;
if ( t = = hak - > _true )
2018-04-03 14:02:40 +00:00
{
2025-09-02 23:58:15 +09:00
b = hak_subints ( hak , m , HAK_SMOOI_TO_OOP ( 1 ) ) ;
if ( HAK_UNLIKELY ( ! b ) ) goto oops ;
2018-04-03 14:02:40 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
a = hak_addints ( hak , m , HAK_SMOOI_TO_OOP ( 1 ) ) ;
if ( HAK_UNLIKELY ( ! a ) ) goto oops ;
2018-04-03 14:02:40 +00:00
}
}
2025-09-02 23:58:15 +09:00
hak_popvolats ( hak , 5 ) ;
x = hak_subints ( hak , a , HAK_SMOOI_TO_OOP ( 1 ) ) ;
if ( HAK_UNLIKELY ( ! x ) ) return HAK_NULL ;
2018-04-04 04:41:23 +00:00
2025-09-02 23:58:15 +09:00
if ( neg ) x = hak_negateint ( hak , x ) ;
2018-04-04 04:41:23 +00:00
return x ;
2018-04-03 14:02:40 +00:00
oops :
2025-09-02 23:58:15 +09:00
hak_popvolats ( hak , 5 ) ;
return HAK_NULL ;
2018-04-03 14:02:40 +00:00
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_absint ( hak_t * hak , hak_oop_t x )
2018-04-07 02:28:38 +00:00
{
2025-09-02 23:58:15 +09:00
if ( HAK_OOP_IS_SMOOI ( x ) )
2018-04-07 02:28:38 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v ;
v = HAK_OOP_TO_SMOOI ( x ) ;
2023-11-10 00:03:03 +09:00
if ( v < 0 )
2018-04-07 02:28:38 +00:00
{
v = - v ;
2025-09-02 23:58:15 +09:00
x = HAK_SMOOI_TO_OOP ( v ) ;
2018-04-07 02:28:38 +00:00
}
}
2025-09-02 23:58:15 +09:00
else if ( HAK_IS_NBIGINT ( hak , x ) )
2018-04-07 02:28:38 +00:00
{
2025-09-02 23:58:15 +09:00
x = _clone_bigint ( hak , x , HAK_OBJ_GET_SIZE ( x ) , hak - > c_large_positive_integer ) ;
2018-04-07 02:28:38 +00:00
}
2025-09-02 23:58:15 +09:00
else if ( HAK_IS_PBIGINT ( hak , x ) )
2018-04-07 04:43:56 +00:00
{
/* do nothing. return x without change.
* [ THINK ] but do i need to clone a positive bigint ? */
}
else
2018-04-07 02:28:38 +00:00
{
2025-09-05 10:52:02 +09:00
hak_seterrbfmt ( hak , HAK_EINVAL , " not integer - %O " , x ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-04-07 02:28:38 +00:00
}
return x ;
}
2025-09-02 23:58:15 +09:00
static HAK_INLINE hak_liw_t get_last_digit ( hak_t * hak , hak_liw_t * x , hak_oow_t * xs , int radix )
2019-04-16 09:06:30 +00:00
{
/* this function changes the contents of the large integer word array */
2025-09-02 23:58:15 +09:00
hak_oow_t oxs = * xs ;
hak_liw_t carry = 0 ;
hak_oow_t i ;
hak_lidw_t dw ;
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , oxs > 0 ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
for ( i = oxs ; i > 0 ; )
{
- - i ;
2025-09-02 23:58:15 +09:00
dw = ( ( hak_lidw_t ) carry < < HAK_LIW_BITS ) + x [ i ] ;
2019-04-16 09:06:30 +00:00
/* TODO: optimize it with ASM - no seperate / and % */
2025-09-02 23:58:15 +09:00
x [ i ] = ( hak_liw_t ) ( dw / radix ) ;
carry = ( hak_liw_t ) ( dw % radix ) ;
2019-04-16 09:06:30 +00:00
}
if ( /*oxs > 0 &&*/ x [ oxs - 1 ] = = 0 ) * xs = oxs - 1 ;
return carry ;
}
2025-09-02 23:58:15 +09:00
hak_oop_t hak_inttostr ( hak_t * hak , hak_oop_t num , int flagged_radix )
2018-02-05 10:43:25 +00:00
{
2025-09-02 23:58:15 +09:00
hak_ooi_t v = 0 ;
hak_oow_t w ;
hak_oow_t as ;
hak_liw_t * t = HAK_NULL ;
hak_ooch_t * xbuf = HAK_NULL ;
hak_oow_t xlen = 0 , reqcapa ;
2023-11-10 00:03:03 +09:00
2019-04-16 15:46:00 +00:00
int radix ;
2018-02-28 15:57:19 +00:00
const char * _digitc ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
radix = flagged_radix & HAK_INTTOSTR_RADIXMASK ;
_digitc = _digitc_array [ ! ! ( flagged_radix & HAK_INTTOSTR_LOWERCASE ) ] ;
2025-09-05 10:52:02 +09:00
HAK_ASSERT ( hak , radix > = 2 & & radix < = 36 ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( ! hak_isint ( hak , num ) ) goto oops_einval ;
v = integer_to_oow_noseterr ( hak , num , & w ) ;
2023-11-10 00:03:03 +09:00
2018-02-05 10:43:25 +00:00
if ( v )
{
2018-02-15 08:05:48 +00:00
/* The largest buffer is required for radix 2.
2018-02-05 10:43:25 +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 . */
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
reqcapa = HAK_OOW_BITS + 1 ;
if ( hak - > inttostr . xbuf . capa < reqcapa )
2018-02-15 08:05:48 +00:00
{
2025-09-02 23:58:15 +09:00
xbuf = ( hak_ooch_t * ) hak_reallocmem ( hak , hak - > inttostr . xbuf . ptr , reqcapa * HAK_SIZEOF ( * xbuf ) ) ;
if ( ! xbuf ) return HAK_NULL ;
hak - > inttostr . xbuf . capa = reqcapa ;
hak - > inttostr . xbuf . ptr = xbuf ;
2018-02-15 08:05:48 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
xbuf = hak - > inttostr . xbuf . ptr ;
2018-02-15 08:05:48 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
xlen = oow_to_text ( hak , w , flagged_radix , xbuf ) ;
2018-02-15 08:05:48 +00:00
if ( v < 0 ) xbuf [ xlen + + ] = ' - ' ;
2023-11-10 00:03:03 +09:00
2018-02-15 08:05:48 +00:00
reverse_string ( xbuf , xlen ) ;
2025-09-02 23:58:15 +09:00
if ( flagged_radix & HAK_INTTOSTR_NONEWOBJ )
2018-02-15 08:05:48 +00:00
{
/* special case. don't create a new object.
2025-09-02 23:58:15 +09:00
* the caller can use the data left in hak - > inttostr . xbuf */
hak - > inttostr . xbuf . len = xlen ;
return hak - > _nil ;
2023-11-10 00:03:03 +09:00
}
2025-09-02 23:58:15 +09:00
return hak_makestring ( hak , xbuf , xlen ) ;
2018-02-05 10:43:25 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
/* the number can't be represented as a single hak_oow_t value.
2024-09-20 12:00:18 +09:00
* mutli - word conversion begins now */
2025-09-02 23:58:15 +09:00
as = HAK_OBJ_GET_SIZE ( num ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
reqcapa = as * HAK_LIW_BITS + 1 ;
if ( hak - > inttostr . xbuf . capa < reqcapa )
2018-02-15 06:58:36 +00:00
{
2025-09-02 23:58:15 +09:00
xbuf = ( hak_ooch_t * ) hak_reallocmem ( hak , hak - > inttostr . xbuf . ptr , reqcapa * HAK_SIZEOF ( * xbuf ) ) ;
if ( HAK_UNLIKELY ( ! xbuf ) ) return HAK_NULL ;
hak - > inttostr . xbuf . capa = reqcapa ;
hak - > inttostr . xbuf . ptr = xbuf ;
2018-02-15 06:58:36 +00:00
}
else
{
2025-09-02 23:58:15 +09:00
xbuf = hak - > inttostr . xbuf . ptr ;
2018-02-15 06:58:36 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( hak - > inttostr . t . capa < as )
2019-04-16 09:06:30 +00:00
{
2025-09-02 23:58:15 +09:00
t = ( hak_liw_t * ) hak_reallocmem ( hak , hak - > inttostr . t . ptr , reqcapa * HAK_SIZEOF ( * t ) ) ;
if ( HAK_UNLIKELY ( ! t ) ) return HAK_NULL ;
hak - > inttostr . t . capa = as ;
hak - > inttostr . t . ptr = t ;
2018-02-15 06:58:36 +00:00
}
2023-11-10 00:03:03 +09:00
else
2018-02-15 06:58:36 +00:00
{
2025-09-02 23:58:15 +09:00
t = hak - > inttostr . t . ptr ;
2018-02-15 06:58:36 +00:00
}
2023-11-10 00:03:03 +09:00
2025-09-05 10:52:02 +09:00
HAK_MEMCPY ( t , ( ( hak_oop_liword_t ) num ) - > slot , HAK_SIZEOF ( * t ) * as ) ;
2023-11-10 00:03:03 +09:00
2018-02-05 10:43:25 +00:00
do
{
2025-09-02 23:58:15 +09:00
hak_liw_t dv = get_last_digit ( hak , t , & as , radix ) ;
2019-04-16 09:06:30 +00:00
xbuf [ xlen + + ] = _digitc [ dv ] ;
2024-09-20 12:00:18 +09:00
}
2019-04-16 09:06:30 +00:00
while ( as > 0 ) ;
2023-11-10 00:03:03 +09:00
2025-09-02 23:58:15 +09:00
if ( HAK_IS_NBIGINT ( hak , num ) ) xbuf [ xlen + + ] = ' - ' ;
2018-02-05 10:43:25 +00:00
reverse_string ( xbuf , xlen ) ;
2025-09-02 23:58:15 +09:00
if ( flagged_radix & HAK_INTTOSTR_NONEWOBJ )
2018-02-15 08:05:48 +00:00
{
/* special case. don't create a new object.
2025-09-02 23:58:15 +09:00
* the caller can use the data left in hak - > inttostr . xbuf */
hak - > inttostr . xbuf . len = xlen ;
return hak - > _nil ;
2018-02-15 08:05:48 +00:00
}
2018-02-05 10:43:25 +00:00
2025-09-02 23:58:15 +09:00
return hak_makestring ( hak , xbuf , xlen ) ;
2023-11-10 00:03:03 +09:00
2019-04-16 09:06:30 +00:00
oops_einval :
2025-09-05 10:52:02 +09:00
hak_seterrnum ( hak , HAK_EINVAL ) ;
2025-09-02 23:58:15 +09:00
return HAK_NULL ;
2018-02-05 10:43:25 +00:00
}