/*
 *  call-seq:
 *    fix ** other         => Numeric
 *
 *  Raises <code>fix</code> to the <code>other</code> power, which may
 *  be negative or fractional.
 *
 *    2 ** 3      #=> 8
 *    2 ** -1     #=> 0.5
 *    2 ** 0.5    #=> 1.4142135623731
 */

static VALUE
fix_pow(x, y)
    VALUE x, y;
{
    static const double zero = 0.0;
    long a = FIX2LONG(x);

    if (FIXNUM_P(y)) {
        long b;

        b = FIX2LONG(y);
        if (b == 0) return INT2FIX(1);
        if (b == 1) return x;
        a = FIX2LONG(x);
        if (a == 0) {
            if (b > 0) return INT2FIX(0);
            return rb_float_new(1.0 / zero);
        }
        if (a == 1) return INT2FIX(1);
        if (a == -1) {
            if (b % 2 == 0)
                return INT2FIX(1);
            else 
                return INT2FIX(-1);
        }
        if (b > 0) {
            return rb_big_pow(rb_int2big(a), y);
        }
        return rb_float_new(pow((double)a, (double)b));
    }
    switch (TYPE(y)) {
      case T_BIGNUM:
        if (a == 0) return INT2FIX(0);
        if (a == 1) return INT2FIX(1);
        if (a == -1) {
            if (int_even_p(y)) return INT2FIX(1);
            else return INT2FIX(-1);
        }
        x = rb_int2big(FIX2LONG(x));
        return rb_big_pow(x, y);
      case T_FLOAT:
        if (a == 0) {
            return rb_float_new(RFLOAT(y)->value < 0 ? (1.0 / zero) : 0.0);
        }
        if (a == 1) return rb_float_new(1.0);
        return rb_float_new(pow((double)a, RFLOAT(y)->value));
      default:
        return rb_num_coerce_bin(x, y);
    }
}