こんにちは、NAKAといいます。C言語基礎を確認させてください。
pow()っていう関数を使うと思うのですが
例えば2^15って0x8000だと思うのですが、実際やってみると0x7FFFになってしまいます。
NAKAさん、Sugachanceさん、こんにちは。NoMaYです。他の言語のべき乗2項演算子とC言語のべき乗数学関数の違いが認識出来ていないのかなぁ、と思いました。Fortran (参考 www.ile.osaka-u.ac.jp/research/cmp/download/fortran90-text-v4.pdf#page=10) x ** yR (参考 ds.k.kyoto-u.ac.jp/wp-content/uploads/2021/10/slide-a02.pdf#page=15) x ^ yいろいろまとめhydrocul.github.io/wiki/programming_languages_diff/number/pow.htmlこぼればなしblog.media.teu.ac.jp/2021/08/post-89817a.html数学関数としてのべき乗としては、ググってみたのですが、以下のウェブページを参照してみてはどうかな、と思いました。(CC-RLライブラリでの計算方法はともかくとして、浮動小数点計算をするものである、単純に x を y 回だけ掛け算するものでは無い、というイメージとしてです。)hiroyukichishiro.com/power-and-exponentiation-in-c-language/「自作関数でべき乗の計算」
NoMaYさん、 KatoNaganoさん、Sugachanceさん皆さんありがとうございます。NAKAです。
元々、MicrochipのSAM71V(intは32bit)での疑問で、RL78で確認してもおかしかったので、お聞き致しました。
元々、回路のハード設計出身でソフトは見様見真似でしっかり勉強してないことを反省してます。
こういう場があるのは本当に助かります。
どうも最近ルネサスのエディタの調子が?です。
アルファベット打ってもカタカナになるし、ヘンテコに入力されるし...?((+_+))
NoMaYさん、NAKAです。
数学的本質みたいなのは理解できてませんが、教えていただいたページは興味深く見させて頂きました。0.5乗はルートだし、そもそも^はEXORですものね!
VBでは^がべき乗みたいですが、今更なにを!って感じですかね!
ちょっと前まで、switch~caseをselect~caseって打って怒られてました (*_*;諸悪の原因はEXCELかな?
NAKAさん、こんにちは。NoMaYです。> 諸悪の原因はEXCELかな?たぶん、NAKAさんの場合、まずはそこでしょうかね。ちなみに、ググってみたのですが、EXCELのべき乗演算(x^y)は、xにもyにも浮動小数点数が使えるようですね。[Excel] べき乗・累乗の計算 - Excel VBA 数学教室excelmath.atelierkobato.com/power/[関連リンク]浮動小数点数の内部表現に関しては以下の検索結果を時間のある時に見ていくと知識が溜まるかな、と思います。あとは、xもyも浮動小数点数である場合の、べき乗の数値計算ライブラリの計算精度、の話のウェブページがあれば良いのかなぁ。(その前に、xもyも浮動小数点数である場合の、べき乗の数値計算ライブラリの計算方法、の話の別のウェブページかなぁ。)Google検索: IEEE浮動小数点数 site:qiita.comwww.google.com/search?q=IEEE浮動小数点数+site:qiita.comfloat型では123456789すらも表現できない話qiita.com/y-yoshinari/items/76260f6359d5b4418b33
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)
NoMaYさん、こんにちは。Sugachanceです。
たとえば序盤に出てきた2^15 = 32768がfloatで受けると 3.276798E+004になっていた事象ですが、これはNAKAさんの仰るような「 浮動小数点自体が仮数部で表現できるのに限界が~」によるものではなく、計算アルゴリズムの時点で既に誤差が発生しているという見解なのでしょうか?doubleで受けても確かに3.276800000000004E+004 なので、計算アルゴリズムの時点で既に誤差というのは何となく理解できますが、計算アルゴリズムの時点で既に誤差 -> floatに入れることによりさらに表現限界の誤差 -> intでさらに…というのが最初の事象として正しいような気がするのですがいかがでしょうか?(関数内部の計算アルゴリズムの時点で登場する変数が正確に全てを表現できる理想的な変数で、それが返ってくるという仕様のものであれば、double,floatの表現限界って話にまとまるのでしょうけども...)
Sugachanceさん、こんにちは。NoMaYです。> floatに入れることによりさらに表現限界の誤差以下のQiitaの投稿で知ったのですけれども、ウェブ上で浮動小数点数の内部表現を確認出来るサイトがありました。そのサイトで、32768(とか32767とか32769とか)の単精度浮動小数点数の内部表現を確認すると、ちゃんと数値全体が収まっていますよ。なので、これらの数値ぴったりの数値が単精度浮動小数点数の内部表現限界の外にあるわけではないのですよ。浮動小数点数内部表現シミュレータtools.m-bsys.com/calculators/ieee754.php0.1の浮動小数点数は0.1より大きいのに、10回足すと1.0より小さいのはなぜか【前編】qiita.com/yucatio/items/85a8e8d381d3000922950.1の浮動小数点数は0.1より大きいのに、10回足すと1.0より小さいのはなぜか【後編】qiita.com/yucatio/items/b5ed14bbd1e9a751b703
NAKAです。
NAKA:浮動小数点自体が仮数部で表現できるのに限界が~
Qiita:0.1を浮動小数点数にすると0.1よりわずかに大きくなるのに、10回足すと1.0より小さいのはなぜか、の答えは、2つの浮動小数点数を足す際に、仮数に入りきらない数を丸めるから、でした。同じ事のような気が........
Qiita:0.1
0.1
1.0
いっそ今回のような場合は自分で累乗の関数を作ったほうが早かったですね!
NAKAさん、こんにちは。NoMaYです。> の答えは、 2つの浮動小数点数を足す際に、仮数に入りきらない数を丸めるから、でした。 同じ事のような気が........いやいや、今回は、以下なのですよ。32768は、数値自体は、内部表現的には、丸める必要など無い数値、なのですよ。> 以下のQiitaの投稿で知ったのですけれども、ウェブ上で浮動小数点数の内部表現を確認出来るサイトがありました。そのサイトで、32768(とか32767とか32769とか)の単精度浮動小数点数の内部表現を確認すると、ちゃんと数値全体が収まっていますよ。なので、これらの数値ぴったりの数値が単精度浮動小数点数の内部表現限界の外にあるわけではないのですよ。そして、丸める必要が無い、という点では、以下の数値もそうである、なのですよ。2、4、8、16、32、64、128、256、、、16384
NoMaYさん NAKAです。>今回は、以下なのですよ。32768は、数値自体は、内部表現的には、丸める必要など無い数値、なのですよ
⇒確かに!単純なNAKAは上記のような関数を作ったほうが早かったなあ!そもそも、依頼元の意図が汲み取れれば2^15を0x8000に変更すればよかっただけだしでも、自信が無いから、大本に出来るだけ忠実にしたほうが....と考えちゃう!(;_;)
でも、ちょっと盛り上がりましたね!(^_-)-☆
解説ありがとうございます。(そのシミュレータはたまに利用させてもらってます!便利ですよね)32768そのものをfloatに入れる分に関してはおっしゃる通り問題ないと思うのですがCのPow()関数がこれまでに出てきたアルゴリズムで実装されているとして```pow関数の中身のアルゴリズムの時点で(^の表現を使ってしまいますが)pow(2,15) = e^(y*log(x)) = 32768とはちょっとずれた値になってしまっている。これをfloatに渡すと近い値の3.276798E+004doubleに渡すと近い値の3.276800000000004E+004```という形"ではない"という事ですかね?Windowsの電卓でたたいてみましたが(おそらくdecimal型?)ln(2) = 0.6931471805599453094172321214581815 * ln(2) = 10.397207708399179641258481821873e^(15 * ln(2) ) = 32768ときれいに計算できました。
一方で内部表現シミュレータに15*ln(2)の結果を入れると10.39720770839917964125848182187310.397207708399179641258481821どちらもdouble型では0x4024cb5ecf0a9651となりました。Windowsの電卓ではe^10.397207708399179641258481821 = 32,767.999999999999999999999971405となったので、コンパイラ依存なのか計算機依存なのかは分かりませんがこういう内部の差が出たのではないかと考えていたのですが…
>でも、ちょっと盛り上がりましたね!皆様の回答を含めて、大変勉強になります。興味深い話題提供、ありがとうございます!