NSNumberFormatter 没有按预期工作
NSNumberFormatter not working as expected
我们尝试对 X 小数位后的值进行 舍入 运算。为此,我们使用 NSNumberFormatter
class。结果出错了
工作JAVA代码
public static double roundOff(double value) {
DecimalFormat df2 = new DecimalFormat("#.##########");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
public static double roundOff2(double value) {
DecimalFormat df2 = new DecimalFormat("#.###");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
public static double roundOff2Step(double value) {
DecimalFormat df2 = new DecimalFormat("#.###");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
我们试过的Swift代码。
public func convertToRoundValue(number : Double)->Double{
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.roundingMode = .halfEven
let str = String(describing: formatter.string(from: NSNumber(value:number))!)
return str.toDouble()!
}
是否可以将 java 代码转换为 swift?此计算完全基于 银行部门 .
示例值:
8.60455187289436到8.61在java代码
8.60455187289436到8.60在Swift代码
我的假设:
//8.60455187289436
//8.60455187289444
//8.6045518728944
//8.604551872894
//8.60455187289
//8.6045518729
//8.604551873
//8.60455187
//8.6045519
//8.604552
//8.60455
//8.6046
//8.605
//8.61
//8.6
感谢大家
如果您想获得与 Java 相同的结果,请使用此 ceil 并四舍五入你的要求。
let value = 8.60455187289436
let stringValue = String(format: "%.2f", ceil(value*100)/100)
print(stringValue)
几点观察:
不要使用数字格式化程序进行此转换。这是非常低效的。使用 round
或 rounded
函数。如果你想四舍五入到小数点后两位,你可以乘以 100,四舍五入,然后除以 100。
例如,要使用银行四舍五入法将 Double
值四舍五入到一定的小数位数,则为:
extension Double {
func rounded(to decimalPlaces: Int) -> Double {
let multiplier = pow(10.0, Double(decimalPlaces))
return (self * multiplier).rounded(.toNearestOrEven) / multiplier
}
}
因此:
let value: Double = 8.60455187289436
let result = value.rounded(to: 2) // 8.60
使用银行家四舍五入让我怀疑这是不是金融计算。如果是这样,人们应该承认许多十进制值无法在浮点类型中准确表示的问题。参见 What Every Computer Scientist Should Know About Floating-Point Arithmetic。
这个问题我最喜欢的表现是十次加0.1。对于浮点类型,这将不起作用:
var sum: Double = 0
let increment: Double = 0.1
for _ in 0 ..< 10 {
sum += increment
}
if sum != 1 {
print("This is \(sum)!!!") // This is 0.9999999999999999!!!
}
您可以使用 Decimal
来避免该问题:
var sum: Decimal = 0
let increment = Decimal(sign: .plus, exponent: -1, significand: 1) // or Decimal(string: "0.1")!
for _ in 0 ..< 10 {
sum += increment
}
if sum == 1 {
print("Total is 1")
}
最重要的是,如果处理货币值,您可以考虑使用 Decimal
而不是 Double
。
因此,如果您想使用 Decimal
进行舍入,您可以使用:
extension Decimal {
func rounded(to decimalPlaces: Int) -> Decimal {
var input = self
var result = Decimal()
NSDecimalRound(&result, &input, decimalPlaces, .bankers)
return result
}
}
然后,再次:
let value: Decimal = 8.60455187289436
let result = value.rounded(to: 2) // 8.60
您给出了示例,其中 8.60455187289436
使用这些例程在 Java 中四舍五入为 8.61
,使用 HALF_EVEN
。我不相信是这样。例如,使用:
public double roundOff(double value) {
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df.format(value));
}
我得到了这些结果:
double result1 = roundOff(8.60455187289436); // 8.60
double result2 = roundOff(8.605); // 8.60
double result3 = roundOff(8.615); // 8.62
Log.d("RoundingDebug", Double.toString(result1) + " " + Double.toString(result2) + " " + Double.toString(result3));
如果您得到不同的结果,请向我们展示代码。但是无论是使用银行家四舍五入还是简单四舍五入,8.60455187289436
永远不会产生 8.61
.
所有讨论都假设您确实需要对结果进行四舍五入(例如,为了保存在某些数据存储中,作为未来计算的基础等)。但是,如果您的意图只是将值显示到一定数量的小数位,那么格式化程序就足够了。例如,您可以将格式化程序定义为 属性:
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.roundingMode = .halfEven
return formatter
}()
但是,使用此格式化程序的唯一目的是将 UI 中的数字显示为特定小数位的本地化字符串(或用于解析用户输入)。但是人们不会使用此格式化程序将 Double
往返于 String
并返回以执行舍入。这是一种执行舍入计算的低效方法。
我们尝试对 X 小数位后的值进行 舍入 运算。为此,我们使用 NSNumberFormatter
class。结果出错了
工作JAVA代码
public static double roundOff(double value) {
DecimalFormat df2 = new DecimalFormat("#.##########");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
public static double roundOff2(double value) {
DecimalFormat df2 = new DecimalFormat("#.###");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
public static double roundOff2Step(double value) {
DecimalFormat df2 = new DecimalFormat("#.###");
df2.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df2.format(value));
}
我们试过的Swift代码。
public func convertToRoundValue(number : Double)->Double{
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
formatter.roundingMode = .halfEven
let str = String(describing: formatter.string(from: NSNumber(value:number))!)
return str.toDouble()!
}
是否可以将 java 代码转换为 swift?此计算完全基于 银行部门 .
示例值:
8.60455187289436到8.61在java代码
8.60455187289436到8.60在Swift代码
我的假设:
//8.60455187289436
//8.60455187289444
//8.6045518728944
//8.604551872894
//8.60455187289
//8.6045518729
//8.604551873
//8.60455187
//8.6045519
//8.604552
//8.60455
//8.6046
//8.605
//8.61
//8.6
感谢大家
如果您想获得与 Java 相同的结果,请使用此 ceil 并四舍五入你的要求。
let value = 8.60455187289436
let stringValue = String(format: "%.2f", ceil(value*100)/100)
print(stringValue)
几点观察:
不要使用数字格式化程序进行此转换。这是非常低效的。使用
round
或rounded
函数。如果你想四舍五入到小数点后两位,你可以乘以 100,四舍五入,然后除以 100。例如,要使用银行四舍五入法将
Double
值四舍五入到一定的小数位数,则为:extension Double { func rounded(to decimalPlaces: Int) -> Double { let multiplier = pow(10.0, Double(decimalPlaces)) return (self * multiplier).rounded(.toNearestOrEven) / multiplier } }
因此:
let value: Double = 8.60455187289436 let result = value.rounded(to: 2) // 8.60
使用银行家四舍五入让我怀疑这是不是金融计算。如果是这样,人们应该承认许多十进制值无法在浮点类型中准确表示的问题。参见 What Every Computer Scientist Should Know About Floating-Point Arithmetic。
这个问题我最喜欢的表现是十次加0.1。对于浮点类型,这将不起作用:
var sum: Double = 0 let increment: Double = 0.1 for _ in 0 ..< 10 { sum += increment } if sum != 1 { print("This is \(sum)!!!") // This is 0.9999999999999999!!! }
您可以使用
Decimal
来避免该问题:var sum: Decimal = 0 let increment = Decimal(sign: .plus, exponent: -1, significand: 1) // or Decimal(string: "0.1")! for _ in 0 ..< 10 { sum += increment } if sum == 1 { print("Total is 1") }
最重要的是,如果处理货币值,您可以考虑使用
Decimal
而不是Double
。因此,如果您想使用
Decimal
进行舍入,您可以使用:extension Decimal { func rounded(to decimalPlaces: Int) -> Decimal { var input = self var result = Decimal() NSDecimalRound(&result, &input, decimalPlaces, .bankers) return result } }
然后,再次:
let value: Decimal = 8.60455187289436 let result = value.rounded(to: 2) // 8.60
您给出了示例,其中
8.60455187289436
使用这些例程在 Java 中四舍五入为8.61
,使用HALF_EVEN
。我不相信是这样。例如,使用:public double roundOff(double value) { DecimalFormat df = new DecimalFormat("#.##"); df.setRoundingMode(RoundingMode.HALF_EVEN); return Double.parseDouble(df.format(value)); }
我得到了这些结果:
double result1 = roundOff(8.60455187289436); // 8.60 double result2 = roundOff(8.605); // 8.60 double result3 = roundOff(8.615); // 8.62 Log.d("RoundingDebug", Double.toString(result1) + " " + Double.toString(result2) + " " + Double.toString(result3));
如果您得到不同的结果,请向我们展示代码。但是无论是使用银行家四舍五入还是简单四舍五入,
8.60455187289436
永远不会产生8.61
.所有讨论都假设您确实需要对结果进行四舍五入(例如,为了保存在某些数据存储中,作为未来计算的基础等)。但是,如果您的意图只是将值显示到一定数量的小数位,那么格式化程序就足够了。例如,您可以将格式化程序定义为 属性:
let formatter: NumberFormatter = { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.minimumFractionDigits = 2 formatter.maximumFractionDigits = 2 formatter.roundingMode = .halfEven return formatter }()
但是,使用此格式化程序的唯一目的是将 UI 中的数字显示为特定小数位的本地化字符串(或用于解析用户输入)。但是人们不会使用此格式化程序将
Double
往返于String
并返回以执行舍入。这是一种执行舍入计算的低效方法。