メイン コーダーズルーム【スクリプト系】 浮動小数点の演算について | 投稿するにはまず登録を |
スレッド表示 | 古いものから | 前のトピック | 次のトピック | 下へ |
投稿者 | スレッド |
---|---|
kumaneko | Åê¹ÆNo.13711 投稿日時: 2004-12-29 11:34 |
新米 居住地: 北海道 投稿: 4
使用環境:
Win98,Win2000 Flash MX Win 9,0,28,0 |
Re: 浮動小数点の演算について ちょっと遅れてしまいましたが
Salvoxさん、野中さん、ありがとうございます。 引用:
結局は、Salvoxさんが書かれているような感じで、 必要な桁までで見切りをつけてそれ以下は「Math.floor()」で落として回避することにしました。 「DDA(Digital Differential Analyzer)」調べてみましたが、なかなか面白いですねコレ。 「加算・減算のみで実数計算を含まないアルゴリズム」なんですね。 なかなか面白そうなので自分なりにちょっと調べてみたいと思います。 MCプロパティーなどは、なるべく16進数表記で値を入れるっていうのも凄く参考になりました! 引用:
ユーザーなら登録できるような気がしますが、どうなのかな? 僕自身、ココはユーザー登録したばかりなので詳しい登録の仕方までは、ちょっと分からないです。 面白そうなので、是非見てみたいですね。>モーション・ライブラリー(AS 1.0用) 野中さんの書き込みの「特殊な事情」もなかなか興味深い話ですね。 しかし、_alpha=1%の画像で印刷されないようにするってのは、凄いアイデアですね。(知恵ですね!) プロジェクタの使用が許されるのであれば無敵ですね。(さすがにキャプチャは防げないですけど) なんだか、すごく勉強になりました。(^^) |
salvox | Åê¹ÆNo.13664 投稿日時: 2004-12-26 16:19 |
常連 居住地: 東京都 投稿: 73
使用環境:
Windows2000 FlashMX テキストエディター:EmEditor |
Re: 浮動小数点の演算について そうそう、そうなんですよね。
以前、野中さんがココかF-siteで、 _alphaの内部演算が256階調(すなわち8bit)と書いていたので、その時以来、MCプロパティー系は、納期が迫ってきてる時以外は、なるべく16進数表記で記述しています。 理由は丸め誤差だけじゃなく、特に_alphaは_xとかと違って、演出系で多用する為、毎回演算しなきゃいけない。100/256をもっと追求した結果、行き着いたのが、16進数でした。 それより(^^)! 引用: さらに特殊な事情が加わっています 1%のアルファーか?ぁ。 これは、目からウロコ!確かに、僕も盲点でした。 恐らく、少しでもASを触ったことがあれば、あるほど、 盲点でしょうね。僕も使わせて頂きます。(^^)ゴチ
|
野中文雄 | Åê¹ÆNo.13651 投稿日時: 2004-12-26 6:07 |
ちょんまげら 居住地: 東京 投稿: 4531
使用環境:
CS5.5 .6.8 Vista Home Premium (SP1) |
Re: 浮動小数点の演算について MovieClip._alphaプロパティについては、さらに特殊な事情が加わっています。そして、16進数で考えることが、まさに正解だったりします。
引用: salvoxさんは書きました: |
salvox | Åê¹ÆNo.13649 投稿日時: 2004-12-26 4:58 |
常連 居住地: 東京都 投稿: 73
使用環境:
Windows2000 FlashMX テキストエディター:EmEditor |
Re: 浮動小数点の演算について ど?も、Salvoxです。
(相変わらず話が終わってるものに、蛇足を書き込んでしまいたくなる・・・)。 引用: そこで、Flash使いの皆さんの判断を聞きたく、また実験結果を載せることにしました。 で、原因については野中さんに言われてしまったので、 僕は現場での経験から。 このフォーラムにも書いてあったと思うのですが、 Flashの内部演算は8bitでおこなわれてるらしい・・・。 だもんで、this._x += 1; とか、特に多いのは、this._alpha += 5;とかした時に、_alpha値が単純に10進数倍を取らず、 10.989864126...みたく小数点を含んで増減していくことがあると思います。理由は野中さんが言われた丸め誤差の原因と同じです。 実は、これが厄介もんで、たとえば、 _alpha値を、100でとめたつもりが、数値上では99.2222とかになって微妙にアルファーが掛かったまんまで、デザイナーに『表現が違うんだけど…』(こまか??!!)とか言われちゃったり、 もっと厄介だったのが、座標軸もので、最近ではそうは判定してないのですが、まだ僕が駆け出しだったころ、if(this._x == 100) みたいに、ジャストで判定していたり、if(this._x < 100)とかで 判定していると、永遠に100にならない場合がおきたり、1pxにも拘るデザイナーに、『ズレてるんだけど…』(細かいんだよ!!)とか言われちゃったりして、大変な思いをしたことがあります。 で、そんなこんで、導いた対策(っというか常識?) なるべく浮動小数点演算は避ける。と、直接、値をぶち込む時は なるべく16進数表記(0x64)とかで値をいれると、かなり都合が(期待が)いい結果を得られます。 アルファーを変える時、座標を変える時は、元となる_x座標や各種値を事前にint()で、整数に変換してから演算したり、sin() や cons()を使う上でも、最終的に必要な値は整数で十分ですから、切り落としてから返して、次の処理の為に、場に散らばる浮動小数点を徹底的に排除しています。その方が演算も早いし、何よりバグになりにくい!!。 kumanekoさんがどういった内容を処理しているのか、分からないので的確なアルゴリズムが紹介できませんが、参考になるものとして、DDA(Digital Differential Analyzer)などがあります。 結構、簡単なアルゴリズムなので、ソースみれば即実装できると思います(一応、高速なアルゴリズムとされています)。 ↑余談ですが、僕が現在使ってるモーション・ライブラリー(AS 1.0用)を近じか公開したいなぁ?なんて考えてたりします。 アルゴリズムはDDAを基本にしていますが、製作現場での実装に絶える仕様にする為、一年かけて改良し(これのどこがDDAやね?ん!)って言わんばかり、高速(自称)! になってます(自負(笑))。 ここの『ダウンロード』って、僕でも登録できるんですかね??
|
kumaneko | Åê¹ÆNo.13644 投稿日時: 2004-12-25 23:30 |
新米 居住地: 北海道 投稿: 4
使用環境:
Win98,Win2000 Flash MX Win 9,0,28,0 |
Re: 浮動小数点の演算について 野中さん、回答有り難うございます。
今まで、こんなに細かい値を扱うことがなかったもので、ちょっと気になってしまいまして。 で、色々実験してみたらJavaScriptと違うな?って思ってしまったもので。(苦笑) 引用: 有効桁数15桁ということは、値をすべて16桁目で四捨五入して扱うということではなく、16桁目以降の値が誤差を含んでいることを意味するだけです。 その辺は、まだまだ認識不足ですね。勉強になりました。 まずは、野中さんの「太鼓判」が出たので安心致しました。 「数値計算の落とし穴」と「IEEE754 Floating Point Number」は今後の参考にさせて頂きます。 あとは、自分なりに調べて勉強していこうと思います。 いろいろと分かりやすく解説していただき、有り難うございました。m(_ _)m |
野中文雄 | Åê¹ÆNo.13614 投稿日時: 2004-12-23 21:45 |
ちょんまげら 居住地: 東京 投稿: 4531
使用環境:
CS5.5 .6.8 Vista Home Premium (SP1) |
Re: 浮動小数点の演算について 疑問とされている点が、よく理解できません。有効桁数が15桁で、「15桁は特に問題は見当た」らなければ、それで問題ないような気がします。
こういうことでしょうか? 仮に、有効桁数が1桁だとしましょう。
kumanekoさんは、有効桁数1桁のaの値として「0.5」を期待されるということですか?「0.7」(正確な計算結果は0.715)という値の方が、ふさわしくありませんか? つまり、「計算した結果の値」として、有効桁数までの数値が正確な数値の近似値として使えるということです。具体的には「0.7」と「0.715」は、ともに小数点以下第2位で四捨五入すれば、等しい値になります。 有効桁数15桁ということは、値をすべて16桁目で四捨五入して扱うということではなく、16桁目以降の値が誤差を含んでいることを意味するだけです。 引用: kumanekoさんは書きました: 正確には、コンピュータのビットの扱いを、知る必要があると思います。この点は私も詳しくありませんので、インターネットなどでお調べいただくのがよいでしょう。取りあえず、以下のようなドキュメントがありました。 「数値計算の落とし穴」 「IEEE754 Floating Point Number」 |
kumaneko | Åê¹ÆNo.13613 投稿日時: 2004-12-23 19:01 |
新米 居住地: 北海道 投稿: 4
使用環境:
Win98,Win2000 Flash MX Win 9,0,28,0 |
Re: 浮動小数点の演算について ひろゆきさん、野中さん、はじめまして。
回答ありがとうございます。 「まるめ虫」と「二星まるめ虫(フタボシマルメムシ)」は参考になるし面白かったです。 「ファーブル野中のBUG博物誌」も見てみたかったけどリンク切れだったのが残念でした... 「データ型」も参考にさせていただきました。 「演算結果が半端な値になる(丸め誤差)」も分かりやすく書かれていて、とても参考になりました。 結局はコンピュータは2進数で計算しているってことですね。 で、10進数は2進数で正確に表せないってことになってしまうんですよね。 関係ないですが、Macromediaの「Fact of Life(人生の現実)」はなかなか上手い言葉ですね。(^^) それで試しに今度は計算による値ではなくて、単純に数値を生成して比較するスクリプトを作って実験してみました。 簡単に説明すると、有効桁数以上の数値を文字列として生成して、それを数値に変換して判定用の「1」と比較させるものです。 これで、演算で出た丸め誤差が原因なら今回は正しく判定できるはずですよね。(有効桁数での丸め誤差は発生しますが) ただ単純に「数値を比較してみよう!」というものですね。 結論から言うと、やっぱり納得のいかない結果が出てしまいました。(^^;) 有効桁で丸められた値と内部で扱っている値が少し違っているような気がします。 有効桁数に丸めるときのFlashの振る舞いが、ちょっと奇妙なんです。 そこで、Flash使いの皆さんの判断を聞きたく、また実験結果を載せることにしました。 一応、スクリプトを実行しなくても分かるように実行結果を載せましたので、ちょっと長いかもしれないですが勘弁してください。 以下は実験に使ったスクリプトです。(もし間違っていたら教えて下さい)
ここから、結果と報告です。 ========================================================================= 判定値(A)=1 値作成用初期値(B)=0.99999999999999999 B値は小数点以下 17桁です。 生成されるNUM値は小数点以下 18桁です。 NUM「0.999999999999999999」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999998」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999997」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999996」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999995」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999994」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999993」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999992」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999991」は、A「1」と同じ。 NUM=1, A=1 NUM「0.999999999999999990」は、A「1」と同じ。 NUM=1, A=1 ========================================================================= 小数点以下を18桁で実験すると、NUM値は丸められて「1」になり判定値の「1」と同じと判断されますね。 それに、値の丸めには18桁目は影響していなく、17桁目で判断され値が丸められていると思われます。 次は、初期値(B)を1桁減らして小数点以下を17桁にします。 その結果が以下です。 ========================================================================= 判定値(A)=1 値作成用初期値(B)=0.9999999999999999 B値は小数点以下 16桁です。 生成されるNUM値は小数点以下 17桁です。 NUM「0.99999999999999999」は、A「1」と同じ。 NUM=1, A=1 NUM「0.99999999999999998」は、A「1」と同じ。 NUM=1, A=1 NUM「0.99999999999999997」は、A「1」と同じ。 NUM=1, A=1 NUM「0.99999999999999996」は、A「1」と同じ。 NUM=1, A=1 NUM「0.99999999999999995」は、A「1」より小さい。NUM=1, A=1 NUM「0.99999999999999994」は、A「1」より小さい。NUM=1, A=1 NUM「0.99999999999999993」は、A「1」より小さい。NUM=1, A=1 NUM「0.99999999999999992」は、A「1」より小さい。NUM=1, A=1 NUM「0.99999999999999991」は、A「1」より小さい。NUM=1, A=1 NUM「0.99999999999999990」は、A「1」より小さい。NUM=1, A=1 ========================================================================= NUM値は丸められて「1」になっていますね。 数値の判定を見ると...なぜか「1」以下と判定されてしまいます。 それも、「四捨五入」ではなく「五捨六入」という不思議な処理をしています。 数値の丸めって「四捨五入」ですよね。 この時点で「表示上のNUM値」と「判定上のNUM値」に違いが生じていますよね。 これは何故???(^^;) さらに、初期値(B)を1桁減らして小数点以下を16桁にします。 すると... ========================================================================= 判定値(A)=1 値作成用初期値(B)=0.999999999999999 B値は小数点以下 15桁です。 生成されるNUM値は小数点以下 16桁です。 NUM「0.9999999999999999」は、A「1」より小さい。NUM=1, A=1 NUM「0.9999999999999998」は、A「1」より小さい。NUM=1, A=1 NUM「0.9999999999999997」は、A「1」より小さい。NUM=1, A=1 NUM「0.9999999999999996」は、A「1」より小さい。NUM=1, A=1 NUM「0.9999999999999995」は、A「1」より小さい。NUM=1, A=1 NUM「0.9999999999999994」は、A「1」より小さい。NUM=0.999999999999999, A=1 NUM「0.9999999999999993」は、A「1」より小さい。NUM=0.999999999999999, A=1 NUM「0.9999999999999992」は、A「1」より小さい。NUM=0.999999999999999, A=1 NUM「0.9999999999999991」は、A「1」より小さい。NUM=0.999999999999999, A=1 NUM「0.9999999999999990」は、A「1」より小さい。NUM=0.999999999999999, A=1 ========================================================================= 「表示上のNUM値」は小数点以下16桁目で丸められてはいます(「四捨五入」してますね)が、 判定値(A)の純粋な「1」より小さな値として判断されてしまっています。 本来なら、NUM値「0.9999999999999995」のところから上は丸められて「1」 として認識されていなくてはいけないと思うのですが... これも何故???(^^;) さらに、初期値(B)を1桁減らして小数点以下を15桁にします。 ========================================================================= 判定値(A)=1 値作成用初期値(B)=0.99999999999999 B値は小数点以下 14桁です。 生成されるNUM値は小数点以下 15桁です。 NUM「0.999999999999999」は、A「1」より小さい。NUM=0.999999999999999, A=1 NUM「0.999999999999998」は、A「1」より小さい。NUM=0.999999999999998, A=1 NUM「0.999999999999997」は、A「1」より小さい。NUM=0.999999999999997, A=1 NUM「0.999999999999996」は、A「1」より小さい。NUM=0.999999999999996, A=1 NUM「0.999999999999995」は、A「1」より小さい。NUM=0.999999999999995, A=1 NUM「0.999999999999994」は、A「1」より小さい。NUM=0.999999999999994, A=1 NUM「0.999999999999993」は、A「1」より小さい。NUM=0.999999999999993, A=1 NUM「0.999999999999992」は、A「1」より小さい。NUM=0.999999999999992, A=1 NUM「0.999999999999991」は、A「1」より小さい。NUM=0.999999999999991, A=1 NUM「0.999999999999990」は、A「1」より小さい。NUM=0.99999999999999, A=1 ========================================================================= これは、別になんともないですね。(当たり前ですが) とどめにもう一回チェック。 判定値(A)を「0.999999999999999」(小数点以下15桁)にして再度実行。 ========================================================================= 判定値(A)=0.999999999999999 値作成用初期値(B)=0.999999999999999 B値は小数点以下 15桁です。 生成されるNUM値は小数点以下 16桁です。 NUM「0.9999999999999999」は、A「0.999999999999999」より大きい。NUM=1, A=0.999999999999999 NUM「0.9999999999999998」は、A「0.999999999999999」より大きい。NUM=1, A=0.999999999999999 NUM「0.9999999999999997」は、A「0.999999999999999」より大きい。NUM=1, A=0.999999999999999 NUM「0.9999999999999996」は、A「0.999999999999999」より大きい。NUM=1, A=0.999999999999999 NUM「0.9999999999999995」は、A「0.999999999999999」より大きい。NUM=1, A=0.999999999999999 NUM「0.9999999999999994」は、A「0.999999999999999」より大きい。NUM=0.999999999999999, A=0.999999999999999 NUM「0.9999999999999993」は、A「0.999999999999999」より大きい。NUM=0.999999999999999, A=0.999999999999999 NUM「0.9999999999999992」は、A「0.999999999999999」より大きい。NUM=0.999999999999999, A=0.999999999999999 NUM「0.9999999999999991」は、A「0.999999999999999」より大きい。NUM=0.999999999999999, A=0.999999999999999 NUM「0.9999999999999990」は、A「0.999999999999999」と同じ。 NUM=0.999999999999999, A=0.999999999999999 ========================================================================= 判定値(A)=0.999999999999999 値作成用初期値(B)=0.99999999999999 B値は小数点以下 14桁です。 生成されるNUM値は小数点以下 15桁です。 NUM「0.999999999999999」は、A「0.999999999999999」と同じ。 NUM=0.999999999999999, A=0.999999999999999 NUM「0.999999999999998」は、A「0.999999999999999」より小さい。NUM=0.999999999999998, A=0.999999999999999 NUM「0.999999999999997」は、A「0.999999999999999」より小さい。NUM=0.999999999999997, A=0.999999999999999 NUM「0.999999999999996」は、A「0.999999999999999」より小さい。NUM=0.999999999999996, A=0.999999999999999 NUM「0.999999999999995」は、A「0.999999999999999」より小さい。NUM=0.999999999999995, A=0.999999999999999 NUM「0.999999999999994」は、A「0.999999999999999」より小さい。NUM=0.999999999999994, A=0.999999999999999 NUM「0.999999999999993」は、A「0.999999999999999」より小さい。NUM=0.999999999999993, A=0.999999999999999 NUM「0.999999999999992」は、A「0.999999999999999」より小さい。NUM=0.999999999999992, A=0.999999999999999 NUM「0.999999999999991」は、A「0.999999999999999」より小さい。NUM=0.999999999999991, A=0.999999999999999 NUM「0.999999999999990」は、A「0.999999999999999」より小さい。NUM=0.99999999999999, A=0.999999999999999 ========================================================================= 全部載せるのは長いので肝心のところだけ。 まず、16桁の方ですが、表示上は四捨五入で丸められて「1」と表示されますが、 NUM値「0.9999999999999991」?「0.9999999999999994」では判定が正しく行なわれていない。 四捨五入されているのであれば、「同じ値」として処理されるのが本来だと思います。 ということは、やはり16桁目も判定処理に使われているってことになってしまいますよね。 「0.9999999999999990」は「0.999999999999999」と等しいのは問題なしですね。 15桁は特に問題は見当たりません。 結果的に、内部では16桁で、表示するときに15桁に丸めているってことなのでしょうか? でも、Flashは公称で有効桁数が15桁なはずですよね...う?ん..... こういう仕様なのでしょうか? 内部の値と表示の値が違ってしまっては正しい処理が出来ませんし。 これが仕様だとは思えないのですが... 如何なものでしょう? 画像を動かしたり簡単な計算をさせる上では、特に支障はないと思いますが、 非常に微妙な数値を扱って判断させたりする場面では、ちょっと厄介になってきますよね。 個人的にどうにも腑に落ちなくて納得がいかない「Flashの動作」なんですよね。 新種の虫でもいるんでしょうか、なんか不可解な現象です。(苦笑) この辺の、明確な回答を頂けると非常に助かります。 よろしくお願い致します。 P.S. 一行の文字数が多いため、変な所で改行されて見づらかったらスミマセン。 書き込み初心者なもので許してやってくださいませ。 |
野中文雄 | Åê¹ÆNo.13555 投稿日時: 2004-12-21 21:13 |
ちょんまげら 居住地: 東京 投稿: 4531
使用環境:
CS5.5 .6.8 Vista Home Premium (SP1) |
Re: 浮動小数点の演算について 最終的な参照ドキュメントは、「演算結果が半端な値になる(丸め誤差)」になります。サイトのサーバー移設などがあったため、古いリンクが一部切れてしまっているようです。
引用: ひろゆきさんは書きました: コンピュータの立場に立ってみるとよいでしょう。
なお、人間は通常10進法、コンピュータは2進法で計算します。ですから、人間の目から見て切りのいい数値でも、コンピュータにとってもそうとはかぎりません。人間に理解できる10進法に表示する時点で、誤差を発生していることがあります(たとえば、上記cの値を小数点以下15桁で教えてと聞かれたら1.00...と答えますよね?)。 引用: kumanekoさんは書きました: |
ひろゆき | Åê¹ÆNo.13549 投稿日時: 2004-12-21 19:21 |
ちょんまげら 居住地: 東京砂漠 投稿: 4403
使用環境:
10.8.5 Flash Professional CS4/CS6/CC Safari 6.1 |
Re: 浮動小数点の演算について このあたり が参考になるかもしれません。
|
kumaneko | Åê¹ÆNo.13534 投稿日時: 2004-12-21 17:17 |
新米 居住地: 北海道 投稿: 4
使用環境:
Win98,Win2000 Flash MX Win 9,0,28,0 |
浮動小数点の演算について 皆さま、はじめまして。
初めての投稿になりますが、よろしくお願い致します。 もしかしたら、すごく初歩的な質問なのかもしれませんが、 スクリプトで演算させていたところ 演算結果が合わないという事態に遭遇しました。 テストとして以下の2種類のスクリプトを実行して比較してみます。 ?演算テスト その1?
すると、出力ウインドウに a=0.999999999999999 b=1e-15 c(a+b)=1 d(c-b)=0.999999999999999 e(d-a)=0 と表示されるのですが、これは問題ありませんよね。 で、次に以下を実行してみます。 ?演算テスト その2?
すると今度は、 a=0.999999999999999 b=1.1e-15 c(a+b)=1 d(c-b)=0.999999999999999 e(d-a)=-1.11022302462516e-16 と表示されます。 ここで問題になってくるのが、 「e(d-a)=0」にならないって事です。 表示では「d(c-b)=0.999999999999999」の筈が、 「a=0.999999999999999」と合わないんですね。 その場合「a」の値と「d」の値を比較させて条件分岐したい場合に支障が出てきてしまいますよね。 内部演算の仕方とかは分からないし、 ましてプログラマーってわけでもないので、 浮動小数点の演算の仕組みとか詳しいこともわからないですし、 もしかしたら見当違いのことを言っているかもしれません。 だけど、なぜ「表示上では同じ値」なのに「0」にならないのか不思議なのです。 同じような計算を「JavaScript」(1桁増やしてますが)でやってみると、きちんと「e(d-a)=0」になりますし。 一応、ページにしてみました。 テストページ それで、できれば回避したいのですが、やっぱり「Math.round()」とかで、
このようにしないとダメなのでしょうか? 見かけ上は同じ値なのにエラー(条件分岐で)が出たので気がついたのですが、 ウチだけ特殊ってことはないですよね。(汗) ご意見を頂ければと思って書き込みました。 よろしくお願い致します。 |
スレッド表示 | 古いものから | 前のトピック | 次のトピック | トップ |
投稿するにはまず登録を | |