1

私はそのNSMutableArray中にいくつかを持っていますNSDecimalNumber、のように(500,50.80,70,8000)

decimal numbers今、私はそれらすべてを一緒に追加したいと思います。

使ってみました

for (NSDecimalNumber *number in self.numbersArray)
{
    NSDecimal *sum += [number decimalValue]
}

しかし失敗しました。

4

3 に答える 3

5

配列にすべてのsを追加する簡単な方法NSNumberは、次のとおりです(@Mahonorがコメントで言ったことと同様)。

NSArray *myArray = ... // array of NSNumber (or NSDecimalNumber) objects
NSNumber *sum = [myArray valueForKeyPath:@"@sum.self"];

コレクション演算子:sumの状態とは異なり、配列内の数値はに変換されませんdoubleが、に変換されNSDecimalます。したがって、10進数を加算するときに精度が失われることはありません。NSNumber10進数ではないオブジェクトでもNSDecimal、加算のために変換されます。合計の結果はのインスタンスですNSDecimalValue

私は2つの異なる方法でそれを検証しました(または試みました)。まず、このコードを実行しました

NSNumber *a = [NSNumber numberWithDouble:1.2];
NSNumber *b = [NSDecimalNumber decimalNumberWithString:@"-5.7"];
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];

環境変数「NSObjCMessageLoggingEnabled=YES」を設定して、Objective-Cメッセージロギングをアクティブにしました。作成された「/tmp/ msgSends-NNNN」ファイルに見られるように、decimalNumber(ではなくdoubleValue)両方の番号オブジェクトに送信されます。

次に、との両方decimalValueを実装するカスタムクラスを作成し、カスタムクラスのオブジェクトの配列にdoubleValue適用しました。@sum.self

@interface MyClass : NSObject
@property (nonatomic, assign) double value;
@end

@implementation MyClass

- (NSDecimal)decimalValue
{
    return [[NSNumber numberWithDouble:self.value] decimalValue];
}

- (double)doubleValue
{
    return self.value;
}

@end

MyClass *a = [MyClass new]; a.value = 1.2;
MyClass *b = [MyClass new]; b.value = -5.7;
NSArray *myArray = @[a, b];
id sum = [myArray valueForKeyPath:@"@sum.self"];

両方のメソッドにブレークポイントを設定することによりdecimalValue、合計にのみ使用されることがわかります(valueForKeyPath:@"@sum.self"クラスが実装されていない場合は例外をスローしますdecimalValue)。

decimalValueそれがから呼び出されていることもわかります

-[NSArray(NSKeyValueCoding) _sumForKeyPath:]

このメソッドのアセンブラコードはNSDecimalAdd、が数値の加算に使用されることを示しています。

于 2013-03-13T10:54:06.107 に答える
3

使用する- (NSDecimalNumber *)decimalNumberByAdding:(NSDecimalNumber *)decimalNumber

NSDecimalNumberクラスリファレンスをご覧ください

NSDecimalNumber *lNumber = [NSDecimalNumber zero];
for (NSDecimalNumber *number in self.numbersArray)
{
    lNumber = [lNumber decimalNumberByAdding:number];
}
于 2013-03-13T06:53:29.460 に答える
1

コメントでのマノハールの提案は悪くない。実際、KVCコレクション演算子を使用してこれからワンライナーを作成することはでき[myArray valueForKeyPath:@"@sum.doubleValue"];ますが、精度が低下する可能性があります(保存した数値によって異なります)。

基本的に「削減」機能を探しています。decimalNumberByAdding:各呼び出しが引数として配列の後続要素を持つように、呼び出しをチェーンする必要があります。でこれを行うのNSArrayは簡単です。performSelector:withObject:

@implementation NSArray (Reduce)
- (id)reduceUsingSelector: (SEL)sel
{
    id res = [self objectAtIndex:0];
    for( id obj in [self subarrayWithRange:(NSRange){1, [self count]-1}] ){
        res = [res performSelector:sel withObject:obj];
    }

    return res;
}
@end

次のように使用します。NSDecimalNumber * sum = [myArray reduceUsingSelector:@selector(decimalNumberByAdding:)];

NSDecimal構造体であり、オブジェクトではないため、使用しているコードは成功しません。ポインタとして宣言するべきではありません。宣言しないと、追加できません。それは解決策への正しい道ではありません。

于 2013-03-13T07:11:03.050 に答える