How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
BramPeeters
Posts: 49
Joined: Wed Jan 31, 2018 3:10 pm

How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

Post by BramPeeters » Thu Sep 27, 2018 5:04 pm

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

stijn
Posts: 366
Joined: Thu Apr 24, 2014 9:13 am

Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

Post by stijn » Thu Sep 27, 2018 6:33 pm

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;
    }
 

BramPeeters
Posts: 49
Joined: Wed Jan 31, 2018 3:10 pm

Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

Post by BramPeeters » Thu Sep 27, 2018 7:21 pm

My int's are 32 bit and long long's 64 bit, so thank you very much !

tim3385
Posts: 7
Joined: Fri Mar 22, 2019 11:14 am

Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

Post by tim3385 » Thu Nov 14, 2019 6:36 pm

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.

stijn
Posts: 366
Joined: Thu Apr 24, 2014 9:13 am

Re: How to get a ll out of an objint (inverse of mp_obj_new_int_from_ll)

Post by stijn » Fri Nov 15, 2019 10:57 am

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
    }

Post Reply