简体   繁体   English

Swift 3 中的十进制到双精度转换

[英]Decimal to Double conversion in Swift 3

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.我正在将一个项目从Swift 2.2迁移到Swift 3 ,并且我试图在可能的情况下摆脱旧的 Cocoa 数据类型。

My problem is here: migrating NSDecimalNumber to Decimal .我的问题在这里:将NSDecimalNumber迁移到Decimal

I used to bridge NSDecimalNumber to Double both ways in Swift 2.2 :我曾经在Swift 2.2 中以两种方式将NSDecimalNumber桥接到Double

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

let doubleFromDecimal = decimalNumber.doubleValue

Now, switching to Swift 3 :现在,切换到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: decimal.doubleValue不存在,也不存在Double(decimal) ,甚至不是decimal as Double ......我想出的唯一黑客是:

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...但是试图摆脱NSDecimalNumber并且不得不偶尔使用它是完全愚蠢的......

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 .编辑:没有更多关于Swift 4的主题。

Edit : Nothing more on the subject on Swift 5 .编辑:没有更多关于Swift 5的主题。

NSDecimalNumber and Decimal are bridged NSDecimalNumberDecimal桥接

The Swift overlay to the Foundation framework provides the Decimal structure, which bridges to the NSDecimalNumber class. Swift 覆盖到 Foundation 框架提供了 Decimal 结构,它连接到 NSDecimalNumber 类。 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. Decimal 值类型提供与 NSDecimalNumber 引用类型相同的功能,并且两者可以在与 Objective-C API 交互的 Swift 代码中互换使用。 This behavior is similar to how Swift bridges standard string, numeric, and collection types to their corresponding Foundation classes.这种行为类似于 Swift 将标准字符串、数字和集合类型桥接到它们相应的 Foundation 类的方式。 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

Another solution that works in Swift 3 is to cast the Decimal to NSNumber and create the Double from that.另一个适用于 Swift 3 的解决方案是将DecimalNSNumber并从中创建Double

let someDouble = Double(someDecimal as NSNumber)

As of Swift 4.2 you need:从 Swift 4.2 开始,您需要:

let someDouble = Double(truncating: someDecimal as NSNumber)

Solution that works in Swift 4适用于Swift 4 的解决方案

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

斯威夫特 5

let doubleValue = Double(truncating: decimalValue as NSNumber)

Decimal in Swift 3 is not NSDecimalNumber . Swift 3 中的Decimal不是NSDecimalNumber It's NSDecimal , completely different type.它是NSDecimal ,完全不同的类型。

You should just keep using NSDecimalNumber as you did before.您应该像以前一样继续使用NSDecimalNumber

You are supposed to use as operator to cast a Swift type to its bridged underlying Objective-C type.您应该使用as运算符将 Swift 类型转换为其桥接的底层 Objective-C 类型。 So just use as like this.因此,只要使用as是这样的。

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

In Swift 4, Decimal is NSDecimalNumber .在 Swift 4 中, DecimalNSDecimalNumber Here's citation from Apple's official documentation in Xcode 10.这是 Xcode 10 中 Apple 官方文档的引用。

Important重要的

The Swift overlay to the Foundation framework provides the Decimal structure, which bridges to the NSDecimalNumber class. Swift 覆盖到 Foundation 框架提供了Decimal结构,它连接到NSDecimalNumber类。 For more information about value types, see Working with Cocoa Frameworks in Using Swift with Cocoa and Objective-C (Swift 4.1).有关值类型的更多信息,请参阅使用 Swift 与 Cocoa 和 Objective-C (Swift 4.1) 中的使用 Cocoa 框架。

There's no NSDecimal anymore.没有NSDecimal了。 There was confusing NSDecimal type in Swift 3, but it seems to be a bug. Swift 3 中有令人困惑的NSDecimal类型,但这似乎是一个错误。 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.我看到 OP 对 Swift 4 不感兴趣,但我添加了这个答案,因为只提到(过时的)Swift 3 让我感到困惑。

In Swift open source, the implementation is actually done in Decimal.swift , but it is private.在 Swift 开源中, 实现实际上是在Decimal.swift完成的,但它是私有的。 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)
    }
}

For swift 5, the function is对于 swift 5,函数是

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM