src/bignum-gem.c
static mrb_value
bignum_to_fixnum(mpz_t num)
{
  /* Quick conversion for numbers fitting in signed long */
  if (mpz_fits_slong_p(num)) {
    long fix = mpz_get_si(num);
    if (MRB_FIXNUM_MIN <= fix && fix <= MRB_FIXNUM_MAX) {
      return mrb_fixnum_value((mrb_int)fix);
    }
    else {
      /* Reached only if mrb_int is smaller than long */
      return mrb_nil_value();
    }
  }

#if MRB_FIXNUM_MIN < LONG_MIN || LONG_MAX < MRB_FIXNUM_MAX
  /* Check for number outside of bignum limits */
  /* TODO:  always fails if mrb_int is at least as large as long */
  {
    mrb_bool big_ok;
    mpz_t limit;

    /* Lower limit:  -(2**(MRB_INT_BIT-1)) */
    mpz_init_set_si(limit, -1);
    mpz_mul_2exp(limit, limit, MRB_INT_BIT - 1);
    big_ok = mpz_cmp(num, limit) >= 0;
    /* Upper limit:  +(2**(MRB_INT_BIT-1)) - 1 */
    if (big_ok) {
      mpz_neg(limit, limit);
      big_ok = mpz_cmp(num, limit) >= 0;
    }
    mpz_clear(limit);
    if (!big_ok) {
      return mrb_nil_value();
    }
  }

  /* OK to convert */
  /* This can only be reached if Fixnum is 64 bits and long is less than that */
  {
    mpz_t upper, lower;
    unsigned long ufix, lfix;
    uint64_t fix;

    mpz_init(upper);
    mpz_init(lower);
    mpz_tdiv_q_2exp(upper, num, 32);
    mpz_tdiv_r_2exp(lower, num, 32);
    ufix = mpz_get_ui(upper);
    lfix = mpz_get_ui(lower);
    fix = ((uint64_t)ufix << 32) | lfix;
    mpz_clear(upper);
    mpz_clear(lower);
    return mrb_fixnum_value(
          mpz_cmp_ui(num, 0) < 0 ? (mrb_int)-fix : (mrb_int)+fix);
  }
#else
  return mrb_nil_value();
#endif
}
/* Convert a Bignum to a Fixnum; return nil if not possible */
Convert a Bignum to a Fixnum; return nil if not possible
Convert a Bignum to a Fixnum ; return nil if not possible
static mrb_value
bignum_to_fixnum(mpz_t num)
{
  if (mpz_fits_slong_p(num)) {
    long fix = mpz_get_si(num);
    if (MRB_FIXNUM_MIN <= fix && fix <= MRB_FIXNUM_MAX) {
      return mrb_fixnum_value((mrb_int)fix);
    }
    else {
      return mrb_nil_value();
    }
  }
#if MRB_FIXNUM_MIN < LONG_MIN || LONG_MAX < MRB_FIXNUM_MAX
  {
    mrb_bool big_ok;
    mpz_t limit;
    mpz_init_set_si(limit, -1);
    mpz_mul_2exp(limit, limit, MRB_INT_BIT - 1);
    big_ok = mpz_cmp(num, limit) >= 0;
    if (big_ok) {
      mpz_neg(limit, limit);
      big_ok = mpz_cmp(num, limit) >= 0;
    }
    mpz_clear(limit);
    if (!big_ok) {
      return mrb_nil_value();
    }
  }
  {
    mpz_t upper, lower;
    unsigned long ufix, lfix;
    uint64_t fix;
    mpz_init(upper);
    mpz_init(lower);
    mpz_tdiv_q_2exp(upper, num, 32);
    mpz_tdiv_r_2exp(lower, num, 32);
    ufix = mpz_get_ui(upper);
    lfix = mpz_get_ui(lower);
    fix = ((uint64_t)ufix << 32) | lfix;
    mpz_clear(upper);
    mpz_clear(lower);
    return mrb_fixnum_value(
          mpz_cmp_ui(num, 0) < 0 ? (mrb_int)-fix : (mrb_int)+fix);
  }
#else
  return mrb_nil_value();
#endif
}
static mrb_value bignum_to_fixnum ( mpz_t num ) { if ( mpz_fits_slong_p ( num ) ) { long fix = mpz_get_si ( num ) ; if ( MRB_FIXNUM_MIN <= fix && fix <= MRB_FIXNUM_MAX ) { return mrb_fixnum_value ( ( mrb_int ) fix ) ; } else { return mrb_nil_value ( ) ; } } #if MRB_FIXNUM_MIN < LONG_MIN || LONG_MAX < MRB_FIXNUM_MAX { mrb_bool big_ok ; mpz_t limit ; mpz_init_set_si ( limit , -1 ) ; mpz_mul_2exp ( limit , limit , MRB_INT_BIT - 1 ) ; big_ok = mpz_cmp ( num , limit ) >= 0 ; if ( big_ok ) { mpz_neg ( limit , limit ) ; big_ok = mpz_cmp ( num , limit ) >= 0 ; } mpz_clear ( limit ) ; if ( ! big_ok ) { return mrb_nil_value ( ) ; } } { mpz_t upper , lower ; unsigned long ufix , lfix ; uint64_t fix ; mpz_init ( upper ) ; mpz_init ( lower ) ; mpz_tdiv_q_2exp ( upper , num , 32 ) ; mpz_tdiv_r_2exp ( lower , num , 32 ) ; ufix = mpz_get_ui ( upper ) ; lfix = mpz_get_ui ( lower ) ; fix = ( ( uint64_t ) ufix << 32 ) | lfix ; mpz_clear ( upper ) ; mpz_clear ( lower ) ; return mrb_fixnum_value ( mpz_cmp_ui ( num , 0 ) < 0 ? ( mrb_int ) - fix : ( mrb_int ) + fix ) ; } #else return mrb_nil_value ( ) ; #endif }
Convert a Bignum to a Fixnum; return nil if not possible
Convert a Bignum to a Fixnum ; return nil if not possible
/* Quick conversion for numbers fitting in signed long */ /* Reached only if mrb_int is smaller than long */ /* Check for number outside of bignum limits */ /* TODO:  always fails if mrb_int is at least as large as long */ /* Lower limit:  -(2**(MRB_INT_BIT-1)) */ /* Upper limit:  +(2**(MRB_INT_BIT-1)) - 1 */ /* OK to convert */ /* This can only be reached if Fixnum is 64 bits and long is less than that */