From: "(Dezawa Shin-ichiro)" (Dezawa Shin-ichiro) Date: 1997-01-25T18:48:43+09:00 Subject: [ruby-list:1871] None でざわです bignum に sqrt 作ってみました。 で、テストしていて気づいたのですが bignum が 32bit を切ると Fixnum に変わってしまうんですね。 c=200000000000000; c.sqrt は通るが (c/100000000000).sqrt は undefined local variable or method `sqrt' for 2000(Fixnum) はて、 すべての Numneric に作る必要がでてきた、、。 と言うことで、Fixnum と Float にも作りました。 Known BUG: 負の Fixnum を sqrt しても エラーにならない。 次の warning が出ます。 bignum.c:1260: warning: assignment makes pointer from integer without a cast bignum.c:1263: warning: assignment makes pointer from integer without a cast bignum な x を x>>1 するにはどうするのが正しい作法? x = big_rshift(x, INT2FIX(1) ); --- bignum.c.orig Sat Jan 25 09:47:03 1997 +++ bignum.c Sat Jan 25 18:11:01 1997 @@ -1,3 +1,4 @@ +#include /************************************************ bignum.c - @@ -1215,6 +1216,55 @@ return INT2FIX(big->len*2); } +static VALUE +big_sqrt(x) + struct RBignum *x; +{ + struct RBignum *z; + USHORT *zds, *xds; + unsigned long y, a; + UINT len, sqrt_len, iz, ix , j ; + UINT mask; + + /* 符号確認*/ + if (x->sign == 0)ArgError("square root for negative number"); + + /* <= 2^32 */ + /* あり得ない */ + /* 正規化 2^30 <= < 2^32 にする*/ + xds = BDIGITS(x); + iz = sqrt_len; ix = x->len; + y = ((long)xds[x->len-1])<<16 ; + j=16; + mask = ~0177777 ; /* 0011 1111 1111 1111 or 0111 1111 1111 1111 */ + while ( y & mask ){ + j -= 2; y >>=2; /* j bits 左shift した */ + } + y = (y << 16) + (((long)xds[x->len-2])<len-3])<>16 ); + + /* 初期値 */ + a = 143257 - 202860544/(1582+( y >>22)); + a = a << ( 16 - (j>>1)); + sqrt_len = (( x->len+1) >>1) ; + z = (struct RBignum*)bignew( sqrt_len, 1); + zds = BDIGITS(z); + zds[sqrt_len-1] = a>>16; zds[sqrt_len - 2 ] = a & 0177777; + + /* 精度計算 */ + iz = (x->len *16 - j)>>1 ; + + /* Newton (until j * 2^i > iz ) */ + /* X(i+1) = (X(i)^2 + Y)/2X(i) --> = X(i)>>1 + (Y>>1)/X(i) */ + /* x = x>>1 */ + x = big_rshift(x, INT2FIX(1) ); + for(j=15; j < iz; j = j<<1){ + /* z = ( z >> 1 ) + ( x >> 1 )/z */ + z = big_plus(big_rshift(z, INT2FIX(1)), big_div( x,z) ); + } + return bignorm(z); +} + void Init_Bignum() { @@ -1246,4 +1296,6 @@ rb_define_method(cBignum, "to_f", big_to_f, 0); rb_define_method(cBignum, "abs", big_abs, 0); rb_define_method(cBignum, "size", big_size, 0); + rb_define_method(cBignum, "sqrt", big_sqrt, 0); + } *** numeric.c.orig Sat Jan 25 09:44:25 1997 --- numeric.c Sat Jan 25 18:41:49 1997 *************** *** 1040,1045 **** --- 1040,1065 ---- } return num; } + static VALUE + flo_sqrt(flt) + struct RFloat *flt; + { + double val = flt->value; + if (val < 0.0) ArgError("square root for negative number"); + return float_new(sqrt(val)); + } + static VALUE + fix_sqrt(fix) + VALUE fix; + { + double dbl; + fix = FIX2INT(fix) ; + if ( fix < 0 ) ArgError("square root for negative number"); + dbl = fix; + fix = sqrt(dbl)+0.5 ; + fix =INT2FIX(fix) ; + return fix ; + } extern VALUE mComparable; extern VALUE eException; *************** *** 1138,1141 **** --- 1158,1163 ---- rb_define_method(cFloat, "to_i", flo_to_i, 0); rb_define_method(cFloat, "to_f", flo_to_f, 0); rb_define_method(cFloat, "abs", flo_abs, 0); + rb_define_method(cFloat, "sqrt", flo_sqrt, 0); + rb_define_method(cFixnum, "sqrt", fix_sqrt, 0); }