Different result in RoundingMode.HALF_UP - java

Please comment me freely. What was wrong in the following program. It is giving different round result.
public class Test {
public static String round(double value, int places) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.toPlainString();
}
public static void main(String[] args) throws Exception {
double value1 = 1.1234565;
System.out.println(round(value1, 6));
double value2 = 1.1235;
System.out.println(round(value2, 3));
}
}
Why it is out put like that?
1.123457
1.123 --> Actually, I expect 1.124
In Doc(eclipse)

You're calling the BigDecimal(double) constructor. That's documented as:
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.
The notes are illuminating too, and I suggest you read them.
The value you're passing in is exactly 1.12349999999999994315658113919198513031005859375, as that's the closest double to 1.1235. You can see that if you print out bd.toPlainString() before calling setScale. Therefore, that isn't half-way between 1.123 and 1.124 - it's closest to 1.123.
If you want a BigDecimal value of exactly 1.1235, I suggest you pass it as a String instead:
import java.math.*;
public class Test {
public static String round(String value, int places) {
BigDecimal bd = new BigDecimal(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.toPlainString();
}
public static void main(String[] args) throws Exception {
String value1 = "1.1234565";
System.out.println(round(value1, 6));
String value2 = "1.1235";
System.out.println(round(value2, 3));
}
}
Alternatively you could use BigDecimal.valueOf(double) instead of new BigDecimal(double) - but then you still have the problem that you've converted your real original source data (the text in your source code) into a binary floating point number first, potentially losing information.

The problem is you are using to exact represention of the double including any representation error. A simple solution is to use the value you would get from the double if it was printed.
public static String round(double value, int places) {
return BigDecimal.valueOf(value)
.setScale(places, RoundingMode.HALF_UP);
.toPlainString();
}
BigDecimal.valueOf uses the simplest value which would be represented as the double you have.

Related

Return double type without trialing zero

I am trying to return the double/float value but without the trailing zero added to it.
I've used NumberFormat, DecimalFormat but once I cast double or float to the result, it will add trailing zero(which is expected). I was wondering if there is a way to prevent this.
private Double format (double input) {
NumberFormat nf = NumberFormat.getIntegerInstance(Locale.US);
Double result = null;
BigDecimal bd = new BigDecimal(input);
if(bd.intValue() > 99){
//(don't want to add trailing zeros here)
return (double)bd.intValue();
}else{
nf.setMinimumFractionDigits(1);
nf.setMaximumFractionDigits(1);
result = Double.parseDouble(nf.format(bd.doubleValue()));
}
return result;
P.S. I am not trying to return String value here.
The "trailing zeros" is only about the string representation of a float or double number.
As the trailing zeros do not affect the value of a number, the data stored in the float or double remains the same. For example, "3.4" and "3.4000" are the same number, it's only two different representations of this number, like "3.4 e+00" is still another way to display that very same number.
You can Use stripTrailingZeros which inbuilt method in Java that returns a BigDecimal after remove trailing zero.
Double.valueOf(bd.stripTrailingZeros().toPlainString());
If you assign an int value to a double variable, it will always be represented with a trailing zero by default. You have two choices:
Format it into a string in whichever you want.
Convert it into a BigDecimal and then use BigDecimal#stripTrailingZeros to get a BigDecimal without the trailing zero.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
double x = 5;
System.out.println(x);
BigDecimal y = BigDecimal.valueOf(x).stripTrailingZeros();
System.out.println(y);
}
}
Output:
5.0
5

BigDecimal format with exponential

I have a problem with formating BigDecimal in Java (Android Studio)!
I want to format BigDecimal to String when it is bigger than 16 characters, with 9 decimals plus exponential (0.000000000e+00).
I used String#format but the result is not correct, it is 1.000000000e+32 instead of 9.99999999e+31.
How can I get the number in the correct format? Here is the code.
String b = "9999999999999999";
String c = "9999999999999999";
BigDecimal resultMultyply = (new BigDecimal(b)).multiply(new BigDecimal(c));
String main_number = resultMultyply.toString();
if (main_number.length() > 16) {
// main_number = 99999999999999980000000000000001
main_number = String.format("%16.9e", new BigDecimal(main_number));
// main_number = 1.000000000e+32
}
main_number is correct before formatting.
Use DecimalFormat with rounding mode DOWN
Your problem is that you don't have your hands on the rounding mode when creating your output value. The default rounding mode for BigDecimal is HALF_UP, which is not what you want: you want to see the first digits as is. So that means you discard the digits after your expected precision, which translates into rounding DOWN. Unfortunately, BigDecimal doesn't offer such fine grain by default. So you have to use DecimalFormat.
All in all, it works like this:
import java.math.*;
import java.text.*;
public class Main {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("9999999999999999");
BigDecimal mul = a.multiply(a);
System.out.println(format(mul, 9));
}
private static String format(BigDecimal x, int scale) {
NumberFormat formatter = new DecimalFormat("0.0E0");
formatter.setRoundingMode(RoundingMode.DOWN);
formatter.setMinimumFractionDigits(scale);
return formatter.format(x);
}
}
Outputs:
9.999999999E31

How to show user defined digits after a decimal

I am trying to figure out how to show the correct number of digits after a decimal, based off a number passed into the method.
public static double chopDecimal(double value, int place)
{
int chopped;
//???
return chopped;
}
So if the value passed is 123.456789 and the place is 2, it should show 123.45.
The print statement is in another method.
System.out.println("***MyMath ChopDecimal Test***");
//Chop Decimal Test 1
if (MyMath.chopDecimal(123.456789, 2) == 123.45)
{
System.out.println("Chop Decimal Test 1 Passed");
}
else
{
System.out.printf("Chop Decimal Test 1 Failed. Your answer: %f Correct Answer: 123.45\n",
MyMath.chopDecimal(123.456789, 2));
}
//Chop Decimal Test 2
if (MyMath.chopDecimal(.98765, 4) == .9876)
{
System.out.println("Chop Decimal Test 2 Passed");
}
else
{
System.out.printf("Chop Decimal Test 2 Failed. Your answer: %f Correct Answer: .9876\n",
MyMath.chopDecimal(.98765, 4));
}
This is possible using java.text.NumberFormat, although when you wish to convert to String for 'showing' purposes.
To match your example though, I've converted it babck to a double:
public static double chopDecimal(double value, int place)
{
String chopped = NumberFormat.getInstance().setMaximumFractionDigits( place ).format( value );
return Double.valueOf( chopped );
}
I suggest you to use the java Rounding Mode.
Simple example:
public static void main(String[] args) {
System.out.println(chopDecimal(123.456789, 2));
}
public static String chopDecimal(double value, int place)
{
// Parameter is the pattern
DecimalFormat format = new DecimalFormat("0.00");
format.setRoundingMode(RoundingMode.HALF_UP);
return format.format(value);
}
This question is duplicated:
How to round a number to n decimal places in Java
Reference:
Oracle Documentation
All of the answers above are pretty great, but if this for something you need to be able to explain, I wrote the segment of code below with all pretty basic tools of programming. Study this process below, it's not always about the solution, more so about can you come up with a solution. Always keep that in mind when solving any problem. There is always time later to improve your solution.
public static void main(String[] args) {
chopDecimal(123.456789,2);
}
public static double chopDecimal(double value, int place)
{
String valToStr = Double.toString(value);
int decimal=0;
for(int i = 0; i < valToStr.length(); i++)
{
if(valToStr.charAt(i) == '.')
{
decimal = valToStr.indexOf(valToStr.charAt(i));
System.out.println(decimal);
break;
}
}
String newNum = valToStr.substring(0,(++decimal+place));
System.out.println(newNum);
double chopped = Double.parseDouble(newNum);
return chopped;
}
}
Let me know if you have any questions.
You can use BigDecimal and setScale:
double chopped = BigDecimal
.valueOf(value)
.setScale(place, RoundingMode.DOWN)
.doubleValue()

Avoid round number when casting a float to string

I need avoid round number when casting a float to string, I need the number is exactly the same.
In this moment if I make this:
String value = String.valueOf(1234567.99);
The the value = 1234568.0 ,so I need the value = 1234567.99 after casting.
1234567.99 can't be exactly represented as a float. The nearest float is actually equal to 1234568.
If you want more precision, you can use a double: 1234567.99d will do what you expect.
You can run this simple test to check it (it is in Java but easily transposable on android by replacing the println):
public static void main(String[] args) {
float f = 1234567.99f;
double d = 1234567.99d;
System.out.println(new BigDecimal(f));
System.out.println(new BigDecimal(d));
}
prints:
1234568
1234567.98999999999068677425384521484375
Note: String.valueOf(double) does round the double to another representation, with less decimals, of the same double. In other words, as you see above 1234567.99d can't be represented as a double and the nearest double is 1234567.98999999999068677425384521484375. But String.valueOf figures it out and uses the first representation of that double (with only 2 decimals) since they are effectively the same double according to the specifications of the language.
String.valueOf() never round off any number you have some other issue but you can try it as:
String value = ""+1234567.99;
String s = Double.toString(1234567.99);
update: for more control over the string's format, use DecimalFormat and DecimalFormatSymbols
For example:
java.text.DecimalFormat formater = new java.text.DecimalFormat();
formater.setMinimumFractionDigits(0);
formater.setMaximumFractionDigits(3);
formater.setGroupingUsed(false);
java.text.DecimalFormatSymbols dfs = new java.text.DecimalFormatSymbols();
dfs.setNaN("NaN");
formater.setDecimalFormatSymbols(dfs);
String s = formater.format(1234567.99);

Convert Double to String value preserving every digit

How do I convert a double value with 10 digits for e.g 9.01236789E9 into a string 9012367890 without terminating any of its digits ?
I tried 9.01236789E9 * Math.pow(10,9) but the result is still double "9.01236789E18"
double d = 9.01236789E9;
System.out.println(BigDecimal.valueOf(d).toPlainString());
While 10 digits should be preservable with no problems, if you're interested in the actual digits used, you should probably be using BigDecimal instead.
If you really want to format a double without using scientific notation, you should be able to just use NumberFormat to do that or (as of Java 6) the simple string formatting APIs:
import java.text.*;
public class Test
{
public static void main(String[] args)
{
double value = 9.01236789E9;
String text = String.format("%.0f", value);
System.out.println(text); // 9012367890
NumberFormat format = NumberFormat.getNumberInstance();
format.setMaximumFractionDigits(0);
format.setGroupingUsed(false);
System.out.println(format.format(value)); // 9012367890
}
}
Try String.format("%20.0f", 9.01236789E9)
Note though it's never an exact value, so "preserving every digit" doesn't really make sense.
You can use it.
String doubleString = Double.toString(inValue)
inValue -----> Described by you.to what position you want to Change double to a string.
In this case, you can also do
double value = 9.01236789E9;
System.out.println((long) value); // prints 9012367890

Categories