C言語でべき乗表現

こんにちは、NAKAといいます。

C言語基礎を確認させてください。

pow()っていう関数を使うと思うのですが

例えば2^15って0x8000だと思うのですが、実際やってみると0x7FFFになってしまいます。

  • NAKAさん、こんにちは。NoMaYです。

    > 諸悪の原因はEXCELかな?

    たぶん、NAKAさんの場合、まずはそこでしょうかね。ちなみに、ググってみたのですが、EXCELのべき乗演算(x^y)は、xにもyにも浮動小数点数が使えるようですね。

    [Excel] べき乗・累乗の計算 - Excel VBA 数学教室
    excelmath.atelierkobato.com/power/

    [関連リンク]

    浮動小数点数の内部表現に関しては以下の検索結果を時間のある時に見ていくと知識が溜まるかな、と思います。あとは、xもyも浮動小数点数である場合の、べき乗の数値計算ライブラリの計算精度、の話のウェブページがあれば良いのかなぁ。(その前に、xもyも浮動小数点数である場合の、べき乗の数値計算ライブラリの計算方法、の話の別のウェブページかなぁ。)

    Google検索: IEEE浮動小数点数 site:qiita.com
    www.google.com/search?q=IEEE浮動小数点数+site:qiita.com

    float型では123456789すらも表現できない話
    qiita.com/y-yoshinari/items/76260f6359d5b4418b33
     

  • NAKAさん、こんにちは。NoMaYです。

    > 数学的本質みたいなのは理解できてませんが、

    この文面を見た時、これは分かっていないサインかな、と感じたのですけれども、そういうことだったな、と思いました。数値計算の分野では、浮動小数点数での数値計算ライブラリの計算結果が、机上の計算結果とは一致しないことがある、というのは常識といってもよいようなことなのです。

    (例) 実際に計算していないので、たまたま、うまくいくこともあるかもしれません。

    (1) 0.001を1000個足したからといって、1.000(それ以下の桁は省略) になるとは限らない
    (2) √2 × √2 = 2 ではあるけども、SQRT(2.000) × SQRT(2.000) = 2.000(それ以下の桁は省略) になるとは限らない
    (3) 2の2乗 = 4 ではあるけれども、POW(2.000, 2.000) = 4.000(それ以下の桁は省略) になるとは限らない

  • NAKAさん こんにちは。Sugachanceです。

    私がいじったのはコンパイルオプションのdouble型/long~のところです。
    正しくはつけたらというか、いいえにしたらですが…

  • NoMaYさん いつもありがとうございます。 NAKAです。


    数値計算関数は浮動小数点で作られているので、浮動小数点自体が仮数部で表現できるのに限界があるため、誤差が発生し、必ずしも机上計算どうりにはいかないという理解でしょうか?

    元々、北米の有名大学の先生(ソフトの専門ではない)が書いたコードで先頭のbitの符号を確認するのに2^15(0x8000)をandしているような書き方だったで、論理演算のためFloatで誤差を少くしても意味ないし、int型をビットシフトしたり、色々悩ましいです。(;_;)

  • NAKAさん、こんにちは。NoMaYです。

    > 浮動小数点自体が仮数部で表現できるのに限界があるため、誤差が発生し

    むしろ、べき乗の計算方法がNAKAさんが思っているのとは全く別物、という点に思い至っていない、のかなと私は思うのです。


    > CC-RLライブラリでの計算方法はともかくとして、浮動小数点計算をするものである、単純に x を y 回だけ掛け算するものでは無い、というイメージとしてです。

    > その前に、xもyも浮動小数点数である場合の、べき乗の数値計算ライブラリの計算方法、の話の別のウェブページかなぁ。

    SAMマイコンでも、べき乗を計算する数値計算ライブラリは、コンパイラがGCCとかClangとかなら、newlibと呼ばれるオープンソースライブラリが使われているのではないかな、と、思いますけれども、そのソースコードは以下のようなものになります。繰り返しになりますけれども、単純に x を y 回だけ掛け算するものでは無い、のです。

    github.com/eblot/newlib/blob/master/newlib/libm/math/e_pow.c#L16-L23

         *                    n
         * Method:  Let x =  2   * (1+f)
         *  1. Compute and return log2(x) in two pieces:
         *          log2(x) = w1 + w2,
         *     where w1 has 53-24 = 29 bit trailing zeros.
         *  2. Perform y*log2(x) = n+y' by simulating multi-precision
         *     arithmetic, where |y'|<=0.5.
         *  3. Return x**y = 2**n*exp(y'*log2)

     

  • NAKAさん、こんにちは。NoMaYです。

    > 北米の有名大学の先生(ソフトの専門ではない)が書いたコード

    ちなみに、その先生がコードを書くのに使用されていたプログラミング言語は何ですか?

    また、可能であれば、原著へのURLもあれば、と思います。

  • NoMaYさん、こんにちは。Sugachanceです。

    たとえば序盤に出てきた2^15 = 32768が
    floatで受けると 3.276798E+004
    になっていた事象ですが、
    これはNAKAさんの仰るような「 浮動小数点自体が仮数部で表現できるのに限界が~
    によるものではなく、計算アルゴリズムの時点で既に誤差が発生しているという見解なのでしょうか?

    doubleで受けても確かに3.276800000000004E+004 なので、
    計算アルゴリズムの時点で既に誤差というのは何となく理解できますが、

    計算アルゴリズムの時点で既に誤差 -> floatに入れることによりさらに表現限界の誤差 -> intでさらに…

    というのが最初の事象として正しいような気がするのですがいかがでしょうか?
    (関数内部の計算アルゴリズムの時点で登場する変数が
    正確に全てを表現できる理想的な変数で、それが返ってくるという仕様のものであれば、
    double,floatの表現限界って話にまとまるのでしょうけども...)

  • NoMaYさん NAKAです。
    すみません!NDA締結した共同研究先なのであまり情報は出せません。C言語的な感じですが指示書みたいなものです。

    Sugachanceさん

    ⇒ありがとうございました。♡ RH850のプロパティ見てました(*_*)

  • Sugachanceさん、こんにちは。NoMaYです。

    >  floatに入れることによりさらに表現限界の誤差

    以下のQiitaの投稿で知ったのですけれども、ウェブ上で浮動小数点数の内部表現を確認出来るサイトがありました。そのサイトで、32768(とか32767とか32769とか)の単精度浮動小数点数の内部表現を確認すると、ちゃんと数値全体が収まっていますよ。なので、これらの数値ぴったりの数値が単精度浮動小数点数の内部表現限界の外にあるわけではないのですよ。

    浮動小数点数内部表現シミュレータ
    tools.m-bsys.com/calculators/ieee754.php


    0.1の浮動小数点数は0.1より大きいのに、10回足すと1.0より小さいのはなぜか【前編】
    qiita.com/yucatio/items/85a8e8d381d300092295

    0.1の浮動小数点数は0.1より大きいのに、10回足すと1.0より小さいのはなぜか【後編】
    qiita.com/yucatio/items/b5ed14bbd1e9a751b703
     

  • ちょっと気になるのですが、ビルド時に警告出ていないでしょうか?

    C言語の場合、宣言されてない関数を使うと、引数/戻り値 共に intと見なされます。

    関係なければ、良いですが、、。