まつもと ゆきひろです

以下のようなメールがruby-talkに来たのですが、私にはどこがどう違うのか
良く分かりませんでした。もしよければ知恵を貸していただけませんか?

In message "Fixes for the new step methods in the range.c & numeric.c"
    on 02/05/06, chr_rippel / gmx.net <chr_rippel / gmx.net> writes:
|
|This is a multi-part message in MIME format.
|
|------=_NextPart_000_0001_01C1F50B.6E551680
|Content-Type: text/plain;
|	charset="us-ascii"
|Content-Transfer-Encoding: 7bit
|
|Hi,
|
|an included patch for the step method in range.c is a simple
|bug-fix - for example
|
|---
|class Class
|  alias succ superclass
|end
|
|# currently throws an exception complaining that succ for nil
|# is undefined
|(Fixnum..Object).step(2) {|x| p x }
|---
|
|The patch for the step method in numeric.c adds a sequence 
|end point adjustment strategy - #step_fuzzyness measures the
|``fuzzyness'' of step-length additions around the end-point
|and adds a safety margin (there exist probably much better 
|step_fuzzyness measures) - in pure Ruby:  
|
|---
|class Float
|    def test_step(b,s)
|      n = ((b - self)/ s).round
|      last = n*s + self
|      
|      fuzzyness = step_fuzzyness(n,s)
|      if (s > 0 && last > b + fuzzyness) || \
|         (s < 0 && last < b - fuzzyness)
|         n-=1
|         last = n*s + self
|      end
|      
|      if (last - b).abs < fuzzyness
|        last = b
|      end
|        
|      (n-1).times {|i| yield i*s + self }
|      yield last
|	self
|    end
|    
|    EPSILON = 2.0**(-43)
|    def step_fuzzyness(n, s)
|      tmp = ((n-1)..(n+1)).collect do |i| 
|       ((i*s + self - ((i-1)*s + self)) - s).abs
|      end
|      tmp.push s.abs*EPSILON
|      2*tmp.max
|    end
|end
|
|
|# with this patch on my machine ...
|M = 52343
|T = 12418.979
|K = 20300012
|L = 15673
|
|p b = (K/T)                  # => 1634.595887
|p e = (-L*M + K)/T           # => -64423.31749
|p s = -M/T                   # => -4.214758717
|p err = M/T * (2.0**(-40))# => 3.677147842e-12
|
|# with this patch on my machine
|
|last = nil
|b.step(e,s) {|last| }
|p e - last       # => 0.0
|
|b.step(e+err,s) {|last| }
|p (e+err) - last # => -4.214758717
|
|b.step(e-err,s) {|last| }
|p (e-err) - last # => -7.275957614e-12
|
|
|# a bigger error is necessary to demonstrate
|# fuzzyness in pure Ruby 
|
|p err = M/T * (2.0**(-38.00))
|
|b.test_step(e,s) {|last| }
|p e - last       # => 0.0
|
|b.test_step(e+err,s) {|last| }
|p (e+err) - last # => -4.214758717
|
|b.test_step(e-err,s) {|last| }
|p (e-err) - last # => -1.455191523e-11
|---
|
|
|/Christoph
|
|------=_NextPart_000_0001_01C1F50B.6E551680
|Content-Type: application/octet-stream;
|	name="range.patch"
|Content-Transfer-Encoding: quoted-printable
|Content-Disposition: attachment;
|	filename="range.patch"
|
|--- range.c.1.34	Fri May  3 18:44:42 2002=0A=
|+++ range.c	Fri May  3 00:23:28 2002=0A=
|@@ -71,7 +71,7 @@=0A=
|     VALUE obj;=0A=
| {=0A=
|     VALUE beg, end, flags;=0A=
|-    =0A=
|+=0A=
|     rb_scan_args(argc, argv, "21", &beg, &end, &flags);=0A=
|     /* Ranges are immutable, so that they should be initialized only =
|once. */=0A=
|     if (rb_ivar_defined(obj, id_beg)) {=0A=
|@@ -304,26 +304,21 @@=0A=
|     else {			/* generic each */=0A=
| 	VALUE v =3D b;=0A=
| 	long lim =3D NUM2LONG(step);=0A=
|-	long i;=0A=
|+	long i =3D lim;=0A=
| =0A=
| 	if (lim <=3D 0) {=0A=
| 	    rb_raise(rb_eArgError, "step can't be <=3D 0");=0A=
| 	}=0A=
|-	if (EXCL(range)) {=0A=
|-	    while (r_lt(v, e)) {=0A=
|-		if (r_eq(v, e)) break;=0A=
|-		rb_yield(v);=0A=
|-		for (i=3D0; i<lim; i++) =0A=
|-		    v =3D rb_funcall(v, id_succ, 0, 0);=0A=
|-	    }=0A=
|-	}=0A=
|-	else {=0A=
|-	    while (r_le(v, e)) {=0A=
|+	for(;NUM2INT(rb_funcall(v, id_cmp, 1, e)) < 0; v =3D rb_funcall(v, =
|id_succ, 0, 0))=0A=
|+		if (i =3D=3D lim) {=0A=
|+			rb_yield(v);=0A=
|+			i =3D 1;=0A=
|+		} else {=0A=
|+			i++;=0A=
|+		}=0A=
|+	if (!(EXCL(range)) && (i =3D=3D lim) && \=0A=
|+	    (v =3D=3D e || NUM2INT(rb_funcall(v, id_cmp, 1, e)) =3D=3D 0)) {=0A=
| 		rb_yield(v);=0A=
|-		if (r_eq(v, e)) break;=0A=
|-		for (i=3D0; i<lim; i++) =0A=
|-		    v =3D rb_funcall(v, id_succ, 0, 0);=0A=
|-	    }=0A=
| 	}=0A=
|     }=0A=
|     return range;=0A=
|
|------=_NextPart_000_0001_01C1F50B.6E551680
|Content-Type: application/octet-stream;
|	name="numeric.patch"
|Content-Transfer-Encoding: quoted-printable
|Content-Disposition: attachment;
|	filename="numeric.patch"
|
|--- numeric.c.1.47	Fri May  3 19:02:33 2002=0A=
|+++ numeric.c	Sun May  5 12:17:11 2002=0A=
|@@ -224,7 +224,7 @@=0A=
| 	return rb_str_new2(value < 0 ? "-Infinity" : "Infinity");=0A=
|     else if(isnan(value))=0A=
| 	return rb_str_new2("NaN");=0A=
|-    =0A=
|+=0A=
|     avalue =3D fabs(value);=0A=
|     if (avalue =3D=3D 0.0) {=0A=
| 	fmt =3D "%.1f";=0A=
|@@ -234,13 +234,13 @@=0A=
| 	while (d1 < 1.0) d1 *=3D 10.0;=0A=
| 	d1 =3D modf(d1, &d2);=0A=
| 	if (d1 =3D=3D 0) fmt =3D "%.1e";=0A=
|-    }    =0A=
|+    }=0A=
|     else if (avalue >=3D 1.0e10) {=0A=
| 	d1 =3D avalue;=0A=
| 	while (d1 > 10.0) d1 /=3D 10.0;=0A=
| 	d1 =3D modf(d1, &d2);=0A=
| 	if (d1 =3D=3D 0) fmt =3D "%.1e";=0A=
|-    }    =0A=
|+    }=0A=
|     else if ((d1 =3D modf(value, &d2)) =3D=3D 0) {=0A=
| 	fmt =3D "%.1f";=0A=
|     }=0A=
|@@ -641,7 +641,7 @@=0A=
| =0A=
| static VALUE flo_is_nan_p(num)=0A=
|      VALUE num;=0A=
|-{     =0A=
|+{=0A=
| =0A=
|   double value =3D RFLOAT(num)->value;=0A=
| =0A=
|@@ -650,7 +650,7 @@=0A=
| =0A=
| static VALUE flo_is_infinite_p(num)=0A=
|      VALUE num;=0A=
|-{     =0A=
|+{=0A=
|   double value =3D RFLOAT(num)->value;=0A=
| =0A=
|   if (isinf(value)) {=0A=
|@@ -662,12 +662,12 @@=0A=
| =0A=
| static VALUE flo_is_finite_p(num)=0A=
|      VALUE num;=0A=
|-{     =0A=
|+{=0A=
|   double value =3D RFLOAT(num)->value;=0A=
| =0A=
|   if (isinf(value) || isnan(value))=0A=
|     return Qfalse;=0A=
|-  =0A=
|+=0A=
|   return Qtrue;=0A=
| }=0A=
| =0A=
|@@ -762,6 +762,25 @@=0A=
|     return flo_truncate(rb_Float(num));=0A=
| }=0A=
| =0A=
|+=0A=
|+static double=0A=
|+step_fuzzyness(n,a,b,c)=0A=
|+	long  n;=0A=
|+	double a,b,c;=0A=
|+{=0A=
|+	/* eps =3D 2^(-43)  */=0A=
|+	const double eps =3D 1.136868377e-13;=0A=
|+	double n0 =3D (n-2)*c + a;=0A=
|+	double n1 =3D (n-1)*c + a;=0A=
|+	double n2 =3D (n)*c + a;=0A=
|+	double n3 =3D ((n)+1)*c + a;=0A=
|+	/* max-macro is not universal */=0A=
|+	#define fuzzy_max(a,b)    (((a) > (b)) ? (a) : (b))=0A=
|+	return 2*fuzzy_max(fuzzy_max(fabs(n1-n0-c),fabs(n2-n1-c)),\=0A=
|+	                   fuzzy_max(fabs(n3-n2-c),fabs(c)*eps));=0A=
|+}=0A=
|+=0A=
|+=0A=
| static VALUE=0A=
| num_step(argc, argv, from)=0A=
|     int argc;=0A=
|@@ -798,17 +817,32 @@=0A=
| 	}=0A=
|     }=0A=
|     else if (TYPE(from) =3D=3D T_FLOAT || TYPE(to) =3D=3D T_FLOAT || =
|TYPE(step) =3D=3D T_FLOAT) {=0A=
|-	const double epsilon =3D 2.2204460492503131E-16;=0A=
| 	double beg =3D NUM2DBL(from);=0A=
| 	double end =3D NUM2DBL(to);=0A=
| 	double unit =3D NUM2DBL(step);=0A=
|-	double n =3D (end - beg)/unit;=0A=
|-	long i;=0A=
|+	double fuzzy,last;=0A=
|+	long   n,i;=0A=
|+	n =3D floor((end - beg)/unit + 0.5);=0A=
|+=0A=
|+	if (n < 0) {=0A=
|+		return from;=0A=
|+	}=0A=
|+	fuzzy =3D step_fuzzyness(n,beg,end,unit);=0A=
|+	last =3D n* unit + beg;=0A=
| =0A=
|-	n =3D floor(n + n*epsilon) + 1;=0A=
|-	for (i=3D0; i<n; i++) {=0A=
|-	    rb_yield(rb_float_new(i*unit+beg));=0A=
|+	if ((unit > 0.0 && last > end + fuzzy) || (unit < 0.0 && last < end - =
|fuzzy)) {=0A=
|+		n--;=0A=
|+		last =3D n*unit + beg;=0A=
| 	}=0A=
|+	if (fabs(last - end) < fuzzy) {=0A=
|+		last =3D end;=0A=
|+	}=0A=
|+=0A=
|+	for (i =3D 0; i<n; i++) {=0A=
|+		rb_yield(rb_float_new(i*unit + beg));=0A=
|+	}=0A=
|+	rb_yield(rb_float_new(last));=0A=
|+=0A=
|     }=0A=
|     else {=0A=
| 	VALUE i =3D from;=0A=
|
|------=_NextPart_000_0001_01C1F50B.6E551680--
|
|