舍入 NSDecimalNumber

Posted

技术标签:

【中文标题】舍入 NSDecimalNumber【英文标题】:Rounding NSDecimalNumber 【发布时间】:2010-10-20 18:46:30 【问题描述】:

我很难弄清楚看起来应该很简单的东西。我需要将 NSDecimalNumber 精确地四舍五入到特定的小数位数(在运行时确定)。据我所知,我有两个选项,我都不喜欢。

    转换为浮点数,并使用 C 舍入函数:我不喜欢这样,因为在这种情况下准确性很重要。浮点数不能总是准确地表示十进制数,这可能会导致问题。 使用 NSNumberFormatter 转换为字符串,然后再转换回来:我不喜欢这个,因为它看起来丑陋且效率低下。

还有其他我错过的方法吗? 得到有一种简单的方法可以对 NSDecimalNumbers 进行四舍五入,但我似乎无法终生弄清楚它是什么。

【问题讨论】:

【参考方案1】:

您只需使用所需的NSDecimalNumberBehaviors 协议调用decimalNumberByRoundingAccordingToBehavior:。请参阅dev docs 中的NSDecimalNumberBehaviors 参考。

更新:见http://www.cimgf.com/2008/04/23/cocoa-tutorial-dont-be-lazy-with-nsdecimalnumber-like-me/

【讨论】:

RTFM 不是响应。响应是“您只需调用 decimalNumberByRoundingAccordingToBehavior:使用所需的 NSDecimalNumberBehaviors 协议。”参考开发文档以提供各种协议的枚举,而不是在此处复制它们。【参考方案2】:

对于那些喜欢示例代码的人...

四舍五入到小数点后两位 (12345.68):

NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"];
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                          scale:2
                                                                               raiseOnExactness:NO
                                                                                raiseOnOverflow:NO
                                                                               raiseOnUnderflow:NO
                                                                            raiseOnDivideByZero:NO];

NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior];

四舍五入到最接近的千位 (12000):

NSDecimalNumber *originalNumber = [NSDecimalNumber decimalNumberWithString:@"12345.6789"];
NSDecimalNumberHandler *behavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain
                                                                                          scale:-3
                                                                               raiseOnExactness:NO
                                                                                raiseOnOverflow:NO
                                                                               raiseOnUnderflow:NO
                                                                            raiseOnDivideByZero:NO];

NSDecimalNumber *roundedNumber = [originalNumber decimalNumberByRoundingAccordingToBehavior:behavior];

【讨论】:

【参考方案3】:

我在 Swift 3 中使用以下代码让它工作。

let amount = NSDecimalNumber(string: "123.456789")
let handler = NSDecimalNumberHandler(roundingMode: .plain, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let roundedAmount = amount.rounding(accordingToBehavior: handler)

注意 scale 参数,用于定义您需要的小数位。此处概述:https://developer.apple.com/reference/foundation/nsdecimalnumberhandler/1578295-decimalnumberhandlerwithrounding

【讨论】:

【参考方案4】:

我正在使用这个解决方案:

import Foundation

extension NSDecimalNumber 
    public func round(_ decimals:Int) -> NSDecimalNumber 
        return self.rounding(accordingToBehavior:
            NSDecimalNumberHandler(roundingMode: .plain,
                                   scale: Int16(decimals),
                                   raiseOnExactness: false,
                                   raiseOnOverflow: false,
                                   raiseOnUnderflow: false,
                                   raiseOnDivideByZero: false))
    


let amount = NSDecimalNumber(string: "123.456")

amount.round(2)  --> 123.46
amount.round(1)  --> 123.5
amount.round(0)  --> 123
amount.round(-1) --> 120
amount.round(-2) --> 100

【讨论】:

以上是关于舍入 NSDecimalNumber的主要内容,如果未能解决你的问题,请参考以下文章

哪个舍入舍入日期时间在 SQL 中更有效

T-SQL 舍入与 C# 舍入

T-SQL 舍入与 C# 舍入

BigDecimal提供了8种舍入方式

MATLAB 舍入函数 - 它如何向上或向下舍入 0.5?

常用函数