2024.12.10
“放置系”なのにサイバー攻撃を監視・検知、「統合ログ管理ツール」とは 最先端のログ管理体制を実現する方法
浮動小数点数(全1記事)
リンクをコピー
記事をブックマーク
安原祐二氏(以下、安原):パート4です。大丈夫ですか。寝ていませんか? パート4を始めていきたいと思います。浮動小数点数、floatです。
簡単な問題を出してみましょう。float aに「1f」を入れた時に、Debug.Logでそのaを出力させたらConsoleに何が出ますか? 急に聞かれると困るかもしれませんが、これは引っかけ問題ではなくて「1」が出ます。
次ですね、「1/3」。1割る3を書いたら何になるかな。これはちょっと引っかけ問題かもしれないですね。「0」になります。これは大した話ではありませんが、1f割る3fと書けば0.333になりますが、1割る3だと切り捨てられちゃうよという、わりとどうでもいい話です。
次です。「3e-1f」と書いてあります。これ、わかりますか。これはもう知っているか知らないかだけなのですが、こういうふうに書いても、きちんとコンパイルは通るし理解されます。この答えは「0.3」です。ぜひこれはお家に帰ってやってみてもらいたいですね。
どういうことかというと、eというのが数字の後ろに急に出てきたら、その後ろの数が10のべき乗を掛けていることになるよ、という話です。これは覚えておいたほうがいいでしょうね。2や、ネイピア数ではなく、10です。
という話がありつつ、floatの話をしていきます。ちょっとゴチャゴチャした話になりますが、floatは32bitあって、中身はこうなっているんですね。これは調べるとネット上にいくらでもある情報ですが、符号が1bitあって、指数部が8bitあって、仮数部が23bitあります。
ざっくり言うと、仮数部に2の指数部乗を掛けたもののプラスマイナスが結果になります。
実はこれはちょっと嘘で、(スライドを示して)厳密に言うとこうですね。1.0をベースにしていて、指数部からは127を引いて掛けるというのが、規格上の決まりごとになっています。
なので今001111と書いてありますが、これは、この上の32bitでfloatにした時に、ちょうど1.0を表現できるビットパターンになっています。これはベテランプログラマーはわりと知っていますが、16進でいうと、3f800がfloatの1.0です。
ちょっと限界を探ってみましょう。まず指数部。指数部は規格上、マイナス126からプラス127までいけます。では、2の127がどのくらいの数字なのかと計算してみると、長い数字の後ろのほうにeと書いています。つまり、10の38乗を掛けている。
パート3で対数の話をした時に、だいたい3分の1と3倍の関係という話をしましたが、127の3分の1はだいたい38じゃないですか。これもだいたい合っているんですね。
けっこう大きな値ですね。小さいほうはどれくらいかというと、eのマイナス38乗、つまり10のマイナス38乗というすごく広い値です。
floatには限界があるということをなんとなく知っている方は多いと思います。ですが、実は表現の幅は超絶広いです。どのくらい広いかというと、これはちょっとお遊びで調べてみたのですが、10の36乗を表す、澗(かん)という単位があります。なので、100澗ぐらいの数字が限界になるわけです。この値まで使うことはあり得ないぐらいの大きな値を扱うことができます。
では、小さいほう。調べても調べても、10のマイナス24乗以下の単位が見つかりませんでした。誰か教えてほしいのですが、涅槃寂静(ねはんじゃくじょう)という尊い感じの単位があって、これでもまだ10のマイナス24乗です。なので、マイナス38乗どんだけだよというぐらい小さな値を表現できます。
また、一番下に小さく書きましたが、僕の知識の中で一番小さな物理定数を考えると、ディラック定数というものがあります。10のマイナス34乗なので、これでもぜんぜん大きいですね。
というぐらい小さな値を、実はfloatは表現できます。
ですが、やはり限界はあります。どこに限界があるかというと、むしろこの大きいほうのここです。23bitのほう。つまり大きな数字に小さな数字が足されている場合、表現できないということになります。
例えば(スライドの)下に書いてある、1,000万にすごく小さな値を足すことは、floatでは表現できません。
では、この23bitのほうをちょっと深掘りしてみましょう。この仮数部は、2のマイナス23乗という小さな値を扱えると主張していて、どのくらいの値なのか見てみると、このくらいになります。
1.0に足せる最小の数。floatのビットパターンの一番右側に1を立てて表示させるとこんなふうになります。このぐらいの値が限界ということになります。
1と、この小さな桁が始まるまでの距離は7桁ぐらいです。これも計算するとわりとわかるのですが、log10の2というのは0.3なので、23bitにこの数字を掛けると6.9という値が出てきます。なので、だいたい7桁というのが計算上もわかってくるわけです。
具体的にまずいところへ近づいていきましょうか。(スライドの)一番上ですね、10という数字に一番小さなbitを立てた時はこのぐらいです。100、1,000といって、10,000になった時に0.0009。これが一番小さな単位、解像度です。分解能と言いますが、そういう値になるわけです。
例えばUnityでトランスフォームに値を入れていたとしましょう。原点から10キロ離れたところでなにが起きているかというと、1ミリの分解能が限界になっているわけです。1ミリと1ミリの間、つまり0.5ミリみたいな値を表現できなくなっているということになります。10キロ離れるのはそんなにないかもしれませんが、これは知っておいたほうがよいでしょう。
もっとヤバいのは時間ですね。例えば1.0を1秒にするケースは多いと思いますが、そうすると24時間で86,400秒になるんですね。この状態でどのくらい小さな値が使えるのかというと、計算してみると7.8ミリぐらいが限界になります。
例えば、プログラム上で毎フレームdeltaTimeを足している部分があったとしましょう。24時間これを回していると、16ミリ秒足しているつもりでも分解能が7.8ミリになってしまうので、15ミリしか足されていないみたいな、おかしなことが起きてしまいます。これは明らかにおかしなことが起きるので、気をつけましょう。
実際ヤバいのは知っていても、具体的にどのくらいなのかというのは意外と知らない方が多いと思います。具体的に知っていると、嗅覚が働くというか、「これはヤバいんじゃない?」というのがわかってきます。
そういう問題にぶち当たってから調べるよりもやはり効率はよいので、このへんは知識として知っておくと制作に役立つかなと思います。
ちょっと実験です。原点からzの値をガンガンガンガン足してみました。まだけっこう大丈夫ですが、Standard Shaderで普通に出している男の子がだんだん、だんだん人の形を保てなくなっていくのがわかるでしょうか。
(会場笑)
900キロ離すとかはゲームではちょっとあり得ないと思いますが、ええーヤバい。ヤバい(笑)。ヤバいですね、これは本当にヤバいことがあります。
みなさん、こんなのやらないだろうと思うかもしれませんが、マップゲームとか考えてみてくださいよ。同じアプリで東京とロンドンの家を表現する時に、人によってはずーっと画面を見ていて、連続しているかもしれないですよね。その時にどう対応するのかみたいな、おもしろいですね。
もう人の形を保てなくなっていますが、マップゲームの場合だと、いろいろな対応はあると思いますが、例えば1キロなら1キロで原点に全体をずらすという処理がおそらく必要になるでしょう。
これはなんにも考えずにやった場合で、絶対こうなると考えるのは誤解があります。なので、ちょっとシェーダーを入れ替えます。右側の男の子は、がんばって姿勢を崩さないように僕がシェーダーを書いてみたものです。左側は先ほどと同じですね。
右側の男の子は崩れないのですが、結局シェーダーでがんばっても、アニメーションの部分の精度が落ちるので、首がガクガク動いたりして、結局駄目なのですね。こういう対応をしてもあまり意味はなくて、今は影を出していませんが、影を出すともっとヤバかったりします。ここをシェーダーでがんばる意味はほとんどないです。気をつけましょうという話になります。
おもしろいので、ぜひやってみてください。簡単にできます。トランスフォームのzの値を、ずっと足すだけです。
もう1つやり方があって、double(double precision floating point number)ですね。doubleを推奨したい。先ほど、時間の例がありましたね。86,400という数字があった時に、doubleだったらどうなるかというと、仮数部は52bitなので、24時間経っても0.014ナノ秒までいけます。かなり強力。365日ずーっとアプリを動かし続けても3.7ナノ秒までいけるので、doubleはほとんど無敵に近いですね。
もちろん、毎フレーム300足すとか、もっとヤバいケースがあるかもしれませんが、doubleにしておくと特に時間に関しては大丈夫です。
なので、僕はずっと足していくTimeとかをやる時は、だいたいdoubleを使うようにしています。doubleが遅いかというと、実は計算上はそんなに遅いわけではなくて、現代のプロセッサーだとぜんぜん遅くありません。むしろdoubleのほうが速いプロセッサーもあるぐらいなので、double使っていきましょう。
というわけでパート4が終わりました。floatの限界を具体的に知ってみようという、実験をやってみました。2進数と10進数の桁の関係がわかると、このへんの勘も働くでしょう。このあと公開しますが、ここについてもうちょっと詳しくブログを書いたので、興味ある方はぜひ見てください。というわけで、パート4は終わりです。
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
2024.12.09
10点満点中7点の部下に言うべきこと 部下を育成できない上司の特徴トップ5
2024.12.09
国内の有名ホテルでは、マグロ丼がなんと1杯「24,000円」 「良いものをより安く」を追いすぎた日本にとって値上げが重要な理由
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
2024.12.10
職場であえて「不機嫌」を出したほうがいいタイプ NOと言えない人のための人間関係をラクにするヒント
2024.12.12
今までとこれからで、エンジニアに求められる「スキル」の違い AI時代のエンジニアの未来と生存戦略のカギとは
PR | 2024.11.26
なぜ電話営業はなくならない?その要因は「属人化」 通話内容をデータ化するZoomのクラウドサービス活用術
PR | 2024.11.22
「闇雲なAI導入」から脱却せよ Zoom・パーソル・THE GUILD幹部が語る、従業員と顧客体験を高めるAI戦略の要諦
2024.12.11
大企業への転職前に感じた、「なんか違うかも」の違和感の正体 「親が喜ぶ」「モテそう」ではない、自分の判断基準を持つカギ