nsdecimal, nsdecimalnumber, cfnumber 사이의 올바른 선택은 무엇입니까?
-
19-09-2019 - |
문제
나는 nsdecimal, nsnumber, nsnumberdecimal, cfnumber에 대해 많은 것을 읽었습니다 ... 그리고 그것은 나에게 일종의 정글이되기 시작합니다.
기본적으로 나는 이와 같은 간단한 계산을 처리 할 간단한 모델 클래스를 만들려고 노력하고 있습니다.
#import <Foundation/Foundation.h>
@interface Test : NSObject
{
float rate;
float amount;
int duration;
}
- (float)capitalizedAmount;
@end
@implementation Test
- (float)capitalizedAmount {
return (amount*pow((1.0+rate),duration));
}
@end
나는이 방법과 세트를 문자열로 사용 하여이 방법과 세터에 액세스하고 싶습니다. 왜냐하면이 클래스와 같은 다른 클래스를 많이 가질 계획이므로 주요 가치 코딩을 수행 할 필드 목록 만 보관하고 있습니다.
// This is just the desired behavior
// This evidently won't work with the previous class definition
Test *obj = [[Test alloc] init];
[NSNumber numberWithInt:10]
...
float r;
r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
나는 이것이 불가능하다는 것을 이해합니다 performSelector:
물체를 반환 할 것입니다 capitalizedAmount
물체를 반환해야합니다. 나는 내용을 읽었습니다 NSInvocation
그리고 comp.lang의 대상 C FAQ의 관련 부분.
나는 또한 내가 사용해야한다는 것을 이해합니다 NSDecimalNumber
, 그러나 알고 싶은 두 가지가 있습니다.
- 메모리 오버 헤드와 성능 손실은 다소 복잡한 클래스 (이런 종류의 재무 계산 만, uitable view에서 보여 지)에 허용됩니까? 나는 C에 대한 배경이별로 없다.
- 기능을 사용하기에는 너무 까다 롭고 복잡하지 않습니까?
decimalNumberByAdding:
? 파이썬을 사용하면 정의하기가 쉽습니다__add__
객체와 함께 연산자를 사용합니다. 플로트 값을 얻을 수 있어야합니다NSDecimalNumber
, 그런 다음 계산을 수행하고 결과를NSDecimalNumber
? 이 문제를 어떻게 처리 하시겠습니까?
나는 단순하고 아름다운 솔루션을 찾고 있습니다!
같은 영역에있는 또 다른 질문은 다음과 같습니다 CFBoolean
객체 래퍼 BOOL
iPhone Core Foundation에서?
당신의 도움을 주셔서 대단히 감사합니다!
해결책
재무 계산을 다루는 경우 표준 Base-2 플로팅 포인트 유형에서 발생할 수있는 반올림 오류를 피하기 위해 Base-10 산술을 사용해야합니다. 따라서 NSDECIMAL 또는 NSDECIMALNUMBER입니다. 객체 지향 코드를 작성하기 때문에 NSDECIMALNUMBER가 귀하에게 적합한 선택입니다.
질문에 답하기 위해 : 코드의 테스트 만 메모리 오버 헤드와 성능 손실이 허용되는지 여부를 밝힐 수 있습니다. 나는 NSDECIMALNUMBER와 실제로 많은 일을하지 않았지만 Apple의 구현이 매우 효율적이며 대부분의 사람들의 요구에 적합 할 것이라고 베팅 할 것입니다.
불행히도, 당신은 decimalNumberByAdding:
Objective-C는 C ++처럼 연산자 과부하를 지원하지 않기 때문입니다. 나는 그것이 당신의 코드를 다소 우아하게 만든다는 데 동의합니다.
게시 한 코드에 대한 댓글 하나 : r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
다소 불가사의합니다. 어느 하나
r = [obj performSelector:@selector(capitalizedAmount)];
또는 심지어 단순한
r = [obj capitalizedAmount];
필요하지 않으면 더 좋을 것입니다 NSSelectorFromString
다른 이유에 대한 구문.
다른 팁
OLE은 맞습니다. 재무 계산을 수행 할 때 부동 소수점 수학 오류를 피하기 위해 NSDECIMAL 또는 NSDECIMALNUMBER를 사용해야합니다. 그러나 내 제안은 nsdecimalnumber가 아닌 nsdecimal과 그 C 함수를 사용하는 것입니다. nsdecimal 계산이 훨씬 빠를 수 있으며, 많은 자동 퇴행 객체를 생성하지 않기 때문에 메모리 사용에있어 훨씬 좋습니다.
예를 들어, 나는 MacBook Air의 두 유형에 대한 수학 작업을 벤치마킹했습니다.
NSDecimal
Additions per second: 3355476.75
Subtractions per second: 3866671.27
Multiplications per second: 3458770.51
Divisions per second: 276242.32
NSDecimalNumber
Additions per second: 676901.32
Subtractions per second: 671474.6
Multiplications per second: 720310.63
Divisions per second: 190249.33
NSDECIMAL 대 NSDECIMALNUMBER를 사용할 때 성능이 약 5 배 증가하지 않은 유일한 작업이었습니다. iPhone에서도 비슷한 성능 향상이 발생합니다. 이것은 메모리 절약과 함께 최근 코어 플롯을 NSDECIMAL 사용으로 전환 한 이유였습니다.
당신이 달라질 수있는 유일한 어려움은 nsdecimal 유형으로 안팎으로 값을 얻는 것입니다. 플로트 및 정수 값으로 직접오고 나가면 NSDECIMALNUMBER를 브리지로 사용해야 할 수도 있습니다. 또한 핵심 데이터를 사용하는 경우 NSDECIMALS가 아닌 NSDECIMALNUMBERS로 값을 저장하게됩니다.
나는이 방법과 세트를 문자열로 사용 하여이 방법과 세터에 액세스하고 싶습니다. 왜냐하면이 클래스와 같은 다른 클래스를 많이 가질 계획이므로 주요 가치 코딩을 수행 할 필드 목록 만 보관하고 있습니다.
r = [obj performSelector:NSSelectorFromString(@"capitalizedAmount")];
KVC는 단순히 문자열을 사용하여 객체에 메시지를 보내는 것이 아닙니다. 보다 키 값 코딩 프로그래밍 안내서.
nsdecimalNumber에서 float 값을 얻은 다음 계산을 수행하고 nsdecimalNumber로 래핑 한 결과를 반환해야합니까?
아니요. 바이너리 플로팅 지점으로의 전환 (float
/double
) 소수점 부동 소수점에서 (NSDecimal
/nsdecimalNumber)는 손실입니다. 그런 식으로 수행하면 일부 계산에 대한 결과가 잘못됩니다.