Decimal to Double conversion in Swift 3

IosSwiftMigrationType ConversionSwift3

Ios Problem Overview


I'm migrating a project from Swift 2.2 to Swift 3, and I'm trying to get rid of old Cocoa data types when possible.

My problem is here: migrating NSDecimalNumber to Decimal.

I used to bridge NSDecimalNumber to Double both ways in Swift 2.2:

let double = 3.14
let decimalNumber = NSDecimalNumber(value: double)

let doubleFromDecimal = decimalNumber.doubleValue

Now, switching to Swift 3:

let double = 3.14
let decimal = Decimal(double)

let doubleFromDecimal = ???

decimal.doubleValue does not exist, nor Double(decimal), not even decimal as Double... The only hack I come up with is:

let doubleFromDecimal = (decimal as NSDecimalNumber).doubleValue

But that would be completely stupid to try to get rid of NSDecimalNumber, and have to use it once in a while...

Well, either I missed something obvious, and I beg your pardon for wasting your time, or there's a loophole needed to be addressed, in my opinion...

Thanks in advance for your help.

Edit : Nothing more on the subject on Swift 4.

Edit : Nothing more on the subject on Swift 5.

Ios Solutions


Solution 1 - Ios

NSDecimalNumber and Decimal are bridged > The Swift overlay to the Foundation framework provides the Decimal > structure, which bridges to the NSDecimalNumber class. The Decimal > value type offers the same functionality as the NSDecimalNumber > reference type, and the two can be used interchangeably in Swift code > that interacts with Objective-C APIs. This behavior is similar to how > Swift bridges standard string, numeric, and collection types to their > corresponding Foundation classes. Apple Docs

but as with some other bridged types certain elements are missing.

To regain the functionality you could write an extension:

extension Decimal {
    var doubleValue:Double {
        return NSDecimalNumber(decimal:self).doubleValue
    }
}

// implementation
let d = Decimal(floatLiteral: 10.65)
d.doubleValue

Solution 2 - Ios

Another solution that works in Swift 3 is to cast the Decimal to NSNumber and create the Double from that.

let someDouble = Double(someDecimal as NSNumber)

As of Swift 4.2 you need:

let someDouble = Double(truncating: someDecimal as NSNumber)

Solution 3 - Ios

Solution that works in Swift 4

let double = 3.14
let decimal = Decimal(double)
let doubleFromDecimal = NSDecimalNumber(decimal: decimal).doubleValue
print(doubleFromDecimal)

Solution 4 - Ios

Swift 5
let doubleValue = Double(truncating: decimalValue as NSNumber)

Solution 5 - Ios

Decimal in Swift 3 is not NSDecimalNumber. It's NSDecimal, completely different type.

You should just keep using NSDecimalNumber as you did before.

Solution 6 - Ios

You are supposed to use as operator to cast a Swift type to its bridged underlying Objective-C type. So just use as like this.

let p = Decimal(1)
let q = (p as NSDecimalNumber).doubleValue

In Swift 4, Decimal is NSDecimalNumber. Here's citation from Apple's official documentation in Xcode 10.

> Important > > The Swift overlay to the Foundation framework provides the Decimal > structure, which bridges to the NSDecimalNumber class. For more > information about value types, see Working with Cocoa Frameworks in > Using Swift with Cocoa and Objective-C (Swift 4.1).

There's no NSDecimal anymore. There was confusing NSDecimal type in Swift 3, but it seems to be a bug. No more confusion.

Note

I see the OP is not interested in Swift 4, but I added this answer because mentioning only about (outdated) Swift 3 made me confused.

Solution 7 - Ios

In Swift open source, the implementation is actually done in Decimal.swift, but it is private. You can re-use the code from there.

extension Double {
    @inlinable init(_ other: Decimal) {
        if other._length == 0 {
            self.init(other._isNegative == 1 ? Double.nan : 0)
            return
        }

        var d: Double = 0.0
        for idx in (0..<min(other._length, 8)).reversed() {
            var m: Double
            switch idx {
            case 0: m = Double(other._mantissa.0)
                break
            case 1: m = Double(other._mantissa.1)
                break
            case 2: m = Double(other._mantissa.2)
                break
            case 3: m = Double(other._mantissa.3)
                break
            case 4: m = Double(other._mantissa.4)
                break
            case 5: m = Double(other._mantissa.5)
                break
            case 6: m = Double(other._mantissa.6)
                break
            case 7: m = Double(other._mantissa.7)
                break
            default: break
            }
            d = d * 65536 + m
        }

        if other._exponent < 0 {
            for _ in other._exponent..<0 {
                d /= 10.0
            }
        } else {
            for _ in 0..<other._exponent {
                d *= 10.0
            }
        }
        self.init(other._isNegative != 0 ? -d : d)
    }
}

Solution 8 - Ios

For swift 5, the function is

let doubleValue = Double(truncating: decimalValue as NSNumber)

the example in the below, show the number of float.

let decimalValue: Decimal = 3.14159
let doubleValue = Double(truncating: decimalValue as NSNumber)
print(String(format: "%.3f", doubleValue))  // 3.142
print(String(format: "%.4f", doubleValue)) // 3.1416
print(String(format: "%.5f", doubleValue)) // 3.14159
print(String(format: "%.6f", doubleValue)) // 3.141590
print(String(format: "%.7f", doubleValue)) // 3.1415900

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZaphodView Question on Stackoverflow
Solution 1 - IossketchyTechView Answer on Stackoverflow
Solution 2 - IosrmaddyView Answer on Stackoverflow
Solution 3 - IosPranavan SPView Answer on Stackoverflow
Solution 4 - IosRafa de KingView Answer on Stackoverflow
Solution 5 - Iosuser28434'mstepView Answer on Stackoverflow
Solution 6 - IoseonilView Answer on Stackoverflow
Solution 7 - IosEugene DudnykView Answer on Stackoverflow
Solution 8 - IosZgpeaceView Answer on Stackoverflow