6

NSNumberFormatterを使用してObjCで非常に大きな数値をフォーマットするという予期しない動作が発生しています。

数値フォーマッタは、小数桁に関係なく、15桁目以降の小数(NSDecimalNumber)を丸めているようです。

以下のテストは、値1、3、および5で失敗します。

2つのリクエスト:

  • 代替コードに関する提案をいただければ幸いです。
  • NSNumberFormatterでハードコードされた数字制限を使用しているために問題が発生していると思いますか?

ここの投稿には、問題が発生した場合の十分な説明がない回避策がリストされています。また、アプリケーション(銀行セクター)は複数の国で実行されており、バックエンドで構成されているように、フォーマットをユーザーのロケールにリンクしています。この回避策は、要件を処理するために独自の数値フォーマッターを作成することを意味します。やりたくないこと。

- (void)testFormatterUsingOnlySDK {
    NSDecimalNumber *value1 = [NSDecimalNumber decimalNumberWithMantissa: 9423372036854775808u exponent:-3 isNegative:YES];
    NSDecimalNumber *value2 = [NSDecimalNumber decimalNumberWithMantissa: 9999999999999990u exponent:-3 isNegative:YES];
    NSDecimalNumber *value3 = [NSDecimalNumber decimalNumberWithMantissa: 9999999999999991u exponent:-3 isNegative:YES];
    NSDecimalNumber *value4 = [NSDecimalNumber decimalNumberWithMantissa: 99999999999999900u exponent:-4 isNegative:YES];
    NSDecimalNumber *value5 = [NSDecimalNumber decimalNumberWithMantissa: 11111111111111110u exponent:-4 isNegative:YES];

    NSNumberFormatter *formatter = [[[NSNumberFormatter alloc] init] autorelease];
    formatter.allowsFloats = YES;
    formatter.maximumFractionDigits = 3;

    [self assertStringAreEqualWithActual:[formatter stringFromNumber:value1] andExpeted: @"-9423372036854775.808"];
    [self assertStringAreEqualWithActual:[formatter stringFromNumber:value2] andExpeted: @"-9999999999999.99"];
    [self assertStringAreEqualWithActual:[formatter stringFromNumber:value3] andExpeted: @"-9999999999999.991"];
    [self assertStringAreEqualWithActual:[formatter stringFromNumber:value4] andExpeted: @"-9999999999999.99"];
    [self assertStringAreEqualWithActual:[formatter stringFromNumber:value5] andExpeted: @"-1111111111111.111"];
}

- (void)assertStringAreEqualWithActual:(NSString *)actual andExpeted:(NSString *)expected {
    STAssertTrue([expected isEqualToString:actual], @"Expected %@ but got %@", expected, actual);
}
4

3 に答える 3

4

残念ながら、NSNumberFormatterでは正しく機能しませんNSDecimalNumber。問題は(おそらく)それが最初に行うことはdoubleValue、フォーマットしたい番号を呼び出すことです。

NSDecimalNumberラウンドロング数も参照してください。

を何度も試した後NSNumberFormatter、私は独自のフォーマッターを作成しました。実際には非常に簡単です。

  1. ハンドルNaN
  2. ラウンド使用roundToScale:
  3. 得るstringValue
  4. 負の値かどうかを確認し、先頭を削除します-
  5. 小数点を探す(.
  6. 小数点のローカライズ([locale objectForKey:NSLocaleDecimalSeparator]
  7. グループ化区切り文字を追加します([locale objectForKey:NSLocaleGroupingSeparator]
  8. 負の場合、通貨をフォーマットする場合は、先頭を追加する-か、数字を括弧で囲みます。
  9. 終わり。
于 2012-12-19T13:36:18.250 に答える
1

このオープンソースコードから独自のNSNumberFormatterをコンパイルし、プレフィックスを変更する必要があります。これにより、フォーマットをデバッグし、これが発生している理由を理解できるようになります。最悪の場合、Appleにパッチを送信できます。

http://code.google.com/p/cocotron/source/browse/Foundation/NSNumberFormatter.m?r=7542c3a7ef0ef75479e6154a75d304113f5a9738

于 2012-12-19T13:29:36.193 に答える
1

2つに設定maximumFractionDigitsしました。失敗したテストはすべて、期待値に3桁の小数部が含まれています。期待値またはコードのいずれかを一致するように変更する必要があります。この変更を行う場合:

formatter.maximumFractionDigits = 3;

その後、すべてのテストケースが満たされます。

于 2012-12-19T13:29:39.017 に答える