@@ -590,6 +590,14 @@ mpz_t *mpz_from_ll(long long val, bool is_signed) {
590590 return z ;
591591}
592592
593+ #if MICROPY_PY_BUILTINS_FLOAT
594+ mpz_t * mpz_from_float (mp_float_t val ) {
595+ mpz_t * z = mpz_zero ();
596+ mpz_set_from_float (z , val );
597+ return z ;
598+ }
599+ #endif
600+
593601mpz_t * mpz_from_str (const char * str , mp_uint_t len , bool neg , mp_uint_t base ) {
594602 mpz_t * z = mpz_zero ();
595603 mpz_set_from_str (z , str , len , neg , base );
@@ -682,6 +690,80 @@ void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
682690 }
683691}
684692
693+ #if MICROPY_PY_BUILTINS_FLOAT
694+ void mpz_set_from_float (mpz_t * z , mp_float_t src ) {
695+ #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
696+ #define EXP_SZ 11
697+ #define FRC_SZ 52
698+ typedef uint64_t mp_float_int_t ;
699+ #else
700+ #define EXP_SZ 8
701+ #define FRC_SZ 23
702+ typedef uint32_t mp_float_int_t ;
703+ #endif
704+ union {
705+ mp_float_t f ;
706+ struct { mp_float_int_t frc :FRC_SZ , exp :EXP_SZ , sgn :1 ; } p ;
707+ } u = {src };
708+
709+ z -> neg = u .p .sgn ;
710+ if (u .p .exp == 0 ) {
711+ // value == 0 || value < 1
712+ mpz_init_zero (z );
713+ } else if (u .p .exp == ((1 << EXP_SZ ) - 1 )) {
714+ // inf or NaN
715+ #if 0
716+ // TODO: this probably isn't the right place to throw an exception
717+ if (u .p .frc == 0 )
718+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_OverflowError , "cannot convert float infinity to integer" ));
719+ else
720+ nlr_raise (mp_obj_new_exception_msg_varg (& mp_type_ValueError , "cannot convert float NaN to integer" ));
721+ #else
722+ mpz_init_zero (z );
723+ #endif
724+ } else {
725+ const int adj_exp = (int )u .p .exp - ((1 << (EXP_SZ - 1 )) - 1 );
726+ if (adj_exp < 0 ) {
727+ // value < 1 , truncates to 0
728+ mpz_init_zero (z );
729+ } else if (adj_exp == 0 ) {
730+ // 1 <= value < 2 , so truncates to 1
731+ mpz_init_from_int (z , 1 );
732+ } else {
733+ // 2 <= value
734+ const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1 )) / DIG_SIZE ;
735+ const unsigned int rem = adj_exp % DIG_SIZE ;
736+ int dig_ind , shft ;
737+ mp_float_int_t frc = u .p .frc | ((mp_float_int_t )1 << FRC_SZ );
738+
739+ if (adj_exp < FRC_SZ ) {
740+ shft = 0 ;
741+ dig_ind = 0 ;
742+ frc >>= FRC_SZ - adj_exp ;
743+ } else {
744+ shft = (rem - FRC_SZ ) % DIG_SIZE ;
745+ dig_ind = (adj_exp - FRC_SZ ) / DIG_SIZE ;
746+ }
747+ mpz_need_dig (z , dig_cnt );
748+ z -> len = dig_cnt ;
749+ if (dig_ind != 0 ) {
750+ memset (z -> dig , 0 , dig_ind * sizeof (mpz_dig_t ));
751+ }
752+ if (shft != 0 ) {
753+ z -> dig [dig_ind ++ ] = (frc << shft ) & DIG_MASK ;
754+ frc >>= DIG_SIZE - shft ;
755+ }
756+ while (dig_ind != dig_cnt ) {
757+ z -> dig [dig_ind ++ ] = frc & DIG_MASK ;
758+ frc >>= DIG_SIZE ;
759+ }
760+ }
761+ }
762+ }
763+ #undef EXP_SZ
764+ #undef FRC_SZ
765+ #endif
766+
685767// returns number of bytes from str that were processed
686768mp_uint_t mpz_set_from_str (mpz_t * z , const char * str , mp_uint_t len , bool neg , mp_uint_t base ) {
687769 assert (base < 36 );
0 commit comments