acosの計算がバグる原因【Objective-C】

公開: 2015-06-15 10:30
更新: 2016-04-29 06:03

どうもみなさんこんにちは。

昨日「世の中が全てがコピー製品で、本当の本物を探す旅に出る」という夢を見ました。これをネタに小説家になろうと思います。(いけるね。


Objective-Cでacosの計算を使いました。
acosとはcosの逆関数で、cosとは包み焼きハンバーグが美味しいファミリーレストランの略称です。


そんでもって次のような計算で、
二つのベクトルが作る角度を求めていました。

CGVector v1 = {..., ...};
CGVector v2 = {..., ...};
CGFloat d1 = |v1|;
CGFloat d2 = |v2|;
CGFloat a = acos((v1.dx*v2.dx+v1.dy*v2.dy)/(d1 * d2));

すると時々
a = nan になることが。



d1かd2が0の時は省いてたので、
なんだろうと思って各変数のログをNSLogでとってみることに。



するとこんな感じ。

[Line 484] v1:{12.5, 11.5} v2:{12.272937708633577, 12.272937708633577} d1:16.985288 d2:17.356555
[Line 486] a:0.041643
[Line 484] v1:{11.5, 11.5} v2:{12.010412149464315, 12.010412149464315} d1:16.263456 d2:16.985288
[Line 486] nan

ほうほう。

この計算って普通acos(1)になるからa = 0になるはずの計算なのですが。


試しにこの値を入力して、ログを取ってみよう。

CGVector v1 = (CGVector){11.5, 11.5};
CGVector v2 = (CGVector){12.010412149464315, 12.010412149464315};
CGFloat d1 = 16.263456;
CGFloat d2 = 16.985288;
CGFloat a = acos((v1.dx*v2.dx+v1.dy*v2.dy)/(d1 * d2));
NSLog(@"%lf",a);
0.000182

あれ???

nanにならない。というか0にもならない。



あ、

CGVector v1 = (CGVector){11.5, 11.5};
CGVector v2 = (CGVector){12.010412149464315, 12.010412149464315};
CGFloat d1 = sqrt(v1.dx*v1.dx + v1.dy*v1.dy);
CGFloat d2 = sqrt(v2.dx*v2.dx + v2.dy*v2.dy);
CGFloat a = acos((v1.dx*v2.dx+v1.dy*v2.dy)/(d1 * d2));
NSLog(@"%lf",a);
nan

おーっ出た出た。


って、いやいや。
なんでさっきのが0にならないでこっちがnanになるんだよ。というかなんでnanになるんだよ。





原因は?

とりあえず解決方法をズバッと言っちゃうと、

acos((v1.dx*v2.dx+v1.dy*v2.dy)/(d1 * d2));

「acos()」ではなく、



acosf((v1.dx*v2.dx+v1.dy*v2.dy)/(d1 * d2));

「acosf()」を使えば治ります。


さらに同様に「sqrt()」ではなく、「sqrtf()」を使うべきです。

今回のバグは、floatとdoubleの精度の違いから来ているものなのでしょうか?





いやでもちょっと待って、CGFloatって?

こんな記事があります。

⇒ iOS - 本当は怖いCGFloat - Qiita

64bitアーキテクチャではdouble, それ以外(32bit)ではfloatとして定義されています。

今回検証した環境は64bitです。

でもdouble用の関数acosに入れるとぶっ壊れます。

定義ではdouble扱いだけど、CGFloatはやはりfloatだってことですか?



さらによく調べてみると分かりそうだけど、

とりあえず、小数の丸め込みあたりでおかしくなってるっぽいと納得することに。

あと、細かい計算は精度の低いf付きのfloat用の関数を使うことにしよう。詳しくはまた調べたら更新しまうす。

(だれか詳しい人教えてっ)



ではでは。



この記事をシェア
この記事にコメントする
書き込む
あっきぃ(@appstars_aki)
Web、iOSなフリーランサーです。好きなものはお寿司です。でもお寿司は高いので普段は雑草とか拾ったドングリを食べています。お仕事や意味もなく毎月お小遣いをくれる人を探してます。

お仕事の依頼や自分で作ったアプリのレビューを希望しちゃう方はaki@appstars.jpまでご連絡ください。