FORMATプロシジャの「FUZZ=オプション」のデフォルト設定が悪さをすることがあります。
まずは「FUZZ=オプション」の説明を交えて紹介していきます。
落とし穴①
「3~5」の値を "aaa" と表示するフォーマットですが、「fuzz=1」というオプションも指定しています。
この「FUZZ=」に指定した値を誤差として「- ~ +」して範囲を拡張することが出来ます。
今回だと「3~5」に「-1 ~ +1」した範囲なので、「2~6」の範囲を "aaa" と表示するフォーマットになります。
では次。ヘンテコな結果になります。
「3より大きく、5より小さい」値に対して "aaa" と表示するフォーマットですが「fuzz=1」によっておかしな結果になります。
FORMATプロシジャで範囲の指定に使う「<」は「大なり、小なり」の意味ではなく「除外」の意味合いがあるようですね。
つまり今回の例では「3<-<5」と「fuzz=1」の組み合わせによって、「2~6」の範囲で「3」と「5」を除く値に "aaa" と表示するフォーマットになっているようです。
📝 まとめ
「FUZZ=」と「<」の組み合わせは危険。
落とし穴②
まず、前提知識として「浮動小数点誤差」の理解から。
以下、2オブザベーションとも値が「0.1」になるはずなのに、、
「if x=0.1 then y=1」の結果、2オブザベーション目の値が何故か「0.1」ではない事が分かります。
これが有名な浮動小数点誤差ってやつで、2オブザベーション目は「0.09999999...」みたいな値が格納されてしまっているわけですね。
データステップ100万回や私の過去記事でも紹介済です。
そしてここから本題。
FORMATを定義した時の浮動小数点誤差の取り扱いを見てみます。
あれ?浮動小数点誤差のデータも「0.1」としてフォーマットをあてられてる??
実は、VALUEまたはPICTUREフォーマット、かつ数値フォーマット(1 = "aaa"のような左辺が数値のフォーマット)では「fuzz=1E-12」という非常に小さな値がデフォルトで設定されています。
浮動小数点誤差で「0.09999999...」みたいに格納されてる値が「0.1」のプラスマイナス「1E-12」の中に入っているため「0.1です」と表示することが出来たわけです。
いい感じじゃん!と思いきや、非常にヘンテコな挙動をする場合があります。
「0.1以上、0.2未満」の範囲のFORMATを作って、それを今回の浮動小数点誤差が起きているデータに割り当てると、、
これは想定通りですね。フォーマットの範囲「0.1 -< 0.2」と「fuzz=1E-12」の組み合わせによって浮動小数点誤差で「0.09999999...」みたいに格納されてる値も「0.1以上、0.2未満」として表示することが出来ました。
例1のフォーマットに「0 -< 0.1」という範囲を追加してみます。
あれ?今度は「0以上、0.1未満」の値としてフォーマットがあてられてる??
これは今回フォーマットに追加した「0 -< 0.1」による範囲に、浮動小数点誤差が起きている「0.09999999...」が入ってしまうため。先にこのフォーマットが適用されてしまったというわけですね。
今度は、例2のフォーマットに「0.2 -< 0.3」という範囲を追加してみます。
あれ?また「0.1以上、0.2未満」の値としてフォーマットあてられてる??
実は変数値がどのフォーマットの範囲に入っているか内部で検索する際、特殊な順番で検索が行われています。
今回は1個目の「0 -< 0.1」ではなく、2個目の「0.1 -< 0.2」の方が先に検索されたためです。
📝 まとめ
範囲を指定するフォーマットは「FUZZ=」の挙動に注意!
「fuzz=0」とすれば範囲の拡張がされなくなりますが、浮動小数点誤差が考慮されなくなってしまうので、そこのケアが必要になります。
解決策は時と場合によって異なるので、適宜ご留意下さい。
0 件のコメント:
コメントを投稿