안녕하세요 이웃님들~ ㅎㅎ
오늘은 제가 만든 라이브러리도 소개할 겸, 숫자를 나타내기 위해 우리가 자주 쓰는 Decimal, Double 타입의 소수점 부분을 어떻게 핸들링 하면 좋을지 한번 알아보도록 하겠습니다~!!
소수점을 다루어야 하는데 Double을 쓰고 계신가요? 흠... 소수점이 별로 안 중요한 서비스라면 괜찮을것 같습니다!? 그런데.. 정확도가 필요하다면 Double, Float 둘다 쓰지 마세요! Decimal을 사용하시는 것을 추천드립니다. 이진수를 십진수로 변환하는 방식으로 숫자를 표기하다보니까 소수점이 정확하게 될수가 없어요( 제 다른 글에 Money 객체 만들기 글이 있고, 여기에서 자세한 내용을 보실 수 있습니다) 오늘 중요한건 어쨋든 소수점을 올림 내림 반올림을 잘 해보자 이니까 그 부분에 집중해보도록 하죠~!
Double 형의 경우에는 floor() ceil() round() 를 모두 제공하고있어요. 대신 이게 소수점이 아니라 정수부에만 적용이 되기 때문에.. 소수점자리수를 기준으로 하려면 소수점을 모두 정수부로 만들어주고, round처리를 한 다음에 다시 소수부를 만들어줘야해요!
예를들어서
20.0037이라는 숫자가 있고 소수점 3자리까지 나타내고 나머지는 반올림 한다고 가정해볼게요~!
소수점 3자리 수까지 나타내고 싶으면 pow()를 통해 10^3 을 만들어 줍니다.
그리고 20.0037에 10^3을 곱해주세요. 20003.7이 될것입니다.
20003.7을 round() 해주게 되면 20004가 될 것입니다. 다시 10^3으로 나누어줍니다. 20.004가 됩니다.
func roundExample(value: Double, decimalPlaces: Int) -> Double {
let multiplier = pow(10.0, Double(decimalPlaces))
return round(value * multiplier) / multiplier
}
하지만 이 방법에 장점만 있는것은 아니에요. 물론 그런 경우가 많지는 않겠지만, 지수가 너무 크면 오버플로우가 생길수도 있으니까요.
저는 NSDecimalRound를 사용해서 Decimal 타입의 소수점을 올림, 내림, 반올림 등 처리를 해 주었습니다.
그런데 왜 절대값을 구하는지, sign같은걸 만들어서 곱해주고 있는지 궁금하실거예요.
NSDecimalNumber는 Float형 처럼 다양한 roundMode를 제공하고 있지 않아요. (
FloatingPointRoundingRule로 검색해보시면 케이스를 모두 보실 수 있어요)
그러다 보니 Android와 반올림에서 조금 다른 동작이 있었어요..
음수일때 올림, 내림, 반올림 하는 기준이 양수와 조금 다르게 동작하는 이슈가 있었거든요.
그래서 절대값을 구하여 음수였을 경우 round가 끝난 뒤에 사인을 곱해서 리턴하도록 하였어요.
// 소수점을 포함한 숫자, 반올림해서 남겨야하는 자릿수, 올림내림반올림 모드
func roundNumber(_ number: Decimal, decimalPlaces: Int, roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
var decimal = abs(number)
var rounded = Decimal()
NSDecimalRound(&rounded, &decimal, decimalPlaces, roundingMode)
let sign: Decimal = number >= 0 ? 1 : -1
return (rounded * sign)
}
기존의 NumberFormatter를 활용해서 minimumFractionDigits으로 최소 소수점 자리를 정해주면 소수점 길이가 더 짧더라도 0으로 채워주게 됩니다. 더 긴경우에 잘리게 하려면 maximumFractionDigits도 설정해주시면 됩니다.
// 3번째 자리까지 자르고, 모자라면 0을 채우고 싶다
let doubleValue: Double = 2.0406
let formatter = NumberFormatter()
formatter.numberStyle = comma ? .decimal : .none
formatter.maximumFractionDigits = 3
if fillZero {
formatter.minimumFractionDigits = 3
}
let string = formatter.string(from: doubleValue as NSNumber)
이래 저래 소수점 관리가 피곤하다고 생각하신다면 간단하게 제가 만든 라이브러리를 import해서 사용해보셔도 됩니다. round 모드도 더 간략해지고, 인자로 입력만 해주면 원하는 모양의 String을 return 받을 수 있어요!
소수점 특정 자리까지 0으로 채우거나, 천단위 구분자를 1,000,000 처럼 넣는것도 한번에 가능해요.
감사합니다 :)
https://github.com/AnnaBaeTofuMom/KWNumberFormatter
[TCA] TCA UI Case Study - TabView (2) | 2024.08.12 |
---|---|
[iOS] CoreTelephony 를 활용하여 Cellular data 사용 가능 여부 알기 (0) | 2023.10.26 |
[Swift Concurrency] Async/Await 진짜 쉽게 이해하기 (3) - 흔히 하는 실수 (1) | 2023.06.13 |
[Swift Concurrency] Async/Await 진짜 쉽게 이해하기 (2) - 작성법 배우기 (0) | 2023.06.13 |
[Swift Concurrency] Async/Await 진짜 쉽게 이해하기 (1) - Do,Try,Catch 알기 (5) | 2023.06.12 |