在 Swift 中获取双精度数的小数部分

Getting the decimal part of a double in Swift

我试图在 swift 中分隔双精度数的小数部分和整数部分。我尝试了多种方法,但它们都 运行 进入了同一个问题...

let x:Double = 1234.5678
let n1:Double = x % 1.0           // n1 = 0.567800000000034
let n2:Double = x - 1234.0        // same result
let n3:Double = modf(x, &integer) // same result

有没有办法在不将数字转换为字符串的情况下获得 0.5678 而不是 0.567800000000034?

使用 Float 因为它的精度数字低于 Double

let x:Double = 1234.5678
let n1:Float = Float(x % 1)           // n1 = 0.5678

无需将其转换为字符串,您可以像这样四舍五入到小数位:

let x:Double = 1234.5678
let numberOfPlaces:Double = 4.0
let powerOfTen:Double = pow(10.0, numberOfPlaces)
let targetedDecimalPlaces:Double = round((x % 1.0) * powerOfTen) / powerOfTen

你的输出将是

0.5678

Swift 2:

您可以使用:

modf(x).1

x % floor(abs(x))

您可以使用 truncatingRemainder1 作为分隔符。

Returns the remainder of this value divided by the given value using truncating division.

Apple doc

示例:

let myDouble1: Double = 12.25
let myDouble2: Double = 12.5
let myDouble3: Double = 12.75

let remainder1 = myDouble1.truncatingRemainder(dividingBy: 1)
let remainder2 = myDouble2.truncatingRemainder(dividingBy: 1)
let remainder3 = myDouble3.truncatingRemainder(dividingBy: 1)

remainder1 -> 0.25
remainder2 -> 0.5
remainder3 -> 0.75

作为 FloatingPoint 协议实例 属性 实现的与 Alessandro Ornano 相同的方法:

Xcode 11 • Swift 5.1

import Foundation

extension FloatingPoint {
    var whole: Self { modf(self).0 }
    var fraction: Self { modf(self).1 }
}

1.2.whole    // 1
1.2.fraction // 0.2

如果您需要小数位数并保留其精度数字,则需要使用 Swift Decimal 类型并使用 String:

对其进行初始化
extension Decimal {
    func rounded(_ roundingMode: NSDecimalNumber.RoundingMode = .plain) -> Decimal {
        var result = Decimal()
        var number = self
        NSDecimalRound(&result, &number, 0, roundingMode)
        return result
    }
    var whole: Decimal { rounded(sign == .minus ? .up : .down) }
    var fraction: Decimal { self - whole }
}

let decimal = Decimal(string: "1234.99999999")!  // 1234.99999999
let fractional = decimal.fraction                // 0.99999999
let whole = decimal.whole                        // 1234
let sum = whole + fractional                     // 1234.99999999

let negativeDecimal = Decimal(string: "-1234.99999999")!  // -1234.99999999
let negativefractional = negativeDecimal.fraction         // -0.99999999
let negativeWhole = negativeDecimal.whole                 // -1234
let negativeSum = negativeWhole + negativefractional      // -1234.99999999

你可以这样得到整数部分:

let d: Double = 1.23456e12

let intparttruncated = trunc(d)
let intpartroundlower = Int(d)

trunc() 函数截断小数点后的部分,Int() 函数舍入到下一个较低的值。这对于正数是相同的,但对于负数是不同的。如果你从d中减去截断部分,那么你将得到小数部分。

func frac (_ v: Double) -> Double
{
    return (v - trunc(v))
}

您可以像这样获取 Double 值的尾数和指数:

let d: Double = 1.23456e78

let exponent = trunc(log(d) / log(10.0))

let mantissa = d / pow(10, trunc(log(d) / log(10.0)))

您的指数结果为 78,尾数结果为 1.23456。

希望对您有所帮助。

C 的数学库中有一个函数,包括 Swift 在内的许多编程语言都可以让您访问它。它被称为modf,在Swift中,它是这样工作的

// modf returns 一个 2 元素元组,

//第一个元素为整数部分,

//和第二个元素中的小数部分

让 splitPi = modf(3.141592)

splitPi.0 // 3.0

splitPi.1 // 0.141592

您可以像下面这样创建一个扩展,

extension Double {

    func getWholeNumber() -> Double {

        return modf(self).0

    }

    func getFractionNumber() -> Double {

        return modf(self).1

    }

}

Swift 5.1

let x:Double = 1234.5678

let decimalPart:Double = x.truncatingRemainder(dividingBy: 1)    //0.5678
let integerPart:Double = x.rounded(.towardZero)                   //1234

这两种方法return双精度值。

如果你想要一个整数作为整数部分,你可以只使用

Int(x)

不可能创建适用于所有人的解决方案 Doubles。如果其他答案曾经奏效(我也认为这是不可能的),那么它们就不再奏效了。

let _5678 = 1234.5678.description.drop { [=10=] != "." } .description // ".5678"
Double(_5678)  // 0.5678

let _567 = 1234.567.description.drop { [=10=] != "." } .description // ".567"
Double(_567) // 0.5669999999999999
extension Double {

    /// Gets the decimal value from a double.
    var decimal: Double {
        Double("0." + string.split(separator: ".").last.string) ?? 0.0
    }
    
    var string: String {
        String(self)
    }
}

这似乎解决了双精度问题。

用法:

print(34.46979988898988.decimal) // outputs 0.46979988898988
print(34.46.decimal) // outputs 0.46