次のテスト コードでは、アサートが失敗します。
NSDecimalNumber *num1 = [[NSDecimalNumber alloc] initWithInteger:1];
NSDecimalNumber *num2 = [[NSDecimalNumber alloc] initWithInteger:6];
NSDecimalNumber *num3 = [[NSDecimalNumber alloc] initWithInteger:3];
NSDecimalNumber *result1 = [num1 decimalNumberByDividingBy:num2]; // 1 ÷ 6
NSDecimalNumber *result2 = [result1 decimalNumberByMultiplyingBy:num3]; // 1 ÷ 6 x 3 = 0.5
NSDecimalNumber *num4 = [[NSDecimalNumber alloc] initWithFloat:0.5];
NSAssert([result2 compare:num4] == NSOrderedSame, @"Math error");
これは浮動小数点の精度に関係していることを理解しています。1 ÷ 6 で問題が発生します。結果 2 は、0.5 ではなく 0.4999999999999999999999999999999999998 です。
2 つの数式が同じ結果をもたらすことを検証しようとしています。この目的で比較を使用するのではなく、2 つの NSDecimalNumbers の間のわずかな差を許容する必要がありますか? それとも、decimalNumberByDividingBy:withBehavior: メソッドを使用して丸めを行う必要がありますか? どのように進めればよいかわかりません。理想的には、結果 2 は 0.5 であり、比較をハックする必要はありません。
編集:これは、比較段階で許容範囲アプローチを使用して進めることを考えている方法です(理想的ではありません)-
- (NSDecimalNumber *)abs:(NSDecimalNumber *)num {
if ([num compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber * negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [num decimalNumberByMultiplyingBy:negativeOne];
} else {
return num;
}
}
- (void)test {
NSDecimalNumber *num1 = [[NSDecimalNumber alloc] initWithInteger:1];
NSDecimalNumber *num2 = [[NSDecimalNumber alloc] initWithInteger:6];
NSDecimalNumber *num3 = [[NSDecimalNumber alloc] initWithInteger:3];
NSDecimalNumber *result1 = [num1 decimalNumberByDividingBy:num2]; // 1 ÷ 6
NSDecimalNumber *result2 = [result1 decimalNumberByMultiplyingBy:num3]; // 1 ÷ 6 x 3 = 0.5
NSDecimalNumber *num4 = [[NSDecimalNumber alloc] initWithFloat:0.5];
NSDecimalNumber *tolerance = [[NSDecimalNumber alloc] initWithFloat:0.000000000001];
NSDecimalNumber *delta = [self abs:[result2 decimalNumberBySubtracting:num4]];
NSAssert([delta compare:tolerance] == NSOrderedAscending, @"Math error");
}