Swift 3
Decimal
NSDecimal
NSDecimalNumber
Programming

Swift 3 Decimal, NSDecimal and NSDecimalNumber

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When you need exact base-10 arithmetic in Swift, the three related names you see are Decimal, NSDecimal, and NSDecimalNumber. They are connected, but they do not play the same role: Decimal is the normal Swift-friendly value type, NSDecimal is the lower-level Foundation representation, and NSDecimalNumber is the Objective-C class wrapper for decimal values.

Use Decimal for Normal Swift Arithmetic

In most Swift code, Decimal is the right default. It behaves like a value type and fits naturally into ordinary application logic.

swift
1import Foundation
2
3let price: Decimal = 19.99
4let tax: Decimal = 1.50
5let total = price + tax
6
7print(total)

This is especially useful for currency, quantities, and other domains where binary floating-point artifacts are unacceptable.

swift
1let doubleResult = 0.1 + 0.2
2print(doubleResult)
3
4let a: Decimal = 0.1
5let b: Decimal = 0.2
6print(a + b)

The Double example can expose binary floating-point approximation, while Decimal is designed for exact decimal-style arithmetic.

What NSDecimal Actually Is

NSDecimal is the lower-level C-style struct Foundation uses for decimal operations. Most Swift developers do not need to work with it directly, but it becomes relevant when you use low-level Foundation decimal functions.

swift
1import Foundation
2
3var left = Decimal(string: "12.34")!
4var right = Decimal(string: "0.66")!
5var result = Decimal()
6
7NSDecimalAdd(&result, &left, &right, .plain)
8print(result)

This works, but it is more verbose than ordinary Decimal operators. That is why NSDecimal is usually an implementation detail or an escape hatch, not the first choice for everyday code.

When NSDecimalNumber Is Useful

NSDecimalNumber is an immutable Foundation class. It is still useful when:

  • an API expects an Objective-C object
  • you need Foundation rounding behavior objects
  • you are interoperating with NSNumber-oriented APIs
swift
1import Foundation
2
3let value = NSDecimalNumber(string: "19.995")
4let behavior = NSDecimalNumberHandler(
5    roundingMode: .plain,
6    scale: 2,
7    raiseOnExactness: false,
8    raiseOnOverflow: true,
9    raiseOnUnderflow: true,
10    raiseOnDivideByZero: true
11)
12
13let rounded = value.rounding(accordingToBehavior: behavior)
14print(rounded)

This is one of the clearest places where NSDecimalNumber remains convenient. It gives you object-based behavior and Foundation rounding helpers in one package.

Bridging Between Decimal and NSDecimalNumber

In real Swift code, a common pattern is:

  • use Decimal for your business logic
  • bridge to NSDecimalNumber only when an API or Foundation helper requires it
swift
1import Foundation
2
3let swiftValue = Decimal(string: "42.50")!
4let objectValue = swiftValue as NSDecimalNumber
5
6print(objectValue)

That keeps most of the code Swift-native while still letting you interact with older Foundation and Objective-C interfaces when necessary.

The reverse also happens:

swift
let number = NSDecimalNumber(string: "12.75")
let decimal = number.decimalValue
print(decimal)

This makes it easy to cross the boundary deliberately instead of mixing the types without a plan.

Rounding Is a Separate Design Decision

Choosing a decimal type is not the same as choosing a rounding policy. Even with exact decimal arithmetic, real business logic still needs explicit rules for:

  • how many fractional digits to keep
  • when rounding occurs
  • which rounding mode is allowed

With Decimal, a common low-level Foundation approach is NSDecimalRound:

swift
1import Foundation
2
3var original = Decimal(string: "19.995")!
4var rounded = Decimal()
5
6NSDecimalRound(&rounded, &original, 2, .bankers)
7print(rounded)

This matters because exact decimal storage does not magically define domain rules for tax, currency display, or ledger calculations.

A Practical Rule of Thumb

For most application code, the decision rule is simple:

  • use Decimal for ordinary Swift arithmetic
  • use NSDecimalNumber when you need an object or Foundation rounding helpers
  • use direct NSDecimal functions only when low-level Foundation APIs require them

That covers most situations cleanly and keeps the code readable.

If you are building a money-related domain model, this rule is especially useful because it keeps the main logic in Swift-native value semantics and limits Objective-C bridging to clear integration points.

Avoid Double in Decimal-Sensitive Domains

The most important mistake to avoid is not choosing between the three decimal types incorrectly. The bigger mistake is using Double at all when the problem domain expects decimal correctness.

For prices, invoices, tax amounts, or balances, a safer default is:

  • store with Decimal
  • round deliberately
  • bridge to NSDecimalNumber only when required

That is far more predictable than letting binary floating-point become part of the business model and then patching over formatting surprises later.

Common Pitfalls

One common mistake is using Double for money and expecting exact decimal behavior.

Another pitfall is reaching for NSDecimal directly when Decimal would make the code simpler and clearer.

A third issue is mixing Decimal and NSDecimalNumber casually without being clear about why object-based bridging is needed.

Finally, even exact decimal types do not remove the need for an explicit rounding policy. That decision still belongs to your business rules.

Summary

  • 'Decimal is usually the best Swift-native choice for exact decimal arithmetic.'
  • 'NSDecimal is the lower-level Foundation representation used by low-level decimal functions.'
  • 'NSDecimalNumber is the Foundation class wrapper and is useful for object-based APIs and rounding helpers.'
  • Prefer Decimal for normal Swift logic and bridge only when needed.
  • Decimal arithmetic still requires deliberate rounding rules in real business code.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.