Projects

Ticket #202: numeric.c.patch

File numeric.c.patch, 18.3 KB (added by eloy.de.enige@…, 3 years ago)
  • numeric.c

    diff --git a/numeric.c b/numeric.c
    index eb1a0ed..460893c 100644
     
    8383#endif 
    8484 
    8585static ID id_coerce, id_to_i, id_eq; 
     86#if WITH_OBJC 
     87static ID id_spaceship, id_pow, id_shl, id_shr; 
     88#endif 
    8689 
    8790VALUE rb_cNumeric; 
    8891#if WITH_OBJC 
    8992VALUE rb_cCFNumber; 
     93VALUE rb_cNSNumber; 
    9094#endif 
    9195VALUE rb_cFloat; 
    9296VALUE rb_cInteger; 
     
    32043208} 
    32053209#endif 
    32063210 
     3211/**********************************************************************************/ 
     3212#if WITH_OBJC 
     3213static inline double 
     3214nsnum_cdouble(VALUE num) 
     3215{ 
     3216        double val; CFNumberGetValue((CFNumberRef)num, kCFNumberDoubleType, &val); 
     3217        return val; 
     3218} 
     3219 
     3220static inline long long 
     3221nsnum_cLL(VALUE num) 
     3222{ 
     3223        long long val; CFNumberGetValue((CFNumberRef)num, kCFNumberLongLongType, &val); 
     3224        return val; 
     3225} 
     3226 
     3227static VALUE 
     3228nsnum_to_i(VALUE num) 
     3229{ 
     3230        return LL2NUM(nsnum_cLL(num)); 
     3231} 
     3232 
     3233static VALUE 
     3234nsnum_to_f(VALUE num) 
     3235{ 
     3236        return DOUBLE2NUM(nsnum_cdouble(num)); 
     3237} 
     3238 
     3239static VALUE 
     3240nsnum_class(VALUE num) 
     3241{ 
     3242        CFNumberType t = CFNumberGetType((CFNumberRef)num); 
     3243        switch (t) { 
     3244                case kCFNumberSInt8Type: 
     3245                case kCFNumberSInt16Type: 
     3246                case kCFNumberSInt32Type: 
     3247                case kCFNumberSInt64Type: 
     3248                case kCFNumberCharType: 
     3249                case kCFNumberShortType: 
     3250                case kCFNumberIntType: 
     3251                case kCFNumberLongType: 
     3252                case kCFNumberLongLongType: 
     3253                case kCFNumberCFIndexType: 
     3254                case kCFNumberNSIntegerType: 
     3255                        return rb_cFixnum; 
     3256                case kCFNumberFloat32Type: 
     3257                case kCFNumberFloat64Type: 
     3258                case kCFNumberFloatType: 
     3259                case kCFNumberDoubleType: 
     3260                case kCFNumberMaxType: 
     3261                        return rb_cFloat; 
     3262        } 
     3263        if (CFNumberIsFloatType((CFNumberRef)num)) return rb_cFloat; 
     3264        return rb_cNSNumber; //This could be something exotic like a struct 
     3265} 
     3266 
     3267static VALUE 
     3268nsnum_to_rb(VALUE num) 
     3269{ 
     3270        if (FIXNUM_P(num)) return num; 
     3271        VALUE c = CLASS_OF(num); 
     3272        if (c!=rb_cCFNumber && c!=rb_cNSNumber) return num; 
     3273        VALUE num_class = nsnum_class(num); 
     3274        if (num_class==rb_cFloat) return DOUBLE2NUM(nsnum_cdouble(num)); 
     3275        if (num_class==rb_cFixnum) return LL2NUM(nsnum_cLL(num)); 
     3276        return num; 
     3277} 
     3278 
     3279static void 
     3280nsnum_fail_coerce(VALUE num) 
     3281{ 
     3282        VALUE nsn_desc = rb_funcall(num, rb_intern("description"), 0); 
     3283        const char* numdesc = StringValueCStr(nsn_desc); 
     3284        rb_raise(rb_eTypeError, "Cannot coerce NSNumber %s into a ruby number", numdesc); 
     3285} 
     3286 
     3287static VALUE 
     3288nsnum_to_rb_force(VALUE num) 
     3289{ 
     3290        if (FIXNUM_P(num)) return num; 
     3291        VALUE c = CLASS_OF(num); 
     3292        if (c!=rb_cCFNumber && c!=rb_cNSNumber) return num; 
     3293        VALUE num_class = nsnum_class(num); 
     3294        if (num_class==rb_cFloat) return DOUBLE2NUM((nsnum_cdouble(num))); 
     3295        if (num_class==rb_cFixnum) return LL2NUM((nsnum_cLL(num))); 
     3296        nsnum_fail_coerce(num); 
     3297        return Qnil; 
     3298} 
     3299 
     3300static VALUE 
     3301nsnum_to_rb_abs(VALUE num) 
     3302{ 
     3303        VALUE num_class = nsnum_class(num); 
     3304        if (num_class==rb_cFloat) return DOUBLE2NUM(fabs(nsnum_cdouble(num))); 
     3305        if (num_class==rb_cFixnum) return LL2NUM(llabs(nsnum_cLL(num))); 
     3306        nsnum_fail_coerce(num); 
     3307        return Qnil; 
     3308} 
     3309 
     3310static VALUE 
     3311nsnum_to_rb_neg(VALUE num) 
     3312{ 
     3313        VALUE num_class = nsnum_class(num); 
     3314        if (num_class==rb_cFloat) return DOUBLE2NUM(-(nsnum_cdouble(num))); 
     3315        if (num_class==rb_cFixnum) return LL2NUM(-(nsnum_cLL(num))); 
     3316        nsnum_fail_coerce(num); 
     3317        return Qnil; 
     3318} 
     3319 
     3320static VALUE 
     3321nsnum_cmp(VALUE l, VALUE r) 
     3322{ 
     3323        if (!do_coerce(&l, &r, Qtrue)) return Qnil; 
     3324        return rb_funcall(l, id_spaceship, 1, r); 
     3325} 
     3326 
     3327static VALUE 
     3328nsnum_eq(VALUE l, VALUE r) 
     3329{ 
     3330        if (!do_coerce(&l, &r, Qtrue)) return Qnil; 
     3331        return rb_funcall(l, id_eq, 1, r); 
     3332} 
     3333 
     3334static VALUE 
     3335nsnum_coerce(VALUE num, VALUE b) 
     3336{ 
     3337        return num_coerce(nsnum_to_rb_force(num),b); 
     3338} 
     3339 
     3340static VALUE 
     3341nsnum_init_copy(VALUE x) 
     3342{ 
     3343    /* Numerics are immutable values, which should not be copied */ 
     3344    rb_raise(rb_eTypeError, "can't copy %s",rb_class2name(nsnum_class(x))); 
     3345    return Qnil;                /* not reached */ 
     3346} 
     3347 
     3348static VALUE 
     3349nsnum_dup(VALUE x) 
     3350{ 
     3351    /* Numerics are immutable values, which should not be copied */ 
     3352    rb_raise(rb_eTypeError, "can't dup %s", rb_class2name(nsnum_class(x))); 
     3353    return Qnil;                /* not reached */ 
     3354} 
     3355 
     3356/*static VALUE 
     3357nsnum_missing(int argc, VALUE* argv, VALUE self) 
     3358{ 
     3359        VALUE rb_self = nsnum_to_rb(self); 
     3360        rb_p(rb_self); 
     3361        static ID to_s = Qnil; 
     3362        if (to_s==Qnil) to_s = rb_intern("to_s"); 
     3363        printf("to_s: %s\n", rb_id2name(to_s)); 
     3364        VALUE sel_name = rb_funcall(argv[0], to_s, 0); 
     3365        rb_p(sel_name); 
     3366        ID sel = rb_to_id(sel_name); 
     3367        printf("sel: %s\n", rb_id2name(sel)); 
     3368        if (rb_respond_to(rb_self, sel)) { 
     3369                return rb_self;//rb_funcall2(rb_self, sel, argc-1, argv+1); 
     3370        } else { 
     3371                rb_raise(rb_eNoMethodError, "undefined method `%s' for %s", rb_id2name(sel), rb_obj_classname(rb_self)); 
     3372        } 
     3373        return Qnil; 
     3374}*/ 
     3375 
     3376static VALUE 
     3377nsnum_quo(VALUE a, VALUE b) 
     3378{ 
     3379        static ID sel = 0; 
     3380        if (!sel) sel = rb_intern("quo"); 
     3381        do_coerce(&a,&b,Qtrue); 
     3382        return rb_funcall(a, sel, 1, b); 
     3383} 
     3384 
     3385static VALUE 
     3386nsnum_fdiv(VALUE a, VALUE b) 
     3387{ 
     3388        static ID sel = 0; 
     3389        if (!sel) sel = rb_intern("fdiv"); 
     3390        do_coerce(&a,&b,Qtrue); 
     3391        return rb_funcall(a, sel, 1, b); 
     3392} 
     3393 
     3394static VALUE 
     3395nsnum_divmod(VALUE a, VALUE b) 
     3396{ 
     3397        static ID sel = 0; 
     3398        if (!sel) sel = rb_intern("divmod"); 
     3399        do_coerce(&a,&b,Qtrue); 
     3400        return rb_funcall(a, sel, 1, b); 
     3401} 
     3402 
     3403static VALUE 
     3404nsnum_modulo(VALUE a, VALUE b) 
     3405{ 
     3406        static ID sel = 0; 
     3407        if (!sel) sel = rb_intern("modulo"); 
     3408        do_coerce(&a,&b,Qtrue); 
     3409        return rb_funcall(a, sel, 1, b); 
     3410} 
     3411 
     3412static VALUE 
     3413nsnum_remainder(VALUE a, VALUE b) 
     3414{ 
     3415        static ID sel = 0; 
     3416        if (!sel) sel = rb_intern("remainder"); 
     3417        do_coerce(&a,&b,Qtrue); 
     3418        return rb_funcall(a, sel, 1, b); 
     3419} 
     3420 
     3421static VALUE 
     3422nsnum_true(VALUE a) 
     3423{ 
     3424        return Qtrue; 
     3425} 
     3426 
     3427static VALUE 
     3428nsnum_integer_p(VALUE a) 
     3429{ 
     3430        VALUE num_class = nsnum_class(a); 
     3431        if (num_class==rb_cFloat) return Qfalse; 
     3432        if (num_class==rb_cFixnum) return Qtrue; 
     3433        nsnum_fail_coerce(a); 
     3434        return Qnil; 
     3435} 
     3436 
     3437static VALUE 
     3438nsnum_zero_p(VALUE num) 
     3439{ 
     3440        VALUE num_class = nsnum_class(num); 
     3441        if (num_class==rb_cFloat) return nsnum_cdouble(num)==0; 
     3442        if (num_class==rb_cFixnum) return nsnum_cLL(num)==0; 
     3443        nsnum_fail_coerce(num); 
     3444        return Qnil; 
     3445} 
     3446 
     3447static VALUE 
     3448nsnum_nonzero_p(VALUE num) 
     3449{ 
     3450        VALUE num_class = nsnum_class(num); 
     3451        if (num_class==rb_cFloat) return nsnum_cdouble(num)!=0; 
     3452        if (num_class==rb_cFixnum) return nsnum_cLL(num)!=0; 
     3453        nsnum_fail_coerce(num); 
     3454        return Qnil; 
     3455} 
     3456 
     3457static VALUE 
     3458nsnum_floor(VALUE num) 
     3459{ 
     3460        VALUE num_class = nsnum_class(num); 
     3461        if (num_class==rb_cFixnum) return num; 
     3462         
     3463        if (num_class!=rb_cFloat) { 
     3464                nsnum_fail_coerce(num); 
     3465                return Qnil; 
     3466        } 
     3467        double v = floor(nsnum_cdouble(num)); 
     3468        if (!FIXABLE(v)) return rb_dbl2big(v); 
     3469        return LL2NUM((long long)v); 
     3470} 
     3471 
     3472static VALUE 
     3473nsnum_ceil(VALUE num) 
     3474{ 
     3475        VALUE num_class = nsnum_class(num); 
     3476        if (num_class==rb_cFixnum) return num; 
     3477         
     3478        if (num_class!=rb_cFloat) { 
     3479                nsnum_fail_coerce(num); 
     3480                return Qnil; 
     3481        } 
     3482        double v = ceil(nsnum_cdouble(num)); 
     3483        if (!FIXABLE(v)) return rb_dbl2big(v); 
     3484        return LL2NUM((long long)v); 
     3485} 
     3486 
     3487static VALUE 
     3488nsnum_round(int argc, VALUE* argv, VALUE self) 
     3489{ 
     3490        VALUE num_class = nsnum_class(self); 
     3491        if (num_class==rb_cFloat) return flo_round(argc, argv, DOUBLE2NUM(nsnum_cdouble(self))); 
     3492        if (num_class==rb_cFixnum) return int_round(argc, argv, LL2NUM(nsnum_cLL(self))); 
     3493        nsnum_fail_coerce(self); 
     3494        return Qnil; 
     3495} 
     3496 
     3497static VALUE 
     3498nsnum_truncate(VALUE self) 
     3499{ 
     3500        VALUE num_class = nsnum_class(self); 
     3501        if (num_class==rb_cFloat) return LL2NUM(nsnum_cdouble(self)); 
     3502        if (num_class==rb_cFixnum) return self; 
     3503        nsnum_fail_coerce(self); 
     3504        return Qnil; 
     3505} 
     3506 
     3507static VALUE 
     3508nsnum_step(int argc, VALUE* argv, VALUE self) 
     3509{ 
     3510        VALUE num_class = nsnum_class(self); 
     3511        if (num_class==rb_cFloat) return num_step(argc, argv, DOUBLE2NUM(nsnum_cdouble(self))); 
     3512        if (num_class==rb_cFixnum) return num_step(argc, argv, LL2NUM(nsnum_cLL(self))); 
     3513        nsnum_fail_coerce(self); 
     3514        return Qnil; 
     3515} 
     3516 
     3517static VALUE 
     3518nsnum_numerator(VALUE a) 
     3519{ 
     3520        VALUE num_class = nsnum_class(a); 
     3521        if (num_class==rb_cFloat) return num_numerator(DOUBLE2NUM(nsnum_cdouble(a))); 
     3522        if (num_class==rb_cFixnum) return LL2NUM(nsnum_cLL(a)); 
     3523        nsnum_fail_coerce(a); 
     3524        return Qnil; 
     3525} 
     3526 
     3527static VALUE 
     3528nsnum_denominator(VALUE a) 
     3529{ 
     3530        VALUE num_class = nsnum_class(a); 
     3531        if (num_class==rb_cFloat) return num_denominator(DOUBLE2NUM(nsnum_cdouble(a))); 
     3532        if (num_class==rb_cFixnum) return LONG2FIX(1); 
     3533        nsnum_fail_coerce(a); 
     3534        return Qnil; 
     3535} 
     3536 
     3537static VALUE 
     3538nsnum_even_p(VALUE a) 
     3539{ 
     3540        VALUE num_class = nsnum_class(a); 
     3541        if (num_class==rb_cFloat) //TODO: it will still respond_to the method even if it shouldn't 
     3542                rb_raise(rb_eNoMethodError, "undefined method `even?' for %s", rb_obj_classname(a)); 
     3543        if (num_class==rb_cFixnum) return (nsnum_cLL(a)&1)?Qfalse:Qtrue; 
     3544        return Qnil; 
     3545} 
     3546 
     3547static VALUE 
     3548nsnum_odd_p(VALUE a) 
     3549{ 
     3550        VALUE num_class = nsnum_class(a); 
     3551        if (num_class==rb_cFloat) //TODO: it will still respond_to the method even if it shouldn't 
     3552                rb_raise(rb_eNoMethodError, "undefined method `odd?' for %s", rb_obj_classname(a)); 
     3553        if (num_class==rb_cFixnum) return (nsnum_cLL(a)&1)?Qtrue:Qfalse; 
     3554        return Qnil; 
     3555} 
     3556 
     3557static VALUE 
     3558nsnum_upto(VALUE a, VALUE b) 
     3559{ 
     3560        if (FIXNUM_P(b)) { 
     3561                long i = nsnum_cLL(a); 
     3562                long j = FIX2LONG(b); 
     3563                while (i<=j) { 
     3564                        rb_yield(LONG2FIX(i)); 
     3565                        i++; 
     3566                } 
     3567                return a; 
     3568        } 
     3569        VALUE i = a; 
     3570        VALUE c; 
     3571        while (1) { 
     3572                c = rb_funcall(i, '>', 1, b); 
     3573                if (c==Qnil || c==Qtrue) break; 
     3574                rb_yield(i); 
     3575                i = rb_funcall(i, '+', 1, INT2FIX(1)); 
     3576        } 
     3577        if (NIL_P(c)) rb_cmperr(i, b); 
     3578        return a; 
     3579} 
     3580 
     3581static VALUE 
     3582nsnum_downto(VALUE a, VALUE b) 
     3583{ 
     3584        long long i = nsnum_cLL(a); 
     3585        if (FIXNUM_P(b) && FIXABLE(i)) { 
     3586                long j = FIX2LONG(b); 
     3587                while (i>=j) { 
     3588                        rb_yield(LONG2FIX(i)); 
     3589                        i--; 
     3590                } 
     3591                return a; 
     3592        } 
     3593        VALUE ii = a; 
     3594        VALUE c; 
     3595        while (1) { 
     3596                c = rb_funcall(ii, '<', 1, b); 
     3597                if (c==Qnil || c==Qtrue) break; 
     3598                rb_yield(ii); 
     3599                ii = rb_funcall(ii, '-', 1, INT2FIX(1)); 
     3600        } 
     3601        if (NIL_P(c)) rb_cmperr(ii, b); 
     3602        return a; 
     3603} 
     3604 
     3605static VALUE 
     3606nsnum_dotimes(VALUE a) 
     3607{ 
     3608        long long j = nsnum_cLL(a); 
     3609        long long i = 0; 
     3610        for (; i<j; i++) rb_yield(LL2NUM(i)); 
     3611        return a; 
     3612} 
     3613 
     3614static VALUE 
     3615nsnum_succ(VALUE a) 
     3616{ 
     3617        long long j = nsnum_cLL(a); 
     3618        if (j+1<j) { 
     3619                VALUE r = LL2NUM(j); 
     3620                return rb_funcall(r, '+', 1, INT2FIX(1)); 
     3621        } 
     3622        return LL2NUM(j+1); 
     3623} 
     3624 
     3625static VALUE 
     3626nsnum_pred(VALUE a) 
     3627{ 
     3628        long long j = nsnum_cLL(a); 
     3629        if (j-1>j) { 
     3630                VALUE r = LL2NUM(j); 
     3631                return rb_funcall(r, '-', 1, INT2FIX(1)); 
     3632        } 
     3633        return LL2NUM(j-1); 
     3634} 
     3635 
     3636static VALUE 
     3637nsnum_nan_p(VALUE a) 
     3638{ 
     3639        VALUE num_class = nsnum_class(a); 
     3640        if (num_class==rb_cFloat) return isnan(nsnum_cdouble(a))?Qtrue:Qfalse; 
     3641        if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't 
     3642                rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); 
     3643        nsnum_fail_coerce(a); 
     3644        return Qnil; 
     3645} 
     3646 
     3647static VALUE 
     3648nsnum_inf_p(VALUE a) 
     3649{ 
     3650        VALUE num_class = nsnum_class(a); 
     3651        if (num_class==rb_cFloat) return isinf(nsnum_cdouble(a))?Qtrue:Qfalse; 
     3652        if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't 
     3653                rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); 
     3654        nsnum_fail_coerce(a); 
     3655        return Qnil; 
     3656} 
     3657 
     3658static VALUE 
     3659nsnum_notinf_p(VALUE a) 
     3660{ 
     3661        VALUE num_class = nsnum_class(a); 
     3662        if (num_class==rb_cFloat) return isinf(nsnum_cdouble(a))?Qfalse:Qtrue; 
     3663        if (num_class==rb_cFixnum) //TODO: it will still respond_to the method even if it shouldn't 
     3664                rb_raise(rb_eNoMethodError, "undefined method `is_nan?' for %s", rb_obj_classname(a)); 
     3665        nsnum_fail_coerce(a); 
     3666        return Qnil; 
     3667} 
     3668 
     3669static VALUE 
     3670nsnum_pow(VALUE a, VALUE b) 
     3671{ 
     3672        VALUE num_class = nsnum_class(a); 
     3673        b = nsnum_to_rb_force(b); 
     3674        if (num_class==rb_cFloat) return flo_pow(DOUBLE2NUM(nsnum_cdouble(a)), b); 
     3675        if (num_class==rb_cFixnum) return fix_pow(LL2NUM(nsnum_cLL(a)), b); 
     3676        nsnum_fail_coerce(a); 
     3677        return Qnil; 
     3678} 
     3679 
     3680static VALUE 
     3681nsnum_plus(VALUE a, VALUE b) 
     3682{ 
     3683        VALUE num_class = nsnum_class(a); 
     3684        b = nsnum_to_rb_force(b); 
     3685        if (num_class==rb_cFloat) return flo_plus(DOUBLE2NUM(nsnum_cdouble(a)), b); 
     3686        if (num_class==rb_cFixnum) return fix_plus(LL2NUM(nsnum_cLL(a)), b); 
     3687        nsnum_fail_coerce(a); 
     3688        return Qnil; 
     3689} 
     3690 
     3691static VALUE 
     3692nsnum_minus(VALUE a, VALUE b) 
     3693{ 
     3694        VALUE num_class = nsnum_class(a); 
     3695        b = nsnum_to_rb_force(b); 
     3696        if (num_class==rb_cFloat) return flo_minus(DOUBLE2NUM(nsnum_cdouble(a)), b); 
     3697        if (num_class==rb_cFixnum) return fix_minus(LL2NUM(nsnum_cLL(a)), b); 
     3698        nsnum_fail_coerce(a); 
     3699        return Qnil; 
     3700} 
     3701 
     3702static VALUE 
     3703nsnum_times(VALUE a, VALUE b) 
     3704{ 
     3705        VALUE num_class = nsnum_class(a); 
     3706        b = nsnum_to_rb_force(b); 
     3707        if (num_class==rb_cFloat) return flo_mul(DOUBLE2NUM(nsnum_cdouble(a)), b); 
     3708        if (num_class==rb_cFixnum) return fix_mul(LL2NUM(nsnum_cLL(a)), b); 
     3709        nsnum_fail_coerce(a); 
     3710        return Qnil; 
     3711} 
     3712 
     3713static VALUE 
     3714nsnum_div(VALUE a, VALUE b) 
     3715{ 
     3716        VALUE num_class = nsnum_class(a); 
     3717        b = nsnum_to_rb_force(b); 
     3718        if (num_class==rb_cFloat) return flo_div(DOUBLE2NUM(nsnum_cdouble(a)), b); 
     3719        if (num_class==rb_cFixnum) return fix_div(LL2NUM(nsnum_cLL(a)), b); 
     3720        nsnum_fail_coerce(a); 
     3721        return Qnil; 
     3722} 
     3723 
     3724static VALUE 
     3725nsnum_rev(VALUE a) 
     3726{ 
     3727        return LONG2FIX(~FIX2LONG(a)); 
     3728} 
     3729 
     3730static VALUE 
     3731nsnum_and(VALUE a, VALUE b) 
     3732{ 
     3733        b = bit_coerce(nsnum_to_rb_force(b)); 
     3734        if (!FIXNUM_P(b)) { 
     3735                return rb_big_and(nsnum_to_rb_force(a), b); 
     3736        } 
     3737        return LONG2NUM(nsnum_cLL(a) & FIX2LONG(b)); 
     3738} 
     3739 
     3740static VALUE 
     3741nsnum_or(VALUE a, VALUE b) 
     3742{ 
     3743        b = bit_coerce(nsnum_to_rb_force(b)); 
     3744        if (!FIXNUM_P(b)) { 
     3745                return rb_big_or(nsnum_to_rb_force(a), b); 
     3746        } 
     3747        return LONG2NUM(nsnum_cLL(a) | FIX2LONG(b)); 
     3748} 
     3749 
     3750static VALUE 
     3751nsnum_xor(VALUE a, VALUE b) 
     3752{ 
     3753        b = bit_coerce(nsnum_to_rb_force(b)); 
     3754        if (!FIXNUM_P(b)) { 
     3755                return rb_big_xor(nsnum_to_rb_force(a), b); 
     3756        } 
     3757        return LONG2NUM(nsnum_cLL(a) ^ FIX2LONG(b)); 
     3758} 
     3759 
     3760static VALUE 
     3761nsnum_aref(VALUE l, VALUE idx) 
     3762{ 
     3763        long long v = nsnum_cLL(l); 
     3764        idx = rb_to_int(idx); 
     3765        if (!FIXNUM_P(idx)) { 
     3766                idx = rb_big_norm(idx); 
     3767                if (!FIXNUM_P(idx)) { 
     3768                        if (!RBIGNUM_SIGN(idx) || v >= 0) 
     3769                                return INT2FIX(0); 
     3770                        return INT2FIX(1); 
     3771                } 
     3772        } 
     3773        long i = FIX2LONG(idx); 
     3774        if (i<0) return INT2FIX(0); 
     3775        if (SIZEOF_LONG*CHAR_BIT-1 < i) { 
     3776                if (v < 0) return INT2FIX(1); 
     3777                return INT2FIX(0); 
     3778    } 
     3779    if (v & (1L<<i)) 
     3780                return INT2FIX(1); 
     3781    return INT2FIX(0); 
     3782} 
     3783 
     3784static VALUE 
     3785nsnum_shl(VALUE v, VALUE amt) 
     3786{ 
     3787        VALUE num_class = nsnum_class(v); 
     3788        if (num_class==rb_cFloat) 
     3789                rb_raise(rb_eNoMethodError, "undefined method `<<' for %s", rb_obj_classname(v)); 
     3790        return rb_funcall(nsnum_to_rb_force(v), id_shl, 1, nsnum_to_rb_force(amt)); 
     3791} 
     3792 
     3793static VALUE 
     3794nsnum_shr(VALUE v, VALUE amt) 
     3795{ 
     3796        VALUE num_class = nsnum_class(v); 
     3797        if (num_class==rb_cFloat) 
     3798                rb_raise(rb_eNoMethodError, "undefined method `>>' for %s", rb_obj_classname(v)); 
     3799        return rb_funcall(nsnum_to_rb_force(v), id_shr, 1, nsnum_to_rb_force(amt)); 
     3800} 
     3801 
     3802 
     3803static void 
     3804rb_install_nsnumber_methods() { 
     3805        id_spaceship = rb_intern("<=>"); 
     3806        id_shl = rb_intern("<<"); 
     3807        id_shr = rb_intern(">>"); 
     3808        id_pow = rb_intern("**"); 
     3809        rb_cNSNumber = (VALUE)objc_getClass("NSNumber"); 
     3810        rb_define_method(rb_cNSNumber, "to_i", nsnum_to_i,0); 
     3811        rb_define_method(rb_cNSNumber, "to_f", nsnum_to_f,0); 
     3812        rb_define_method(rb_cNSNumber, "to_rb", nsnum_to_rb,0); 
     3813         
     3814        //rb_define_method(rb_cNSNumber, "class", nsnum_class,0); 
     3815        rb_define_method(rb_cNSNumber, "dup", nsnum_dup,0); 
     3816        rb_define_method(rb_cNSNumber, "initialize_copy", nsnum_init_copy,0); 
     3817        rb_define_method(rb_cNSNumber, "coerce", nsnum_coerce, 1); 
     3818         
     3819        rb_define_method(rb_cNSNumber, "+@", nsnum_to_rb, 0); 
     3820    rb_define_method(rb_cNSNumber, "-@", nsnum_to_rb_neg, 0); 
     3821    rb_define_method(rb_cNSNumber, "<=>", nsnum_cmp, 1); 
     3822    rb_define_method(rb_cNSNumber, "eql?", nsnum_eq, 1); 
     3823        rb_define_method(rb_cNSNumber, "quo", nsnum_quo, 1); 
     3824    rb_define_method(rb_cNSNumber, "fdiv", nsnum_fdiv, 1); 
     3825    rb_define_method(rb_cNSNumber, "div", nsnum_div, 1); 
     3826    rb_define_method(rb_cNSNumber, "divmod", nsnum_divmod, 1); 
     3827    rb_define_method(rb_cNSNumber, "modulo", nsnum_modulo, 1); 
     3828    rb_define_method(rb_cNSNumber, "%", nsnum_modulo, 1); 
     3829    rb_define_method(rb_cNSNumber, "remainder", nsnum_remainder, 1); 
     3830    rb_define_method(rb_cNSNumber, "abs", nsnum_to_rb_abs, 0); 
     3831    rb_define_method(rb_cNSNumber, "to_int", nsnum_to_i, 0); 
     3832         
     3833        rb_define_method(rb_cNSNumber, "scalar?", nsnum_true, 0); 
     3834    rb_define_method(rb_cNSNumber, "integer?", nsnum_integer_p, 0); 
     3835    rb_define_method(rb_cNSNumber, "zero?", nsnum_zero_p, 0); 
     3836    rb_define_method(rb_cNSNumber, "nonzero?", nsnum_nonzero_p, 0); 
     3837         
     3838    rb_define_method(rb_cNSNumber, "floor", nsnum_floor, 0); 
     3839    rb_define_method(rb_cNSNumber, "ceil", nsnum_ceil, 0); 
     3840    rb_define_method(rb_cNSNumber, "round", nsnum_round, -1); 
     3841    rb_define_method(rb_cNSNumber, "truncate", nsnum_truncate, 0); 
     3842    rb_define_method(rb_cNSNumber, "step", nsnum_step, -1); 
     3843 
     3844        rb_define_method(rb_cNSNumber, "numerator", nsnum_numerator, 0); 
     3845    rb_define_method(rb_cNSNumber, "denominator", nsnum_denominator, 0); 
     3846 
     3847        rb_define_method(rb_cNSNumber, "odd?", nsnum_odd_p, 0); 
     3848    rb_define_method(rb_cNSNumber, "even?", nsnum_even_p, 0); 
     3849 
     3850        rb_define_method(rb_cNSNumber, "upto", nsnum_upto, 1); 
     3851    rb_define_method(rb_cNSNumber, "downto", nsnum_downto, 1); 
     3852    rb_define_method(rb_cNSNumber, "times", nsnum_dotimes, 0);   
     3853 
     3854    rb_define_method(rb_cNSNumber, "succ", nsnum_succ, 0);       
     3855    rb_define_method(rb_cNSNumber, "next", nsnum_succ, 0);       
     3856    rb_define_method(rb_cNSNumber, "pred", nsnum_pred, 0);       
     3857         
     3858        rb_define_method(rb_cNSNumber, "nan?",      nsnum_nan_p, 0); 
     3859    rb_define_method(rb_cNSNumber, "infinite?", nsnum_inf_p, 0); 
     3860    rb_define_method(rb_cNSNumber, "finite?",   nsnum_notinf_p, 0);      
     3861         
     3862        rb_define_method(rb_cNSNumber, "**", nsnum_pow, 1); 
     3863        rb_define_method(rb_cNSNumber, "+", nsnum_plus, 1); 
     3864        rb_define_method(rb_cNSNumber, "-", nsnum_minus, 1); 
     3865        rb_define_method(rb_cNSNumber, "*", nsnum_times, 1); 
     3866        rb_define_method(rb_cNSNumber, "/", nsnum_div, 1); 
     3867         
     3868        rb_define_method(rb_cNSNumber, "~", nsnum_rev, 0); 
     3869    rb_define_method(rb_cNSNumber, "&", nsnum_and, 1); 
     3870    rb_define_method(rb_cNSNumber, "|", nsnum_or,  1); 
     3871    rb_define_method(rb_cNSNumber, "^", nsnum_xor, 1); 
     3872    rb_define_method(rb_cNSNumber, "[]", nsnum_aref, 1); 
     3873    rb_define_method(rb_cNSNumber, "<<", nsnum_shl, 1); 
     3874    rb_define_method(rb_cNSNumber, ">>", nsnum_shr, 1); 
     3875         
     3876 
     3877    //rb_define_method(rb_cNSNumber, "method_missing", nsnum_missing, -1); 
     3878    rb_include_module(rb_cNSNumber, rb_mComparable); 
     3879} 
     3880#endif /*WITH_OBJC*/ 
     3881/**********************************************************************************/ 
     3882 
    32073883void 
    32083884Init_Numeric(void) 
    32093885{ 
     
    33944070 
    33954071#if WITH_OBJC 
    33964072    rb_install_nsnumber_primitives(); 
     4073        rb_install_nsnumber_methods(); 
    33974074#endif 
    33984075}