Page 1 of 1
How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)
Posted: Thu Sep 27, 2018 5:04 pm
by BramPeeters
Hi,
After creating an objint with mp_obj_new_int_from_ll, is there a way to get the long long out of there afterwards?
At the moment I am only seeing the mp_int_t mp_obj_get_int(mp_const_obj_t arg) function, but that returns an mp_int_t which is not suppose to have the long long size.
Is mp_obj_int_to_bytes_impl intended for that, with a pointer to a 'long long' as buffer argument ?
Or will this be some internal representation since i am using MICROPY_LONGINT_IMPL_MPZ (not really familiar with how this stores large numbers)
Thanks
Bram
Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)
Posted: Thu Sep 27, 2018 6:33 pm
by stijn
Don't have time to check all my code but this should get you started; as far as I know it depends on sizeof(long long) and on whether you're building as 32bit or 64bit. For instance in a 64bit build where sizeof(long long) is the same as sizeof(mp_int_t) you can just use mp_obj_get_int. But for a 32bit build where sizeof(long long) is 8, I apparently also found no built-in way and ended up with
this at one point (note this works for signed as well, just needs casting):
Code: Select all
//mpz -> 64bit integer for 32bit builds
inline std::uint64_t mpz_to_64bit_int( const mp_obj_int_t* arg, bool is_signed )
{
static_assert( MPZ_DIG_SIZE == 16, "Expected MPZ_DIG_SIZE == 16" );
//see mpz_as_int_checked
const std::uint64_t maxCalcThreshold = is_signed ? 140737488355327 : 281474976710655;
auto i = &arg->mpz;
if( !is_signed && i->neg )
RaiseTypeException( "Source integer must be unsigned" );
auto d = i->dig + i->len;
std::uint64_t val = 0;
while( d-- > i->dig )
{
if( val > maxCalcThreshold )
RaiseOverflowException( "Value too large for 64bit integer" );
val = ( val << MPZ_DIG_SIZE ) | *d;
}
#ifdef _MSC_VER
#pragma warning( disable : 4146 )
#endif
if( i->neg )
val = -val;
#ifdef _MSC_VER
#pragma warning( default : 4146 )
#endif
return val;
}
Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)
Posted: Thu Sep 27, 2018 7:21 pm
by BramPeeters
My int's are 32 bit and long long's 64 bit, so thank you very much !
Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)
Posted: Thu Nov 14, 2019 6:36 pm
by tim3385
Thanks for your
std::uint64_t mpz_to_64bit_int(const mp_obj_int_t* arg, bool is_signed).
I want to use it to get uint64_t from mp_obj_t which is a number in upy code.
But how to get mp_obj_int_t* from a mp_obj_t? MP_OBJ_TO_PTR is a violent way and cause mpz_to_64bit_int crash.
Thank you.
Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)
Posted: Fri Nov 15, 2019 10:57 am
by stijn
MP_OBJ_TO_PTR is the only way I think, see e.g. objint_mpz.c in the MicroPython source for example: check whether the mp_obj_t is really an int then cast:
Code: Select all
if(mp_obj_is_type(lhs_in, &mp_type_int)) {
mp_obj_int_t* p = (mp_obj_int_t*)MP_OBJ_TO_PTR(lhs_in);
...
}
If you check the link in my previous answer you can see why it's done that way, the mp_obj_t could also be a small int in which case you have to use a different conversion, so adding things together then C code would look like this (note I didn't test this, it does not have the overflow checks I have in the original C++ code, and is probably only for 32bit builds; if you want a complete solution look at the C++ code for inspiration):
Code: Select all
std::uint64_t mp_obj_get_uint( mp_const_obj_t arg )
{
if( arg == mp_const_false )
{
return 0u;
}
else if( arg == mp_const_true )
{
return 1u;
}
else if( MP_OBJ_IS_SMALL_INT( arg ) )
{
return MP_OBJ_SMALL_INT_VALUE( arg );
}
else if( MP_OBJ_IS_TYPE( arg, &mp_type_int ) )
{
return mpz_to_64bit_int( (mp_obj_int_t*) arg, false );
}
else
{
RaiseTypeException( arg, "unsigned integer" );
}
#if !defined( _MSC_VER ) || defined( _DEBUG )
return 0u;
#endif
}