돈을 다루기 위해 nsdecimalNumber를 사용해야합니까?
-
05-07-2019 - |
문제
첫 번째 앱을 코딩하기 시작하면서 NSNUMBER를 두 번 생각하지 않고 돈 가치에 NSNUMBER를 사용했습니다. 그런 다음 C 유형이 내 가치를 다루기에 충분하다고 생각했습니다. 그러나 나는 iPhone SDK 포럼에서 우수한 반올림 기능 때문에 nsdecimalnumber를 사용하도록 권고 받았다.
기질에 의해 수학자가 아닌, 나는 만티 사/지수 패러다임이 과잉 일 수 있다고 생각했다. 그럼에도 불구하고, Googlin '주변에서 나는 코코아의 돈/통화에 대한 대부분의 이야기가 nsdecimalnumber로 언급되었다는 것을 깨달았습니다.
내가 작업중 인 앱은 국제화 될 것이므로, 금액을 계산하는 옵션은 실제로 실행 가능하지 않습니다. 금전적 구조는 사용 된 로케일에 크게 의존하기 때문입니다.
나는 NSDECIMALNUMBER와 함께 가야한다고 90% 확신하지만 웹에서 명백한 대답을 찾지 못했기 때문에 ( "돈을 다루면 NSDECIMALNUMBER를 사용하십시오!") 나는 여기서 물어볼 것이라고 생각했습니다. 어쩌면 대답은 대부분 분명하지만 앱의 대규모 리팩토링을 시작하기 전에 확신하고 싶습니다.
나를 설득하십시오 :)
해결책
Marcus Zarra는 이것에 대해 매우 분명한 입장을 가지고 있습니다. "통화를 전혀 다루고 있다면 nsdecimalNumber를 사용해야합니다." 그의 기사는 나에게 nsdecimalnumber를 조사하도록 영감을 주었고, 나는 그것에 깊은 인상을 받았습니다. Base -10 수학을 다룰 때 IEEE 부동 소수점 오류는 한동안 나를 자극했습니다 (1 * (0.5-0.4-0.1) = -0.0000000000000000002776) 및 NSDECIMALNUMBER는 그들과 멀리합니다.
nsdecimalNumber는 이진 부동물 포인트 정밀도의 또 다른 몇 자리를 추가 할뿐 아니라 실제로베이스 -10 수학을합니다. 위의 예에 표시된 오류와 같은 오류가 제거됩니다.
이제 저는 상징적 수학 응용 프로그램을 작성하고 있습니다. 따라서 30+ 십진수 정밀도에 대한 욕구와 이상한 부동 소수점 오류는 예외 일 수 있지만 볼 가치가 있다고 생각합니다. 운영은 단순한 var = 1 + 2 스타일 수학보다 약간 어색하지만 여전히 관리 가능합니다. 수학 작업 중에 모든 종류의 인스턴스를 할당하는 것이 걱정된다면, nsdecimal은 nsdecimalnumber와 동일한 C 구조물이며 정확히 동일한 수학 작업을 수행하기위한 C 함수가 있습니다. 내 경험상, 이것들은 가장 까다로운 응용 프로그램 (3,344,593 개의 추가/S, MacBook Air의 254,017 부서, 281,555 개의 추가/S, iPhone에서 12,027 개의 부서/s)에게 충분히 빠릅니다.
추가 보너스로 NSDECIMALNUMBER의 DescriptionWithLocale : Method는 올바른 소수점 분리기를 포함하여 국소화 된 버전의 문자열을 제공합니다. InitwithString : Locale : Method.
다른 팁
예. 당신은 사용해야합니다
NSDECIMALNUMBER 그리고
~ 아니다 더블 또는 뜨다 iOS에서 통화를 처리 할 때.
왜 그런 겁니까??
우리는 같은 것을 얻고 싶지 않기 때문입니다 $9.9999999998 대신에 $10
어떻게 되는가 ??
수레와 복식은 근사치입니다. 그들은 항상 반올림 오류가 있습니다. 형식 컴퓨터는 소수점을 저장하는 데 사용하면이 루딩 오류가 발생합니다. 자세한 내용이 필요한 경우 읽으십시오
Apple Docs에 따르면
NSDECIMALNUMBER는 NSNUMBER의 불변의 서브 클래스이며 Base-10 산술을 수행하기위한 객체 지향 래퍼를 제공합니다. 인스턴스는 Mantissa x 10^지수로 표현 될 수있는 모든 숫자를 나타낼 수 있으며 Mantissa는 최대 38 자리 길이의 소수 정수이며 지수는 –128에서 127의 정수입니다.
따라서 NSDECIMALNUMBER는 통화를 다루기 위해 권장됩니다.
(다른 답변에 대한 나의 의견에서 적응했다.)
예, 당신은해야합니다. 필연적 인 동전 수는 반 센트를 나타내지 않아도됩니다. 이 경우 반 센트를 계산하도록 변경할 수 있지만, 1/4 센트 또는 8 센트를 대표해야한다면 어떻게해야합니까?
유일한 적절한 솔루션은 NSDECIMALNUMBER (또는 그와 비슷한 것)로, 문제를 10^-128 ¢ (즉,, 즉,
0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000001¢).
(또 다른 방법은 임의의 예비 산술이지만, 이는와 같은 별도의 라이브러리가 필요합니다. GNU MP Bignum 라이브러리. GMP는 LGPL 아래에 있습니다. 나는 그 라이브러리를 사용한 적이없고 그것이 어떻게 작동하는지 정확히 알지 못해서 그것이 당신에게 얼마나 잘 작동하는지 말할 수 없었습니다.)
편집 : 분명히, 적어도 한 사람인 브래드 라슨 (Brad Larson)은이 답변의 어딘가에 이진 부유 식 점에 대해 이야기하고 있습니다. 난 아니에요.
더 나은 질문은 언제라도해야한다는 것입니다 ~ 아니다 돈을 다루기 위해 nsdecimalnumber를 사용하십시오. 그 질문에 대한 짧은 대답은 NSDECIMALNUMBER의 성능 오버 헤드를 견딜 수없고 정밀도의 몇 자리 이상을 다루지 않기 때문에 작은 반올림 오류에 신경 쓰지 않는다는 것입니다. 더 짧은 대답은 당신이해야합니다 언제나 돈을 다룰 때 nsdecimalnumber를 사용하십시오.
정수를 사용하여 센트 수를 나타내고 프레젠테이션을 위해 100으로 나누는 것이 편리하다는 것을 알았습니다. 전체 문제를 피하십시오.
비자, 마스터 카드 및 기타는 금액을 통과하는 동안 정수 값을 사용하고 있습니다. 통화 지수에 따라 올바르게 Amouts를 구문 분석하는 것은 발신자 및 리시버에게 달려 있습니다 (NUM-는 화폐의 지수 인 10^num을 나누거나 곱합니다). 통화가 다르면 지수가 다릅니다. 일반적으로 2 (따라서 우리는 100을 나누고 곱하기)이지만 일부 통화에는 지수 = 0 (VND 등), 또는 = 3이 있습니다.