Swift中的NSDecimalRound

问题描述 投票:1回答:6

试图找出在Swift中舍入十进制数的“正确”方法,并努力正确设置C调用(或其他东西),因为它返回了一个奇怪的结果。这是Playground的一个片段:

import Foundation

func roundTo2(result: UnsafePointer<Double>, number: UnsafePointer<Double>) {

    var resultCOP = COpaquePointer(result)
    var numberCOP = COpaquePointer(number)

    NSDecimalRound(resultCOP, numberCOP, 2, .RoundDown)

}

var from: Double = 1.54762
var to: Double = 0.0

roundTo2(&to, &from)

println("From: \(from), to: \(to)")

输出 - >从:1.54762,到:1.54761981964356

我希望1.54。任何指针将不胜感激。

ios macos swift
6个回答
2
投票

我的解决方案

var from: Double = 1.54762
var to: Double = 0.0

let decimalSize = 2.0 //you want to round for 2 digits after decimal point, change to your right value
let k = pow(10.0, decimalSize) //k here is 100

let cent = from*k

/*
get floor (integer) value of this double, 
equal or less than 'cent'.You will get 154. 
For negative value, it will return-155. 
If you want to get -154, you have to use ceil(cent) for cent < 0.
*/
let centRound = floor(cent) 

to = centRound/k
println("From: \(from), to: \(to)")

0
投票

作为HoaParis回答的附加信息,您可以为Double进行扩展,以便稍后再轻松调用它:

extension Double{
    func roundDown(decimals:Int)->Double{
        var from: Double = self
        var to: Double = 0.0

        let decimalSize = 2.0 //you want to round for 2 digits after decimal point, change to your right value
        let k = pow(10.0, Double(decimals)) //k here is 100

        var cent = from*k

        var centRound = floor(cent) //get floor (integer) value of this double.You will get 154.

        to = centRound/k
        return to
    }
}

var from: Double = 1.54762

from.roundDown(2)// 1.54
from.roundDown(3)// 1.547

0
投票

这是另一种方法(如果你只想要修复四舍五入):

extension Double {
  mutating func roundTo2Digits() {
    self = NSString(format:"%2.2f", self).doubleValue
  }
}

var a:Double = 12.3456
a.roundTo2Digits()

0
投票
// Playground - noun: a place where people can play

import UIKit

// why rounding double (float) numbers is BAD IDEA

let d1 = 0.04499999999999999    // 0.045
let d2 = d1 + 5e-18             // 0.045 (a 'little bit' bigger)
let dd = d2 - d1                // 0.00000000000000000693889390390723
dd == 5e-18                     // false


// this should work by mathematical theory
// and it wokrks ...
// BUT!! the Double DOESN'T means Decimal Number

func round(d: Double, decimalNumbers: UInt) -> Double {
    let p = pow(10.0, Double(decimalNumbers))
    let s = d < 0.0 ? -1.0 : 1.0
    let dabs = p * abs(d) + 0.5
    return s * floor(dabs) / p
}

// this works as expected
let r1 = round(d1, 3)           // 0.045
let r2 = round(d2, 3)           // 0.045
r1 == r2                        // true

// this works only in our heads, not in my computer
// as expected too ... :-)
let r11 = round(d1, 2)          // 0.04
let r21 = round(d2, 2)          // 0.05
r11 == r21                      // false

// look at the difference, it is just about the decimal numbers required
// are you able predict such a result?

0
投票

没有任何包装器,舍入过程应该非常简单。我们应该做的 - 只需调用函数NSDecimalRound(_:_:_:_:),在那里描述:https://developer.apple.com/documentation/foundation/1412204-nsdecimalround

import Cocoa

/// For example let's take any value with multiple decimals like this:
var amount: NSDecimalNumber = NSDecimalNumber(value: 453.585879834)

/// The mutable pointer reserves only "one cell" in memory for the
let uMPtr = UnsafeMutablePointer<Decimal>.allocate(capacity: 1)

/// Connect the pointer to the value of amount
uMPtr[0] = amount.decimalValue

/// Let's check the connection between variable/pointee and the poiner
Swift.print(uMPtr.pointee) /// result: 453.5858798339999232

/// One more pointer to the pointer
let uPtr = UnsafePointer<Decimal>.init(uMPtr)

/// Standard function call
NSDecimalRound(uMPtr, uPtr, Int(2), NSDecimalNumber.RoundingMode.bankers)

/// Check the result
Swift.print(uMPtr.pointee as NSDecimalNumber) /// result: 453.59

0
投票

您可以使用modf浮点方法将浮点乘以100得到整个值,并将结果除以100。

let value = 2.12345
let twoFractionDigits = modf(value * 100).0 / 100    // 2.12

您还可以扩展BinaryFloatingPoint:

extension BinaryFloatingPoint {
    var whole: Self { return modf(self).0 }
    func roundedTo(fractionDigits n: Int) -> Self {
        precondition(n > 0)
        let power = Self(pow(10.0, Double(n)))
        return (self * power).whole / power
    }
    var roundedToTwoFractionDigits: Self {
        return roundedTo(fractionDigits: 2)
    }
}

let value = 1.54762
let oneFractionDigit = value.roundedTo(fractionDigits: 1) // 1.5
let twoFractionDigits = value.roundedToTwoFractionDigits   // 1.54
© www.soinside.com 2019 - 2024. All rights reserved.