我在iPhone应用程序中看到一些奇怪的错误,我已经缩小到使用NSNumberFormatter。
一个精简的例子......
在Xcode游乐场,我有:
let numberFormatter = NSNumberFormatter()
//numberFormatter.numberStyle = .DecimalStyle - does not change behavior
let numberString = "546000.06"
let number: NSNumber = numberFormatter.numberFromString(numberString)!
print("number: \(number)")
let number1: NSNumber = NSDecimalNumber(string: numberString)
print("number1: \(number1)")
这是输出:
number: 546000.0600000001
number1: 546000.06
请注意,将numberStyle设置为.DecimalStyle并不会改变任何内容。
此问题仅发生在某些数值上(例如,8.03是另一个数值)。我认为NSNumberFormatter对于这种类型的转换是安全的,我在互联网上没有看到很多关于这个问题的噪音,所以我想假设这是我做错了。
任何人都可以解释我所看到的吗?非常感谢任何帮助!
答案 0 :(得分:1)
看起来NSNumberFormatter存在问题。有一些值可以使此舍入误差逐渐增加。在XCode 7.2.1游乐场中,它显示大约8.03。
我解决这个问题的一种方法是舍入十进制数。由于差值为+/-很小,因此四舍五入到四分之一的位置应该可行。您可以使用各种舍入模式。在这个例子中,我使用了RoundPlain。
var initialValue = NSDecimalNumber(string: "7")
let handler = NSDecimalNumberHandler(roundingMode: NSRoundingMode.RoundPlain, scale: 4, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: false)
let numberFormatter = NSNumberFormatter()
for index in 1...300 {
initialValue = initialValue.decimalNumberByAdding(0.01)
let stringValue = "\(initialValue)"
var number = numberFormatter.numberFromString(stringValue)
var decimalNumber: NSDecimalNumber = NSDecimalNumber(decimal: number!.decimalValue)
decimalNumber = decimalNumber.decimalNumberByRoundingAccordingToBehavior(handler)
print("stringValue = \(stringValue), decimalNumber = \(decimalNumber), number = \(number!)")
}
答案 1 :(得分:0)
您看到了舍入错误。
如果您想向用户显示两位小数位数,请设置maximumFractionDigits
:
let numberFormatter = NSNumberFormatter()
numberFormatter.maximumFractionDigits = 2
let firstNumber = NSNumber(float:546000.06)
let firstNumberString = numberFormatter.stringFromNumber(firstNumber)!
let secondNumber = NSNumber(float:5.1337)
let secondNumberString = numberFormatter.stringFromNumber(secondNumber)!
print("firstNumber: \(firstNumberString)")
print("secondNumber: \(secondNumberString)")
输出将是:
"firstNumber: 546000.06\n"
"secondNumber: 5.13\n"
如果您尝试从字符串中解析一个数字,那么您已经完成了设置。
let thirdNumber = numberFormatter.numberFromString("546000.06")!
print("thirdNumber \(thirdNumber.className): \(thirdNumber)")
最后一行打印对象本身的描述(带有舍入错误):
"thirdNumber __NSCFNumber: 546000.0600000001\n"
您想要解析以下字符串:
let currencyString = "$546,000.06"
首先,我们创建一个带有locale
和.CurrencyStyle
的格式化程序。请注意,locale
取决于您尝试解析的字符串,而不取决于您运行的系统。
let currencyFormatter = NSNumberFormatter.init()
currencyFormatter.locale = NSLocale.init(localeIdentifier: "en_US")
currencyFormatter.numberStyle = .CurrencyStyle
我们现在可以使用格式化程序来删除字符串。
let currencyNumber = currencyFormatter.numberFromString(currencyString)!
您现在可以自由存储此对象,例如在CoreData中。但是,如果您不想将值呈现给用户(或在控制台上打印),则 使用NSNumberFormatter
。如果直接打印对象,则使用对象的description
(或debugDescription
)。
因此,让我们创建另一个格式化程序来打印NSNumber
对象的值:
let outputFormatter = NSNumberFormatter.init()
outputFormatter.maximumFractionDigits = 10
使用多个小数位数字应该打印任何可能的舍入错误。但是
print("Number: \(outputFormatter.stringFromNumber(currencyNumber)!)")
输出所需的结果:
"Number: 546000.06\n"
您所看到的是NSNumber
对象(description
/ debugDescription
)的内部表示结果。