swift - 四舍五入 NSDecimalNumber HalfDown

标签 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
}

问题:

如何为这个 NSDecimalNumber 执行舍入 halfDown(.plain 的反向,在平局上向下舍入)?

我原来的问题(当然可以跳过这部分)

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

我正在通过以下公式从 var p = price exclude tax 计算 var pT = price include tax:

pT = roundingWithOption(p * tax)

pT 是显示单价(必须含税否则生意会进 jail 哈哈),人们可以自定义它=>我必须通过还原过程计算不含税的价格

p = roundingWithReverseOption(pT2 / tax)

然后我可以将这个price exclude tax 保存到服务器并在以后取回它。我们只保存 p 因为税收可能会改变,我们可以从其他地方获得税收 => 如果税收改变,pT 可能会有所不同。

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

It's simple when options are .up and .down, but I don't know what to do with .plain.

或者您能否提供更好的解决方案来根据自定义价格计算 priceExcludeTax?加上折扣和数量会比较复杂,所以我先问一个简单的问题。

最佳答案

您可以试试这个函数,其中 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

关于swift - 四舍五入 NSDecimalNumber HalfDown,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49402306/

相关文章:

swift - Alamofire:SessionManager 的超时不会根据配置而改变

ios - 保留循环 Swift 闭包

c++ - 将 float 舍入为预定义点的规则网格

objective-c - NSDecimalNumber 的小数部分

ios - 更改 UILabel 文本会导致可移动的 UIImageView 对象恢复到原始位置

arrays - 在 UITableView iOS Swift 中循环遍历数组并使用自定义单元格设置值时出现问题

ios - Swift roundf 不适用于浮点值

python - 如何四舍五入一个值但不以单位步长

swift - 尝试减少 Decimal 属性给出 : Type of expression is ambiguous without more context

objective-c - 如何将 NSDecimalNumber 转换为 NSNumber