From: Yukihiro Matsumoto Date: 2010-08-12T01:44:39+09:00 Subject: [ruby-dev:42007] Re: [Bug #3676] CMath.cbrt(-8)の結果が複素数にならない まつもと ゆきひろです Topポスティングはあまり好きではないのですが、理解しないまま にヘタに削るとまずそうなので、今回は残します。 要約すると (1) Complex#** は主値を返すべきである(現状のまま) (2) CMath.cbrt()は主値を返せた方がよい (2-1) 主値を返す (2-2) 主値を返すオプションを用意する (2-3) オプションを用意した上、CMathはMathのaliasにする これが誤読でないとして、私の意見を表明しておくと (1) 賛成 (2) 条件つき賛成 以下を明確にする必要がある * 変更範囲はどこまでか。cbrtだけ? * 上記の3案(またはそれ以外)のいずれを採用するか * だれが作業するか です。 In message "Re: [ruby-dev:42006] Re: [Bug #3676] CMath.cbrt(-8)の結果が複素数にならない" on Thu, 12 Aug 2010 01:09:13 +0900, Kenta Murata writes: | |むらたです。 | |On 2010/08/11, at 1:08, Yusuke ENDOH wrote: | |> 2010年8月10日23:22 Tadayoshi Funaba : |>>> 現在のCMath.cbrt(-8)の結果は-2で、これは3乗すると-8になるとい |>>> う意味で正しい値に思えるのですが。Cmath.cbrt(-8)が返すべき |>>> 「正しい」値はなんだとお考えですか? |>> |>> 絶対的に正しい値はないと思いますが、おおよそ、Complex(-8) ** (1.0/3) で |>> ある (1.0+1.73205080756888i) ではないでしょうか。 |> |> 高校レベルの複素数の知識しかないので、Complex#**(Rational) が |> n 乗根のどれを返すかは不定だと思っていました。 |> 仰角が正で最小のものが「おおよそ正しい」んですかね。 | |仰角が正で最小のものを主値 (principal value) と言い、 |多価関数を一価関数とするために使用されます。 |http://ja.wikipedia.org/wiki/%E4%B8%BB%E5%80%A4 | |n乗根の主値は1の原始n乗根の実数倍になっています。 |http://ja.wikipedia.org/wiki/1%E3%81%AE%E5%86%AA%E6%A0%B9 | |ご存知の通り、この主値さえあればすべての解を順番に生成できます: | | a = Complex(-8)**(1.0/3) # 主値 | w = a / a.abs # 1の原始3乗根 | a * w #=> (-0.9999999999999996+1.7320508075688776i) | a * w**2 #=> (-2.0+7.771561172376096e-16i) | |しかし、負数の奇数乗根はかならず実解を持ちますから、 |主値ではなく実解をダイレクトに手に入れる方法があっても良いと思います。 |なぜなら、上の方法では浮動小数点演算による誤差を含んでしまうことと、 |ダイレクトに求められれば必要なかった計算を必要としているからです。 | |(引用の順序を入れ替えます) | |> 2010年8月11日0:35 Tadayoshi Funaba : |>> まつもとさんが言っているのはそういう意味じゃないと思いますが、定義域と |>> 値域があって関数がある、Math は実数に対して定義がある。CMath は複素数に |>> 対して定義される、というのは常識的な事で、議論の余地はないくらいに思い |>> ます。CMath は制限の撤廃、あるいは定義域値域の拡大だと思います。 |> |> 私はまつもとさんと同じ感覚でした (CMath は Math の挙動を拡張する |> だけで変えはしない) 。[ruby-core:31234] の人も同じ感覚だと思います。 |> ちなみに後で登場するに違いないと思いますが、むらけんさんはふなば |> さんと同じ感覚のようです。 |> この機会にコンセンサス (や将来的な方針) を決めとくとよさそうですね。 | | |私は、どちらかといえばふなばさんと同じ立場です。 |しかし上で書いたように実解をダイレクトに得る方法があっても良いと思います。 | |たとえば CMath.cbrt にオプション引数を追加して | | CMath.cbrt(-8) #=> 主値 | CMath.cbrt(-8, :real_only => true) #=> -2 | |のようにするとか。 | |もしくは逆に | | CMath.cbrt(-8) #=> -2 | CMath.cbrt(-8, :principal_value => true) #=> 主値 | |でも良いかもしれませんが、実解を得たいなら現在は Math.cbrt を使えるので |CMath.cbrt のデフォルトの返り値は主値のほうが良いと思います。 | |このような、オプション引数による挙動の変更が許されるのであれば、 |いっそ CMath と Math を統合してしまうのも一つの方法だと思います。 | | |> 少なくとも Complex#** の仕様として決まっているなら、できれば |> rdoc に書いておいて欲しいです。 | |私は ** の結果は主値になっているほうが良いと考えます。 |理由はいくつかあって、 | |(1) 1の原始3乗根の実数倍という数学的に特別である |(2) レシーバが Complex なんだから、一般に実解は期待できない |(3) Mathematica がそうなっている | |などです。なお Mathematica の挙動は Wolfram|Alpha で検証できます。 |http://www.wolframalpha.com/input/?i=(-27)^(1/3) | | |-- |Kenta Murata |OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062 | |本を書きました!! |『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22 | |E-mail: mrkn@mrkn.jp |twitter: http://twitter.com/mrkn/ |blog: http://d.hatena.ne.jp/mrkn/