舍入NSDecimalNumber HalfDown

时间:2018-03-21 09:19:10

标签: swift rounding nsdecimalnumber tax

众所周知,在使用精确数字(例如金钱)进行计算时,最好使用NSDecimalNumber代替基本floatdouble。然后,我们有舍入选项:

public enum RoundingMode : UInt {

    case plain // Round up on a tie
    case down // Always down == truncate
    case up // Always up
    case bankers // on a tie round so last digit is even
}

问题:

如何为此.plain执行舍入halfDown(与NSDecimalNumber相反,向下舍入)?

我原来的问题(您可以跳过本节)

设置舍入选项(可以更改):Up,Down,HalfUp

我正在通过此公式计算var pT = price include tax中的var p = price exclude tax

pT = roundingWithOption(p * tax)

pT是显示单位价格(必须包含税或商业转到jail lol ),人们可以自定义它=>我必须通过还原流程计算价格不含税

p = roundingWithReverseOption(pT2 / tax)

然后我可以将此price exclude tax保存到服务器并将其取回以供日后使用。我们只保存p,因为税收可能会发生变化,我们可以从其他地方获得税收=>如果税收改变,pT可能会有所不同。

如果没有任何变化(舍入,税收......),save and continue进程之前和之后的数字应该相同。

选项.up.down时很简单,但我不知道如何处理.plain

或者,您是否可以从自定义价格中提供更好的计算priceExcludeTax的解决方案?当应用折扣和数量时会更复杂,所以我先问一个简单的问题。

1 个答案:

答案 0 :(得分:4)

您可以尝试使用scale定义所需精度的此函数:

func roundSubPlain(_ num: NSDecimalNumber, scale: Int = 0) -> NSDecimalNumber {
    let precision = (1 / pow(10, scale + 2))
    let adjustedDecimalNumber = NSDecimalNumber(decimal: num.decimalValue - precision)
    let handler = NSDecimalNumberHandler(roundingMode: .plain, scale: Int16(scale), raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true)
    let roundedNum = adjustedDecimalNumber.rounding(accordingToBehavior: handler)

    return roundedNum
}

所以,如果你尝试:

let num1 = NSDecimalNumber(decimal: 5.5)
let num2 = NSDecimalNumber(decimal: 6.25)

你将拥有:

let subNum1 = roundSubPlain(num1) // 5
let subNum2 = roundSubPlain(num1, scale: 1) // 6.2

如果你想为银行家做同样的工作,你可以使用类似的东西:

func roundOdd(_ num: NSDecimalNumber, scale: Int = 0) -> NSDecimalNumber {
    let handler = NSDecimalNumberHandler(roundingMode: .bankers, scale: Int16(scale), raiseOnExactness: true, raiseOnOverflow: true, raiseOnUnderflow: true, raiseOnDivideByZero: true)
    let roundedNum = num.rounding(accordingToBehavior: handler)

    let diff = num.decimalValue - roundedNum.decimalValue
    let gap = (1 / pow(10, scale))

    if abs(diff / gap) == 0.5 {
        let adjust: Decimal = diff > 0 ? 1 : -1
        return NSDecimalNumber(decimal: roundedNum.decimalValue + adjust * gap)
    } else {
        return roundedNum
    }
}

这可以肯定地改进,但它有效:)

let num = NSDecimalNumber(decimal: 6.15)
let odd = roundOdd(num, scale: 1) // 6.1