[#28509] Rational — Tadayoshi Funaba <tadf@...>

ふなばです。

49 messages 2006/04/05
[#28510] Re: Rational — keiju@... (石塚圭樹) 2006/04/05

けいじゅ@いしつかです.

[#28512] Re: Rational — Tadayoshi Funaba <tadf@...> 2006/04/05

ふなばです。

[#28513] Re: Rational — Shin-ichiro HARA <sinara@...> 2006/04/05

原です。

[#28514] Re: Rational — keiju@... (石塚圭樹) 2006/04/05

けいじゅ@いしつかです.

[#28517] Re: Rational — Yukihiro Matsumoto <matz@...> 2006/04/06

まつもと ゆきひろです

[#28520] Re: Rational — keiju@... (石塚圭樹) 2006/04/06

けいじゅ@いしつかです.

[#28521] Re: Rational — Yukihiro Matsumoto <matz@...> 2006/04/06

まつもと ゆきひろです

[#28525] Re: Rational — keiju@... (石塚圭樹) 2006/04/06

けいじゅ@いしつかです.

[#28527] Re: Rational — Shin-ichiro HARA <sinara@...> 2006/04/06

原です。

[#28536] Re: Rational — Shin-ichiro HARA <sinara@...> 2006/04/10

原です。

[#28537] Re: Rational — keiju@... (石塚圭樹) 2006/04/10

けいじゅ@いしつかです.

[#28589] Float#div and Float#divmod [AGAIN] — Shin-ichiro HARA <sinara@...>

原です。

16 messages 2006/04/23

[ruby-dev:28566] Re: Rational

From: Shin-ichiro HARA <sinara@...>
Date: 2006-04-15 17:24:47 UTC
List: ruby-dev #28566
原です。

>ふなばです。

>Common Lisp では、integer-decode-float、Haskell では decodeFloat があ
>るので、一般のプログラマが rational/rationalize のようなものを書けると
>思います。ruby でも Float#decode のようなものがあってもいいのかもしれ
>ない、と思いました。

Float#decode というのは、現在でも

  class Float
    def decode
      f, e = Math.frexp(self)
      [Math.ldexp(f, Float::MANT_DIG).floor, e - Float::MANT_DIG]
    end
  end

と書けるのではないかな。

>> これをもうすこし安全にしてCで実装したとしても結構単純
>> なので、それを Float#to_r にしてもまずくはないかなという
>> 気もしてきました。うーむ。
>
>たとえば、e=0 をデフォルトにする、ということでもいいかもしれないですね。
>Common Lisp の rationalize は、e が与えられないので、どうしているのか
>と思ったんですが、clisp のソースをちょっと見たところでは、元の仮数や指
>数に基いた計算がありますね。

clisp ですか、、、ちょっと見てみましたが r に対する e の値がだいたい、
f0, e0 = r.decode としたときの 2**e0/2 になってますね。たぶんこれで
いいんだろうなあ。

これを取り入れて、更に[ruby-dev:28544] をループで書き直すと、

def rationalize(r, e = nil)
  return(-rationalize(-r, e)) if r < 0
  if e
    raise ArgumentError, "negative precision" if e < 0
    x = Rational(r - e)
    y = Rational(r + e)

    return x if x == y

    xn, xd = x.numerator, x.denominator
    yn, yd = y.numerator, y.denominator
  else
    f0, e0 = r.decode

    return f0 << e0 if e0 >= 0

    xn, xd = 2*f0 - 1, 1 << (1 - e0)
    yn, yd = 2*f0 + 1, 1 << (1 - e0)
  end

  a, b, c, d = 1, 0, 0, 1
  while true
    xq, xr = xn.divmod(xd)
    yq, yr = yn.divmod(yd)

    if xr.zero?
      return Rational(a*xq + b, c*xq + d)
    elsif xq < yq
      return Rational(a*(xq + 1) + b, c*(xq + 1) + d)
    elsif xq > yq
      raise "implementation error"
    end

    a, b, c, d = a*xq + b, a, c*xq + d, c
    xn, xd, yn, yd = yd, yr, xd, xr
  end
end

となりました。

>いずれにしても、rationalize 相当は、あればいいな、くらいだと思うので、
>今すぐ実装できなくてもいいと思いますが。

やはりこれは面白いので、rational.c に含めてみることにしました。

  class Float
    def -(y)
      (rationalize - y.rationalize).to_f
    end
  end
  
  p 61.1 - 60.0 == 1.1 #=> true

とかできて、かなりナイスです。


In This Thread