We trying to do some operation with Rounding the values after X number of decimals. To do that We are using NSNumberFormatter
class. The results comes wrong.
Working JAVA Code
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));
}
The Swift Code We tried.
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()!
}
Is it possible to convert java code to swift? This calculations are purely based on Banking Sectors.
Example values :
8.60455187289436 to 8.61 In java code
8.60455187289436 to 8.60 In Swift code
My assumption :
//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
Thanks to All
A few observations:
Don't use number formatters for this conversion. That's very inefficient. Use the round
or rounded
functions. And if you want to round to 2 decimal places, you would multiple by 100, round, and then divide by 100.
E.g., to round a Double
value to a certain number of decimal places using a banker’s rounding, it would be:
extension Double {
func rounded(to decimalPlaces: Int) -> Double {
let multiplier = pow(10, Double(decimalPlaces))
return (self * multiplier).rounded(.toNearestOrEven) / multiplier
}
}
Thus:
let value: Double = 8.60455187289436
let result = value.rounded(to: 2) // 8.60
The use of banker’s rounding makes me wonder if this is a financial calculation. If so, one should acknowledge problems where many decimal values cannot be represented accurately in floating point types. See What Every Computer Scientist Should Know About Floating-Point Arithmetic.
My favorite manifestation of this problem is adding 0.1 ten times. With floating point types, this will not work:
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!!!
}
You can use Decimal
to avoid that problem:
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")
}
Bottom line, if dealing with currency values, you might consider using Decimal
rather than Double
.
So, if you want to round using Decimal
you might use:
extension Decimal {
func rounded(to decimalPlaces: Int, rounding mode: NSDecimalNumber.RoundingMode = .bankers) -> Decimal {
var input = self
var result = Decimal()
NSDecimalRound(&result, &input, decimalPlaces, mode)
return result
}
}
And, again:
let value: Decimal = 8.60455187289436
let result = value.rounded(to: 2) // 8.60
You gave the example where 8.60455187289436
was rounded to 8.61
in Java using these routines, using HALF_EVEN
. I don't believe that’s the case. For example, with:
public double roundOff(double value) {
DecimalFormat df = new DecimalFormat("#.##");
df.setRoundingMode(RoundingMode.HALF_EVEN);
return Double.parseDouble(df.format(value));
}
I got these results:
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));
If you're getting different results, please show us code. But whether using banker’s rounding or just plain rounding, 8.60455187289436
will never produce 8.61
.
All of the discussion presumes that you really need to round the results (e.g. for saving in some data store, the basis for future calculations, etc.). If, however, your intent was simply to show the value to a certain number of decimal places, then a formatter is sufficient. For example, you might define your formatter as a property:
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
formatter.roundingMode = .halfEven
return formatter
}()
But one would use this formatter solely for the sake of displaying the number as a localized string in the UI to a certain number of decimal places (or for parsing user input). But one would not use this formatter for round-tripping a Double
to a String
and back in order to perform rounding. That is an inefficient way of performing rounding calculations.