2014年6月5日木曜日

Objective-Cで0.1+0.2が0.3にならない?

新作アプリ『パズオペ』は計算式を作るパズルゲームです。


数字と演算子を組み合わせて、正しい計算式を作って行きます。

ところが、小数も計算できるようにしていたら不具合が発生しました。
具体的には『0.1+0.2=0.3』とすると、なぜか不正解と判定されてしまうからです。


=================

double num1 = 0.1;
double num2 = 0.2;
double num3 = 0.3;
double ans = num1 + num2;

//比較
if (ans == num3) {
    NSLog(@"YES");
} else {
    //こちらが表示される
    NSLog(@"NO");
}

=================


これは私もすっかり頭から抜け落ちていたのですが、小数の値が二進数では表現できないことによる誤差が原因でした。

そもそも、プログラム内部では値を二進数で計算しています。
十進数の『0.1』は二進数だと『0.0001100110011…』となり循環小数となってしまいます。
演算するときはどこかで丸められてしまうので、十進数の値とは誤差が生じてしまうというわけです。

Objective-Cではそういう場合は『NSDecimalNumber』を使って対処します。

=================

NSDecimalNumber *decimal1 = [NSDecimalNumber decimalNumberWithString:@"0.1"];
NSDecimalNumber *decimal2 = [NSDecimalNumber decimalNumberWithString:@"0.2"];
NSDecimalNumber *decimal3 = [NSDecimalNumber decimalNumberWithString:@"0.3"];
NSDecimalNumber *decimalAns = [decimal1 decimalNumberByAdding:decimal2];

//比較
if ([decimalAns isEqualToNumber:decimal3]) {
    //ちゃんとこちらが表示される
    NSLog(@"YES!!");
} else {
    NSLog(@"NO!!");
}

=================

プログラムを書いていると、内部は二進数で…ということは忘れがちです。
これはどの言語でもある現象なので、覚えておくと良いでしょう。


せり上がってくる数字と演算子で計算式を作り消して行く
5つ正解でクリアー、全30ステージの知育系パズルゲーム


0 件のコメント:

コメントを投稿