Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
BEGIN LICENSE BLOCK ***** Version: EPL 1.0/GPL 2.0/LGPL 2.1 The contents of this file are subject to the Eclipse Public License Version 1.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.eclipse.org/legal/epl-v10.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyright (C) 2001 Alan Moore <alan_moore@gmx.net> Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de> Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr> Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se> Copyright (C) 2002-2004 Thomas E Enebo <enebo@acm.org> Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de> Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com> Copyright (C) 2006 Antti Karanta <Antti.Karanta@napa.fi> Alternatively, the contents of this file may be used under the terms of either of the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the EPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the EPL, the GPL or the LGPL. END LICENSE BLOCK ***
  
  package org.jruby;
  
  import static org.jruby.RubyEnumerator.enumeratorize;
  import static org.jruby.util.Numeric.f_abs;
  import static org.jruby.util.Numeric.f_arg;
  import static org.jruby.util.Numeric.f_mul;
  import static org.jruby.util.Numeric.f_negative_p;
  
  
  import static org.jruby.CompatVersion.*;
  
  import static org.jruby.runtime.Helpers.invokedynamic;
  
Base class for all numerical types in ruby.
  
  // TODO: Numeric.new works in Ruby and it does here too.  However trying to use
  //   that instance in a numeric operation should generate an ArgumentError. Doing
  //   this seems so pathological I do not see the need to fix this now.
  @JRubyClass(name="Numeric", include="Comparable")
  public class RubyNumeric extends RubyObject {
      
      public static RubyClass createNumericClass(Ruby runtime) {
          RubyClass numeric = runtime.defineClass("Numeric"runtime.getObject(), );
          runtime.setNumeric(numeric);
  
          numeric.index = .;
          numeric.setReifiedClass(RubyNumeric.class);
  
          numeric.kindOf = new RubyModule.JavaClassKindOf(RubyNumeric.class);
  
          numeric.includeModule(runtime.getComparable());
          numeric.defineAnnotatedMethods(RubyNumeric.class);
  
          return numeric;
      }
  
      protected static final ObjectAllocator NUMERIC_ALLOCATOR = new ObjectAllocator() {
          public IRubyObject allocate(Ruby runtimeRubyClass klass) {
              return new RubyNumeric(runtimeklass);
          }
      };
  
      public static final double DBL_EPSILON=2.2204460492503131e-16;
  
      private static IRubyObject convertToNum(double valRuby runtime) {
  
          if (val >= (double. || val < (double.) {
             return RubyBignum.newBignum(runtimeval);
         }
         return RubyFixnum.newFixnum(runtime, (longval);
     }
     
     public RubyNumeric(Ruby runtimeRubyClass metaClass) {
         super(runtimemetaClass);
     }
 
     public RubyNumeric(RubyClass metaClass) {
         super(metaClass);
     }
 
     public RubyNumeric(Ruby runtimeRubyClass metaClassboolean useObjectSpace) {
         super(runtimemetaClassuseObjectSpace);
     }    
 
     @Deprecated
     public RubyNumeric(Ruby runtimeRubyClass metaClassboolean useObjectSpaceboolean canBeTainted) {
         super(runtimemetaClassuseObjectSpacecanBeTainted);
     }    
     
     // The implementations of these are all bonus (see TODO above)  I was going
     // to throw an error from these, but it appears to be the wrong place to
     // do it.
     public double getDoubleValue() {
         return 0;
     }
 
     public long getLongValue() {
         return 0;
     }
 
     public BigInteger getBigIntegerValue() {
         return .;
     }
     
     public static RubyNumeric newNumeric(Ruby runtime) {
     	return new RubyNumeric(runtimeruntime.getNumeric());
     }
 
     /*  ================
      *  Utility Methods
      *  ================ 
      */

    
rb_num2int, NUM2INT
 
     public static int num2int(IRubyObject arg) {
         long num = num2long(arg);
 
         checkInt(argnum);
         return (int)num;
     }
    
    
check_int
 
     public static void checkInt(IRubyObject arglong num){
         if (num < .) {
             tooSmall(argnum);
         } else if (num > .) {
             tooBig(argnum);
         } else {
             return;
         }
     }
     
     private static void tooSmall(IRubyObject arglong num) {
         throw arg.getRuntime().newRangeError("integer " + num + " too small to convert to `int'");
     }
     
     private static void tooBig(IRubyObject arglong num) {
         throw arg.getRuntime().newRangeError("integer " + num + " too big to convert to `int'");
     }

    
NUM2CHR
 
     public static byte num2chr(IRubyObject arg) {
         if (arg instanceof RubyString) {
             String value = ((RubyStringarg).toString();
 
             if (value != null && value.length() > 0) return (bytevalue.charAt(0);
         } 
 
         return (bytenum2int(arg);
     }

    
rb_num2long and FIX2LONG (numeric.c)
 
     public static long num2long(IRubyObject arg) {
         if (arg instanceof RubyFixnum) {
             return ((RubyFixnumarg).getLongValue();
         } else {
             return other2long(arg);
         }
     }
 
     private static long other2long(IRubyObject argthrows RaiseException {
         if (arg.isNil()) {
             throw arg.getRuntime().newTypeError("no implicit conversion from nil to integer");
         } else if (arg instanceof RubyFloat) {
             return float2long((RubyFloat)arg);
         } else if (arg instanceof RubyBignum) {
             return RubyBignum.big2long((RubyBignumarg);
         }
         return arg.convertToInteger().getLongValue();
     }
     
     private static long float2long(RubyFloat flt) {
         double aFloat = flt.getDoubleValue();
         if (aFloat <= (double. && aFloat >= (double.) {
             return (longaFloat;
         } else {
             // TODO: number formatting here, MRI uses "%-.10g", 1.4 API is a must?
             throw flt.getRuntime().newRangeError("float " + aFloat + " out of range of integer");
         }
     }

    
rb_dbl2big + LONG2FIX at once (numeric.c)
 
     public static IRubyObject dbl2num(Ruby runtimedouble val) {
         if (Double.isInfinite(val)) {
             throw runtime.newFloatDomainError(val < 0 ? "-Infinity" : "Infinity");
         }
         if (Double.isNaN(val)) {
             throw runtime.newFloatDomainError("NaN");
         }
         return convertToNum(valruntime);
     }

    
rb_num2dbl and NUM2DBL
 
     public static double num2dbl(IRubyObject arg) {
         if (arg instanceof RubyFloat) {
             return ((RubyFloatarg).getDoubleValue();
         } else if (arg instanceof RubyString) {
             throw arg.getRuntime().newTypeError("no implicit conversion to float from string");
         } else if (arg == arg.getRuntime().getNil()) {
             throw arg.getRuntime().newTypeError("no implicit conversion to float from nil");
         }
         return RubyKernel.new_float(argarg).getDoubleValue();
     }

    
rb_dbl_cmp (numeric.c)
 
     public static IRubyObject dbl_cmp(Ruby runtimedouble adouble b) {
         if (Double.isNaN(a) || Double.isNaN(b)) return runtime.getNil();
         return a == b ? RubyFixnum.zero(runtime) : a > b ?
                 RubyFixnum.one(runtime) : RubyFixnum.minus_one(runtime);
     }
 
     public static long fix2long(IRubyObject arg) {
         return ((RubyFixnumarg).getLongValue();
     }
 
     public static int fix2int(IRubyObject arg) {
         long num = arg instanceof RubyFixnum ? fix2long(arg) : num2long(arg);
         checkInt(argnum);
         return (intnum;
     }
 
     public static int fix2int(RubyFixnum arg) {
         long num = arg.getLongValue();
         checkInt(argnum);
         return (intnum;
     }
 
     public static RubyInteger str2inum(Ruby runtimeRubyString strint base) {
         return str2inum(runtime,str,base,false);
     }
 
     public static RubyNumeric int2fix(Ruby runtimelong val) {
         return RubyFixnum.newFixnum(runtime,val);
     }

    
rb_num2fix
 
     public static IRubyObject num2fix(IRubyObject val) {
         if (val instanceof RubyFixnum) {
             return val;
         }
         if (val instanceof RubyBignum) {
             // any BigInteger is bigger than Fixnum and we don't have FIXABLE
             throw val.getRuntime().newRangeError("integer " + val + " out of range of fixnum");
         }
         return RubyFixnum.newFixnum(val.getRuntime(), num2long(val));
     }

    
Converts a string representation of an integer to the integer value. Parsing starts at the beginning of the string (after leading and trailing whitespace have been removed), and stops at the end or at the first character that can't be part of an integer. Leading signs are allowed. If base is zero, strings that begin with '0[xX]', '0[bB]', or '0' (optionally preceded by a sign) will be treated as hex, binary, or octal numbers, respectively. If a non-zero base is given, only the prefix (if any) that is appropriate to that base will be parsed correctly. For example, if the base is zero or 16, the string "0xff" will be converted to 256, but if the base is 10, it will come out as zero, since 'x' is not a valid decimal digit. If the string fails to parse as a number, zero is returned.

Parameters:
runtime the ruby runtime
str the string to be converted
base the expected base of the number (for example, 2, 8, 10, 16), or 0 if the method should determine the base automatically (defaults to 10). Values 0 and 2-36 are permitted. Any other value will result in an ArgumentError.
strict if true, enforce the strict criteria for String encoding of numeric values, as required by Integer('n'), and raise an exception when those criteria are not met. Otherwise, allow lax expression of values, as permitted by String#to_i, and return a value in almost all cases (excepting illegal radix). TODO: describe the rules/criteria
Returns:
a RubyFixnum or (if necessary) a RubyBignum representing the result of the conversion, which will be zero if the conversion failed.
 
     public static RubyInteger str2inum(Ruby runtimeRubyString strint baseboolean strict) {
         ByteList s = str.getByteList();
         return ConvertBytes.byteListToInum(runtimesbasestrict);
     }
 
     public static RubyFloat str2fnum(Ruby runtimeRubyString arg) {
         return str2fnum(runtime,arg,false);
     }

    
Converts a string representation of a floating-point number to the numeric value. Parsing starts at the beginning of the string (after leading and trailing whitespace have been removed), and stops at the end or at the first character that can't be part of a number. If the string fails to parse as a number, 0.0 is returned.

Parameters:
runtime the ruby runtime
arg the string to be converted
strict if true, enforce the strict criteria for String encoding of numeric values, as required by Float('n'), and raise an exception when those criteria are not met. Otherwise, allow lax expression of values, as permitted by String#to_f, and return a value in all cases. TODO: describe the rules/criteria
Returns:
a RubyFloat representing the result of the conversion, which will be 0.0 if the conversion failed.
 
     public static RubyFloat str2fnum(Ruby runtimeRubyString argboolean strict) {
         return str2fnumCommon(runtimeargstrict);
     }
     
     public static RubyFloat str2fnum19(Ruby runtimeRubyString argboolean strict) {
         return str2fnumCommon(runtimeargstrict);
     }
 
     private static RubyFloat str2fnumCommon(Ruby runtimeRubyString argboolean strictByteListCaller caller) {
         final double ZERO = 0.0;
         try {
             return new RubyFloat(runtimecaller.yield(argstrict));
         } catch (NumberFormatException e) {
             if (strict) {
                 throw runtime.newArgumentError("invalid value for Float(): "
                         + arg.callMethod(runtime.getCurrentContext(), "inspect").toString());
             }
             return new RubyFloat(runtime,ZERO);
         }
     }
 
     private static interface ByteListCaller {
         public double yield(RubyString argboolean strict);
     }
 
     private static class ByteListCaller18 implements ByteListCaller {
         public double yield(RubyString argboolean strict) {
             return ConvertDouble.byteListToDouble(arg.getByteList(),strict);
         }
     }
     private static final ByteListCaller18 biteListCaller18 = new ByteListCaller18();
 
     private static class ByteListCaller19 implements ByteListCaller {
         public double yield(RubyString argboolean strict) {
             return ConvertDouble.byteListToDouble19(arg.getByteList(),strict);
         }
     }
     private static final ByteListCaller19 biteListCaller19 = new ByteListCaller19();

    
    
Numeric methods. (num_*)
 
     
     protected IRubyObject[] getCoerced(ThreadContext contextIRubyObject otherboolean error) {
         IRubyObject result;
         
         try {
             result = other.callMethod(context"coerce"this);
         } catch (RaiseException e) {
             if (error) {
                 throw getRuntime().newTypeError(
                         other.getMetaClass().getName() + " can't be coerced into " + getMetaClass().getName());
             }
              
             return null;
         }
         
         if (!(result instanceof RubyArray) || ((RubyArray)result).getLength() != 2) {
             throw getRuntime().newTypeError("coerce must return [x, y]");
         }
         
         return ((RubyArray)result).toJavaArray();
     }
 
     protected IRubyObject callCoerced(ThreadContext contextString methodIRubyObject otherboolean err) {
         IRubyObject[] args = getCoerced(contextothererr);
         if(args == null) {
             return getRuntime().getNil();
         }
         return args[0].callMethod(contextmethodargs[1]);
     }
 
     public IRubyObject callCoerced(ThreadContext contextString methodIRubyObject other) {
         IRubyObject[] args = getCoerced(contextotherfalse);
         if(args == null) {
             return getRuntime().getNil();
         }
         return args[0].callMethod(contextmethodargs[1]);
     }
     
     // beneath are rewritten coercions that reflect MRI logic, the aboves are used only by RubyBigDecimal
 
    
coerce_body
 
     protected final IRubyObject coerceBody(ThreadContext contextIRubyObject other) {
         return other.callMethod(context"coerce"this);
     }

    
do_coerce
 
     protected final RubyArray doCoerce(ThreadContext contextIRubyObject otherboolean err) {
         IRubyObject result;
         try {
             result = coerceBody(contextother);
         } catch (RaiseException e) {
             if (err) {
                 throw getRuntime().newTypeError(
                         other.getMetaClass().getName() + " can't be coerced into " + getMetaClass().getName());
             }
             return null;
         }
     
         if (!(result instanceof RubyArray) || ((RubyArrayresult).getLength() != 2) {
             if (err) {
                 throw getRuntime().newTypeError("coerce must return [x, y]");
             }
             return null;
         }
         return (RubyArrayresult;
     }

    
rb_num_coerce_bin coercion taking two arguments
 
     protected final IRubyObject coerceBin(ThreadContext contextString methodIRubyObject other) {
         RubyArray ary = doCoerce(contextothertrue);
         return (ary.eltInternal(0)).callMethod(contextmethodary.eltInternal(1));
     }
    
    
rb_num_coerce_cmp coercion used for comparisons
 
     protected final IRubyObject coerceCmp(ThreadContext contextString methodIRubyObject other) {
         RubyArray ary = doCoerce(contextotherfalse);
         if (ary == null) {
             return getRuntime().getNil(); // MRI does it!
         } 
         return (ary.eltInternal(0)).callMethod(contextmethodary.eltInternal(1));
     }
        
    
rb_num_coerce_relop coercion used for relative operators
 
     protected final IRubyObject coerceRelOp(ThreadContext contextString methodIRubyObject other) {
         RubyArray ary = doCoerce(contextotherfalse);
         if (ary == null) {
             return RubyComparable.cmperr(thisother);
         }
 
         return unwrapCoerced(contextmethodotherary);
     }
     
     private final IRubyObject unwrapCoerced(ThreadContext contextString methodIRubyObject otherRubyArray ary) {
         IRubyObject result = (ary.eltInternal(0)).callMethod(contextmethodary.eltInternal(1));
         if (result.isNil()) {
             return RubyComparable.cmperr(thisother);
         }
         return result;
     }
         
     public RubyNumeric asNumeric() {
         return this;
     }
 
     /*  ================
      *  Instance Methods
      *  ================ 
      */

    
num_sadded
 
     @JRubyMethod(name = "singleton_method_added")
     public IRubyObject sadded(IRubyObject name) {
         throw getRuntime().newTypeError("can't define singleton method " + name + " for " + getType().getName());
     } 
        
    
num_init_copy
 
     @Override
     @JRubyMethod(name = "initialize_copy", visibility = .)
     public IRubyObject initialize_copy(IRubyObject arg) {
         throw getRuntime().newTypeError("can't copy " + getType().getName());
     }
    
    
num_coerce
 
     @JRubyMethod(name = "coerce")
     public IRubyObject coerce(IRubyObject other) {
         if (getMetaClass() == other.getMetaClass()) return getRuntime().newArray(otherthis);
 
         IRubyObject cdr = RubyKernel.new_float(thisthis);
         IRubyObject car = RubyKernel.new_float(thisother);
 
         return getRuntime().newArray(carcdr);
     }

    
num_uplus
 
     @JRubyMethod(name = "+@")
     public IRubyObject op_uplus() {
         return this;
     }

    
num_imaginary
 
     @JRubyMethod(name = "i", compat = .)
     public IRubyObject num_imaginary(ThreadContext context) {
         return RubyComplex.newComplexRaw(context.runtime, RubyFixnum.zero(context.runtime), this);
     }

    
num_uminus
 
     @JRubyMethod(name = "-@")
     public IRubyObject op_uminus(ThreadContext context) {
         RubyArray ary = RubyFixnum.zero(context.runtime).doCoerce(contextthistrue);
         return ary.eltInternal(0).callMethod(context"-"ary.eltInternal(1));
     }
    
    
num_cmp
 
     @JRubyMethod(name = "<=>")
     public IRubyObject op_cmp(IRubyObject other) {
         if (this == other) { // won't hurt fixnums
             return RubyFixnum.zero(getRuntime());
         }
         return getRuntime().getNil();
     }

    
num_eql
 
     @JRubyMethod(name = "eql?")
     public IRubyObject eql_p(ThreadContext contextIRubyObject other) {
         if (getClass() != other.getClass()) return getRuntime().getFalse();
         return equalInternal(contextthisother) ? getRuntime().getTrue() : getRuntime().getFalse();
     }

    
num_quo (1.8) quo and fdiv in 1.8 just invokes "/"
 
     @JRubyMethod(name = {"quo""fdiv"}, compat = .)
     public IRubyObject quo(ThreadContext contextIRubyObject other) {
         return callMethod(context"/"other);
     }
    
    
num_quo (1.9)
 
     @JRubyMethod(name = "quo", compat = .)
     public IRubyObject quo_19(ThreadContext contextIRubyObject other) {
         return RubyRational.newRationalRaw(context.runtimethis).callMethod(context"/"other);
     }

    
num_div
 
     @JRubyMethod(name = "div", compat = )
     public IRubyObject div(ThreadContext contextIRubyObject other) {
         return callMethod(context"/"other).convertToFloat().floor();
     }

    
num_div
 
     @JRubyMethod(name = "div", compat = )
     public IRubyObject div19(ThreadContext contextIRubyObject other) {
         if (other instanceof RubyNumeric) {
             RubyNumeric numeric = (RubyNumericother;
             if (numeric.zero_p(context).isTrue()) {
                 throw context.runtime.newZeroDivisionError();
             }
         }
         return callMethod(context"/"other).callMethod(context"floor");
     }

    
num_divmod
 
     @JRubyMethod(name = "divmod", compat = )
     public IRubyObject divmod(ThreadContext contextIRubyObject other) {
         return RubyArray.newArray(getRuntime(), div(contextother), modulo(contextother));
     }

    
num_divmod
 
     @JRubyMethod(name = "divmod", compat = )
     public IRubyObject divmod19(ThreadContext contextIRubyObject other) {
         return RubyArray.newArray(getRuntime(), div(contextother), modulo19(contextother));
     }
    
    
num_fdiv (1.9)
 
     @JRubyMethod(name = "fdiv", compat = )
     public IRubyObject fdiv(ThreadContext contextIRubyObject other) {
         return Helpers.invoke(contextthis.convertToFloat(), "/"other);
     }

    
num_modulo
 
     @JRubyMethod(name = "modulo", compat = )
     public IRubyObject modulo(ThreadContext contextIRubyObject other) {
         return callMethod(context"%"other);
     }

    
num_modulo
 
     @JRubyMethod(name = "modulo", compat = )
     public IRubyObject modulo19(ThreadContext contextIRubyObject other) {
         return callMethod(context"-"other.callMethod(context"*"callMethod(context"div"other)));
     }

    
num_remainder
 
     @JRubyMethod(name = "remainder")
     public IRubyObject remainder(ThreadContext contextIRubyObject dividend) {
         IRubyObject z = callMethod(context"%"dividend);
         IRubyObject x = this;
         RubyFixnum zero = RubyFixnum.zero(getRuntime());
 
         if (!equalInternal(contextzzero) &&
                 ((x.callMethod(context"<"zero).isTrue() &&
                 dividend.callMethod(context">"zero).isTrue()) ||
                 (x.callMethod(context">"zero).isTrue() &&
                 dividend.callMethod(context"<"zero).isTrue()))) {
             return z.callMethod(context"-"dividend);
         } else {
             return z;
         }
     }

    
num_abs
 
     @JRubyMethod(name = "abs")
     public IRubyObject abs(ThreadContext context) {
         if (callMethod(context"<", RubyFixnum.zero(getRuntime())).isTrue()) {
             return callMethod(context"-@");
         }
         return this;
     }

    
num_abs/1.9
 
     @JRubyMethod(name = "magnitude", compat = .)
     public IRubyObject magnitude(ThreadContext context) {
         return abs(context);
     }

    
num_to_int
 
     @JRubyMethod(name = "to_int")
     public IRubyObject to_int(ThreadContext context) {
         return Helpers.invoke(contextthis"to_i");
     }

    
num_real_p
 
     @JRubyMethod(name = "real?", compat = .)
     public IRubyObject scalar_p() {
         return getRuntime().getTrue();
     }

    
num_int_p
 
     @JRubyMethod(name = "integer?")
     public IRubyObject integer_p() {
         return getRuntime().getFalse();
     }
    
    
num_zero_p
 
     @JRubyMethod(name = "zero?")
     public IRubyObject zero_p(ThreadContext context) {
         return equalInternal(contextthis, RubyFixnum.zero(getRuntime())) ? getRuntime().getTrue() : getRuntime().getFalse();
     }
    
    
num_nonzero_p
 
     @JRubyMethod(name = "nonzero?")
     public IRubyObject nonzero_p(ThreadContext context) {
         if (callMethod(context"zero?").isTrue()) {
             return getRuntime().getNil();
         }
         return this;
     }

    
num_floor
 
     @JRubyMethod(name = "floor")
     public IRubyObject floor() {
         return convertToFloat().floor();
     }
        
    
num_ceil
 
     @JRubyMethod(name = "ceil")
     public IRubyObject ceil() {
         return convertToFloat().ceil();
     }

    
num_round
 
     @JRubyMethod(name = "round")
     public IRubyObject round() {
         return convertToFloat().round();
     }

    
num_truncate
 
     @JRubyMethod(name = "truncate")
     public IRubyObject truncate() {
         return convertToFloat().truncate();
     }
 
     @JRubyMethod
     public IRubyObject step(ThreadContext contextIRubyObject arg0Block block) {
         return block.isGiven() ? stepCommon(contextarg0, RubyFixnum.one(context.runtime), block) : enumeratorize(context.runtimethis"step"arg0);
     }
 
     @JRubyMethod
     public IRubyObject step(ThreadContext contextIRubyObject toIRubyObject stepBlock block) {
         return block.isGiven() ? stepCommon(contexttostepblock) : enumeratorize(context.runtimethis"step"new IRubyObject[] {tostep});
     }
 
     private IRubyObject stepCommon(ThreadContext contextIRubyObject toIRubyObject stepBlock block) {
         Ruby runtime = context.runtime;
         if (this instanceof RubyFixnum && to instanceof RubyFixnum && step instanceof RubyFixnum) {
             fixnumStep(contextruntime, ((RubyFixnum)this).getLongValue(),
                                          ((RubyFixnum)to).getLongValue(),
                                          ((RubyFixnum)step).getLongValue(),
                                           block);
         } else if (this instanceof RubyFloat || to instanceof RubyFloat || step instanceof RubyFloat) {
             floatStep19(contextruntimethistostepfalseblock);
         } else {
             duckStep(contextruntimethistostepblock);
         }
         return this;
     }
 
     private static void fixnumStep(ThreadContext contextRuby runtimelong fromlong tolong stepBlock block) {
         // We must avoid integer overflows in "i += step".
         if (step == 0) throw runtime.newArgumentError("step cannot be 0");
         if (step > 0) {
             long tov = . - step;
             if (to < tovtov = to;
             long i;
             for (i = fromi <= tovi += step) {
                 block.yield(context, RubyFixnum.newFixnum(runtimei));
             }
             if (i <= to) {
                 block.yield(context, RubyFixnum.newFixnum(runtimei));
             }
         } else {
             long tov = . - step;
             if (to > tovtov = to;
             long i;
             for (i = fromi >= tovi += step) {
                 block.yield(context, RubyFixnum.newFixnum(runtimei));
             }
             if (i >= to) {
                 block.yield(context, RubyFixnum.newFixnum(runtimei));
             }
         }
     }
 
     protected static void floatStep(ThreadContext contextRuby runtimeIRubyObject fromIRubyObject toIRubyObject stepBlock block) { 
         double beg = num2dbl(from);
         double end = num2dbl(to);
         double unit = num2dbl(step);
 
         if (unit == 0) throw runtime.newArgumentError("step cannot be 0");
 
         double n = (end - beg)/unit;
         double err = (Math.abs(beg) + Math.abs(end) + Math.abs(end - beg)) / Math.abs(unit) * ;
 
         if (err > 0.5) err = 0.5;            
         n = Math.floor(n + err) + 1;
 
         for (long i = 0; i < ni++) {
             block.yield(context, RubyFloat.newFloat(runtimei * unit + beg));
         }
     }
 
     static void floatStep19(ThreadContext contextRuby runtimeIRubyObject fromIRubyObject toIRubyObject stepboolean exclBlock block) { 
         double beg = num2dbl(from);
         double end = num2dbl(to);
         double unit = num2dbl(step);
 
         // TODO: remove
         if (unit == 0) throw runtime.newArgumentError("step cannot be 0");
 
         double n = (end - beg)/unit;
         double err = (Math.abs(beg) + Math.abs(end) + Math.abs(end - beg)) / Math.abs(unit) * ;
 
         if (Double.isInfinite(unit)) {
             if (unit > 0) block.yield(context, RubyFloat.newFloat(runtimebeg));
         } else {
             if (err > 0.5) err = 0.5;            
             n = Math.floor(n + err);
             if (!excln++;
             for (long i = 0; i < ni++){
                 block.yield(context, RubyFloat.newFloat(runtimei * unit + beg));
             }
         }
     }
 
     private static void duckStep(ThreadContext contextRuby runtimeIRubyObject fromIRubyObject toIRubyObject stepBlock block) {
         IRubyObject i = from;
         String cmpString = step.callMethod(context">", RubyFixnum.zero(runtime)).isTrue() ? ">" : "<";
 
         while (true) {
             if (i.callMethod(contextcmpStringto).isTrue()) break;
             block.yield(contexti);
             i = i.callMethod(context"+"step);
         }
     }

    
num_equal, doesn't override RubyObject.op_equal
 
     protected final IRubyObject op_num_equal(ThreadContext contextIRubyObject other) {
         // it won't hurt fixnums
         if (this == other)  return getRuntime().getTrue();
 
         return invokedynamic(contextother.this);
     }

    
num_numerator
 
     @JRubyMethod(name = "numerator", compat = .)
     public IRubyObject numerator(ThreadContext context) {
         return RubyRational.newRationalConvert(contextthis).callMethod(context"numerator");
     }
    
    
num_denominator
 
     @JRubyMethod(name = "denominator", compat = .)
     public IRubyObject denominator(ThreadContext context) {
         return RubyRational.newRationalConvert(contextthis).callMethod(context"denominator");
     }

    
numeric_to_c
 
     @JRubyMethod(name = "to_c", compat = .)
     public IRubyObject to_c(ThreadContext context) {
         return RubyComplex.newComplexCanonicalize(contextthis);
     }

    
numeric_real
 
     @JRubyMethod(name = "real", compat = .)
     public IRubyObject real(ThreadContext context) {
         return this;
     }

    
numeric_image
 
     @JRubyMethod(name = {"imaginary""imag"}, compat = .)
     public IRubyObject image(ThreadContext context) {
         return RubyFixnum.zero(context.runtime);
     }

    
numeric_abs2
 
     @JRubyMethod(name = "abs2", compat = .)
     public IRubyObject abs2(ThreadContext context) {
         return f_mul(contextthisthis);
     }

    
numeric_arg
 
     @JRubyMethod(name = {"arg""angle""phase"}, compat = .)
     public IRubyObject arg(ThreadContext context) {
         double value = this.getDoubleValue();
         if (Double.isNaN(value)) {
             return this;
         }
         if (f_negative_p(contextthis) || (value == 0.0 && 1/value == .)) {
             // negative or -0.0
             return context.runtime.getMath().getConstant("PI");
         }
         return RubyFixnum.zero(context.runtime);
     }    

    
numeric_rect
 
     @JRubyMethod(name = {"rectangular""rect"}, compat = .)
     public IRubyObject rect(ThreadContext context) {
         return context.runtime.newArray(this, RubyFixnum.zero(context.runtime));
     }    

    
numeric_polar
 
     @JRubyMethod(name = "polar", compat = .)
     public IRubyObject polar(ThreadContext context) {
         return context.runtime.newArray(f_abs(contextthis), f_arg(contextthis));
     }    

    
numeric_real
 
     @JRubyMethod(name = {"conjugate""conj"}, compat = .)
     public IRubyObject conjugate(ThreadContext context) {
         return this;
     }
 
     @Override
     public Object toJava(Class target) {
         return JavaUtil.getNumericConverter(target).coerce(thistarget);
     }
 
     public static class InvalidIntegerException extends NumberFormatException {
         private static final long serialVersionUID = 55019452543252148L;
         
         public InvalidIntegerException() {
             super();
         }
         public InvalidIntegerException(String message) {
             super(message);
         }
         @Override
         public Throwable fillInStackTrace() {
             return this;
         }
     }
    
    public static class NumberTooLargeException extends NumberFormatException {
        private static final long serialVersionUID = -1835120694982699449L;
        public NumberTooLargeException() {
            super();
        }
        public NumberTooLargeException(String message) {
            super(message);
        }
        @Override
        public Throwable fillInStackTrace() {
            return this;
        }
    }