3

値が 4937446359977427944 のキーを含む NSDictionary があります。その値を long long として取得しようとすると、4937446359977427968 が返されますか?

NSLog(@"value1 = %@", [dict objectForKey"MyKey"]); // prints 4937446359977427944 

long long lv = [dict objectForKey:@"MyKey"] longLongValue];

NSLog(@"value2 = %lld", lv); // prints 4937446359977427968

やっている:

NSLog(@"%lld", [@"4937446359977427944" longLongValue]); // prints 4937446359977427944

下位ビットがクリアされているように見えるため、何らかの丸め問題であると想定していますが、それを停止する方法 (またはなぜ発生するのか) がわかりません。

辞書は を使用して作成されており、JSON オブジェクトには (正しく)エントリNSJSONSerializationが含まれており、オブジェクトは正しいです。"MyKey": 4937446359977427944dict

に保持されている値NSDictionaryは、NSDecimalNumber

舞台裏で何かがフロートに変換されていますか?

4

3 に答える 3

2

NSDecimalValueは として格納されずdouble、64 ビットの符号なし整数の仮数、基数 10 の 8 ビットの符号付き整数指数、および符号ビットです。

問題は、 an の正確な値がNSDecimalValue... an としてしか表現できないことですNSDecimalValue

method を使用して、おおよその 64 ビット IEE754 値を取得できますdoubleValue

使用しようとするとlongLongValue、おおよその IEE754 値を long long int にキャストした結果が効果的に得られます。

の実装のバグと考えるかもしれませんし、考えないかもしれませんNSDecimalValue(最終的にはレーダーを提出し、Apple に別の変換ルーチンを使用するように依頼してください)。しかし厳密に言えば、これはバグではなく、設計上の決定です。

NSDecimalValue一種の浮動小数点10 進数と考える必要があります。実際、IEEE754 が拡張精度浮動小数点 10 進数と呼ぶもののソフトウェア実装に非常に似ていますが、その定義に準拠していない点が異なります (少なくとも −6143 と +6144 の間の値をサポートする指数を持たず、 NAN と無限をサポートしていないためです)。

つまり、これは整数の拡張実装ではなく、double の拡張 (ただし、NAN と無限はありません) 実装です。Apple がネイティブに へのおおよその変換しか提供しないという事実double(53 ビットの精度を超える値に対して long long int への変換が正確である場合と正確ではない場合があることを意味します) はバグではありません。

(カテゴリを使用して) 別の変換を自分で実装したい場合としない場合があります。

別の考えられる視点は、問題が使用した JSON 実装のバグであると考えることです。しかし、これも非常に議論NSDecimalValueの余地があります。を操作するNSDecimalValueか、変換する責任があります

于 2012-09-14T09:14:10.327 に答える
1

あなたが単純な解決策に興味があるのか​​ 、それとも精度の低下が起こる理由の詳細を調べているだけなのかはわかりません。

簡単な答えに興味がある場合:-[NSDecimalNumber description]値を含む文字列を生成し、文字-[NSString longLongValue]列をlong long

NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:@"4937446359977427944"];
long long longLongNumber = [[decimalNumber description] longLongValue];
NSLog(@"decimalNumber %@ -- longLongNumber %lld", decimalNumber, longLongNumber);

出力

2014-04-16 08:51:21.221 APP_NAME[30458:60b] decimalNumber 4937446359977427944 -- longLongNumber 4937446359977427944

ファイナルノート

[decimalNumber descriptionWithLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]]アプリが複数のロケールをサポートしている場合、より信頼性が高くなる可能性があります。

于 2014-04-16T12:56:39.633 に答える
0

Analog Fileの適切な回答に従って、問題の迅速な解決策に興味がある人は:

long long someNumber = 8204064638523577098;
NSLog(@"some number lld:               %lld", someNumber);
NSNumber *snNSNumber = [NSNumber numberWithLongLong:someNumber];
NSLog(@"some number NSNumber:          %@", snNSNumber);
NSString *someJson = @"{\"someValue\":8204064638523577098}";
NSDictionary* dict = [NSJSONSerialization
 JSONObjectWithData:[someJson dataUsingEncoding:NSUTF8StringEncoding]
 options:0
 error:nil];
NSLog(@"Dict: %@", dict);
NSLog(@"Some digit out of dict:        %@", [dict objectForKey:@"someValue"]);
NSLog(@"Some digit out of dict as lld: %lld", [[dict objectForKey:@"someValue"] longLongValue]);
long long someNumberParsed;
sscanf([[[dict objectForKey:@"someValue"] stringValue] UTF8String], "%lld", &someNumberParsed);
NSLog(@"Properly parsed lld:           %lld", someNumberParsed);

結果:

2014-04-16 14:22:02.997 Tutorial4[97950:303] いくつかの数 lld:
8204064638523577098

2014-04-16 14:22:02.998 Tutorial4[97950:303] いくつかの番号 NSNumber:
8204064638523577098

2014-04-16 14:22:02.998 Tutorial4[97950:303] Dict: { someValue = 8204064638523577098; }

2014-04-16 14:22:02.998 Tutorial4[97950:303] dict の一部の数字:
8204064638523577098

2014-04-16 14:22:02.999 Tutorial4[97950:303] lld としての dict の一部の数字: 8204064638523577344

2014-04-16 14:22:02.999 Tutorial4[97950:303] 適切に解析された lld:
8204064638523577098

于 2014-04-16T12:34:03.530 に答える