DecimalFormat not rounding to two decimal places correctly - java

In the program I am writing I have a percent change function. With the numbers I'm using, it is supposed to return .03, yet I just get 0. Using a calculator, the value not formatted would be 0.03303. I want the number to be truncated after the second decimal place, no rounding at all.
df = new DecimalFormat("###.##;-###.##");
df.setRoundingMode(RoundingMode.DOWN);
//later in code
return df.format(((price-base_price)/price)*100.00D);
Edit: all variable types are doubles. Base price is 756.60 and price is 756.85

Your assumption about the value calculated in ((price-base_price)/price)*100.00D is incorrect (I think you've probably invoked integer math, try ((price-base_price)/(double)price)*100.00D). When I directly execute,
double value = 0.03303;
DecimalFormat df = new DecimalFormat("###.##;-###.##");
df.setRoundingMode(RoundingMode.DOWN);
System.out.println(df.format(value));
I get the (requested) output
0.03

Related

Not able to print exact value of Double data Type variable [duplicate]

I want to print a double value in Java without exponential form.
double dexp = 12345678;
System.out.println("dexp: "+dexp);
It shows this E notation: 1.2345678E7.
I want it to print it like this: 12345678
What is the best way to prevent this?
Java prevent E notation in a double:
Five different ways to convert a double to a normal number:
import java.math.BigDecimal;
import java.text.DecimalFormat;
public class Runner {
public static void main(String[] args) {
double myvalue = 0.00000021d;
//Option 1 Print bare double.
System.out.println(myvalue);
//Option2, use decimalFormat.
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(8);
System.out.println(df.format(myvalue));
//Option 3, use printf.
System.out.printf("%.9f", myvalue);
System.out.println();
//Option 4, convert toBigDecimal and ask for toPlainString().
System.out.print(new BigDecimal(myvalue).toPlainString());
System.out.println();
//Option 5, String.format
System.out.println(String.format("%.12f", myvalue));
}
}
This program prints:
2.1E-7
.00000021
0.000000210
0.000000210000000000000001085015324114868562332958390470594167709350585
0.000000210000
Which are all the same value.
Protip: If you are confused as to why those random digits appear beyond a certain threshold in the double value, this video explains: computerphile why does 0.1+0.2 equal 0.30000000000001?
http://youtube.com/watch?v=PZRI1IfStY0
You could use printf() with %f:
double dexp = 12345678;
System.out.printf("dexp: %f\n", dexp);
This will print dexp: 12345678.000000. If you don't want the fractional part, use
System.out.printf("dexp: %.0f\n", dexp);
0 in %.0f means 0 places in fractional part i.e no fractional part. If you want to print fractional part with desired number of decimal places then instead of 0 just provide the number like this %.8f. By default fractional part is printed up to 6 decimal places.
This uses the format specifier language explained in the documentation.
The default toString() format used in your original code is spelled out here.
In short:
If you want to get rid of trailing zeros and Locale problems, then you should use:
double myValue = 0.00000021d;
DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); // 340 = DecimalFormat.DOUBLE_FRACTION_DIGITS
System.out.println(df.format(myValue)); // Output: 0.00000021
Explanation:
Why other answers did not suit me:
Double.toString() or System.out.println or FloatingDecimal.toJavaFormatString uses scientific notations if double is less than 10^-3 or greater than or equal to 10^7
By using %f, the default decimal precision is 6, otherwise you can hardcode it, but it results in extra zeros added if you have fewer decimals. Example:
double myValue = 0.00000021d;
String.format("%.12f", myvalue); // Output: 0.000000210000
By using setMaximumFractionDigits(0); or %.0f you remove any decimal precision, which is fine for integers/longs, but not for double:
double myValue = 0.00000021d;
System.out.println(String.format("%.0f", myvalue)); // Output: 0
DecimalFormat df = new DecimalFormat("0");
System.out.println(df.format(myValue)); // Output: 0
By using DecimalFormat, you are local dependent. In French locale, the decimal separator is a comma, not a point:
double myValue = 0.00000021d;
DecimalFormat df = new DecimalFormat("0");
df.setMaximumFractionDigits(340);
System.out.println(df.format(myvalue)); // Output: 0,00000021
Using the ENGLISH locale makes sure you get a point for decimal separator, wherever your program will run.
Why using 340 then for setMaximumFractionDigits?
Two reasons:
setMaximumFractionDigits accepts an integer, but its implementation has a maximum digits allowed of DecimalFormat.DOUBLE_FRACTION_DIGITS which equals 340
Double.MIN_VALUE = 4.9E-324 so with 340 digits you are sure not to round your double and lose precision.
You can try it with DecimalFormat. With this class you are very flexible in parsing your numbers.
You can exactly set the pattern you want to use.
In your case for example:
double test = 12345678;
DecimalFormat df = new DecimalFormat("#");
df.setMaximumFractionDigits(0);
System.out.println(df.format(test)); //12345678
I've got another solution involving BigDecimal's toPlainString(), but this time using the String-constructor, which is recommended in the javadoc:
this constructor is compatible with the values returned by Float.toString and Double.toString. This is generally the preferred way to convert a float or double into a BigDecimal, as it doesn't suffer from the unpredictability of the BigDecimal(double) constructor.
It looks like this in its shortest form:
return new BigDecimal(myDouble.toString()).stripTrailingZeros().toPlainString();
NaN and infinite values have to be checked extra, so looks like this in its complete form:
public static String doubleToString(Double d) {
if (d == null)
return null;
if (d.isNaN() || d.isInfinite())
return d.toString();
return new BigDecimal(d.toString()).stripTrailingZeros().toPlainString();
}
This can also be copied/pasted to work nicely with Float.
For Java 7 and below, this results in "0.0" for any zero-valued Doubles, so you would need to add:
if (d.doubleValue() == 0)
return "0";
Java/Kotlin compiler converts any value greater than 9999999 (greater than or equal to 10 million) to scientific notation ie. Epsilion notation.
Ex: 12345678 is converted to 1.2345678E7
Use this code to avoid automatic conversion to scientific notation:
fun setTotalSalesValue(String total) {
var valueWithoutEpsilon = total.toBigDecimal()
/* Set the converted value to your android text view using setText() function */
salesTextView.setText( valueWithoutEpsilon.toPlainString() )
}
This will work as long as your number is a whole number:
double dnexp = 12345678;
System.out.println("dexp: " + (long)dexp);
If the double variable has precision after the decimal point it will truncate it.
I needed to convert some double to currency values and found that most of the solutions were OK, but not for me.
The DecimalFormat was eventually the way for me, so here is what I've done:
public String foo(double value) //Got here 6.743240136E7 or something..
{
DecimalFormat formatter;
if(value - (int)value > 0.0)
formatter = new DecimalFormat("0.00"); // Here you can also deal with rounding if you wish..
else
formatter = new DecimalFormat("0");
return formatter.format(value);
}
As you can see, if the number is natural I get - say - 20000000 instead of 2E7 (etc.) - without any decimal point.
And if it's decimal, I get only two decimal digits.
I think everyone had the right idea, but all answers were not straightforward.
I can see this being a very useful piece of code. Here is a snippet of what will work:
System.out.println(String.format("%.8f", EnterYourDoubleVariableHere));
the ".8" is where you set the number of decimal places you would like to show.
I am using Eclipse and it worked no problem.
Hope this was helpful. I would appreciate any feedback!
The following code detects if the provided number is presented in scientific notation. If so it is represented in normal presentation with a maximum of '25' digits.
static String convertFromScientificNotation(double number) {
// Check if in scientific notation
if (String.valueOf(number).toLowerCase().contains("e")) {
System.out.println("The scientific notation number'"
+ number
+ "' detected, it will be converted to normal representation with 25 maximum fraction digits.");
NumberFormat formatter = new DecimalFormat();
formatter.setMaximumFractionDigits(25);
return formatter.format(number);
} else
return String.valueOf(number);
}
This may be a tangent.... but if you need to put a numerical value as an integer (that is too big to be an integer) into a serializer (JSON, etc.) then you probably want "BigInterger"
Example:
value is a string - 7515904334
We need to represent it as a numerical in a Json message:
{
"contact_phone":"800220-3333",
"servicer_id":7515904334,
"servicer_name":"SOME CORPORATION"
}
We can't print it or we'll get this:
{
"contact_phone":"800220-3333",
"servicer_id":"7515904334",
"servicer_name":"SOME CORPORATION"
}
Adding the value to the node like this produces the desired outcome:
BigInteger.valueOf(Long.parseLong(value, 10))
I'm not sure this is really on-topic, but since this question was my top hit when I searched for my solution, I thought I would share here for the benefit of others, lie me, who search poorly. :D
use String.format ("%.0f", number)
%.0f for zero decimal
String numSring = String.format ("%.0f", firstNumber);
System.out.println(numString);
I had this same problem in my production code when I was using it as a string input to a math.Eval() function which takes a string like "x + 20 / 50"
I looked at hundreds of articles... In the end I went with this because of the speed. And because the Eval function was going to convert it back into its own number format eventually and math.Eval() didn't support the trailing E-07 that other methods returned, and anything over 5 dp was too much detail for my application anyway.
This is now used in production code for an application that has 1,000+ users...
double value = 0.0002111d;
String s = Double.toString(((int)(value * 100000.0d))/100000.0d); // Round to 5 dp
s display as: 0.00021
This will work not only for a whole numbers:
double dexp = 12345678.12345678;
BigDecimal bigDecimal = new BigDecimal(Double.toString(dexp));
System.out.println("dexp: "+ bigDecimal.toPlainString());
My solution:
String str = String.format ("%.0f", yourDouble);
For integer values represented by a double, you can use this code, which is much faster than the other solutions.
public static String doubleToString(final double d) {
// check for integer, also see https://stackoverflow.com/a/9898613/868941 and
// https://github.com/google/guava/blob/master/guava/src/com/google/common/math/DoubleMath.java
if (isMathematicalInteger(d)) {
return Long.toString((long)d);
} else {
// or use any of the solutions provided by others, this is the best
DecimalFormat df =
new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMaximumFractionDigits(340); // 340 = DecimalFormat.DOUBLE_FRACTION_DIGITS
return df.format(d);
}
}
// Java 8+
public static boolean isMathematicalInteger(final double d) {
return StrictMath.rint(d) == d && Double.isFinite(d);
}
This works for me. The output will be a String.
String.format("%.12f", myvalue);
Good way to convert scientific e notation
String.valueOf(YourDoubleValue.longValue())

Keep up to 3 decimals without doing any rounding

I have a double that I want to keep only 3 decimal places but without applying any rounding at all.
E.g. 92.36699 should be 92.366
I tried the following:
DecimalFormat nf= new DecimalFormat("#0.000");
String number = nf.format(originalNumber);
But this results in 92.367
How can I do what I need?
This isn't "no rounding", it's DOWN rounding. Simply set the roundingMode.
DecimalFormat nf = new DecimalFormat("#0.000");
nf.setRoundingMode(RoundingMode.DOWN);
String number = nf.format(originalNumber);
Note the difference between FLOOR and DOWN - only relevant for negative numbers. FLOOR rounds towards negative infinity therefore -92.36699 would become "-92.367".

String 999999999.9999999999 is rounded to 1,000,000,000 BigDecimal

I have a problem where my 999999999.9999999999 String is being rounded to 1,000,000,000 BigDecimal when I parse it.
Code:
NumberFormat format = new DecimalFormat("#.0000000000######");
format.setParseIntegerOnly(false);
Number number = format.parse(text);
Result:
number = 1.0E9
If I use the same format to parse the result BigDecimal back to String:
format.format(number) results in 1,000,000,000
Why does this happen and how I can force the original format.parse(text) call not to round?
Unless there's some code you've omitted, parse is returning a Double, not a BigDecimal. (Try System.out.println(number.getClass()) to check this.)
If you want a BigDecimal, you have to use setParseBigDecimal to tell it to return a BigDecimal. (And to do that, format has to be declared as DecimalFormat.)
DecimalFormat format = new DecimalFormat("#.0000000000######");
format.setParseBigDecimal(true);
Number number = format.parse(text);

How to return a double with two decimal places?

I want to return a double with 2 decimal places (i.e. 123.00). The following are part of the codes. The output is always 123.0. How to get a two decimal places?
public static double getPrice(){
double price = Double.valueOf(showInputDialog("Stock's price : "));
DecimalFormat rounded = new DecimalFormat("###.00");
double newPrice = Double.valueOf(rounded.format(price));
System.out.println(newPrice);
return newPrice;
}
As long as the return type of your function is double, the short answer is "you can't".
Many numbers that have no more than two decimal digits cannot be represented exactly as double. One common example is 0.1. The double that's nearest to it is 0.100000000000000005551115...
No matter how much rounding you do, you wouldn't be able to get exactly 0.1.
As far as your options go, you could:
accept the rounding issues associated with using double;
return an int (i.e. the rounded value multiplied by 100);
return a String;
return a BigDecimal.
In particular, if you're representing monetary amounts, using double is almost certainly a bad idea.
When formatting, you're making a string from a double. Don't convert your formatted string to a double again :
String formattedPrice = rounded.format(price);
System.out.println(formattedPrice); // prints 123.00 or 123,00, depending on your locale
A double keeps a numerical value following IEEE754, it doesn't keep any formatting information and it's only as precise as the IEEE754 double precision allows. If you need to keep a rendering information like the number of digits after the comma, you need something else, like BigDecimal.

Print the number of digits before a decimal point

I know there are ways to get the number of digits after a decimal point, for instance the substring method, but how would I go about doing this for the number of digits before a decimal place?
I need to use this to convert US change (double) into Euro change(double). The way I would like to do this is by taking the number before a decimal (such as $1.) and times it by its euro equivalent (.7498) and take the number after a decimal (.16) and times that by its .01 euro coin value (.0075), add both values together to get the euro equivalent of $1.16 (.8698).
To get the number before decimal point,do this:
String str = new Double(your_double_number).toString().subString(0,str.indexOf('.'));
double v = Double.valueOf(str);
If you are using '$' sign then take 1 in place of 0.
Hope it will help you.
convert US change (double) into Euro change(double)
Please don't do that. Never, never, ever use double or float to represent money, because those datatypes cannot represent most decimal fractions, so you get rounding errors before you even start to do any calculations.
Instead, use BigDecimal.
First of all - just multiplying the Dollar value by the exchange rate will get you the euro value so there's no need to do that as far as i can see - you will just introduce rounding errors.
But if you did need to - just use substring
String dollarVal = "$1.16"
String justFullDollar = dollarVal.substring(1, dollarVal.indexOf("."));
String justCents = dollarVal.substring(dollarVal.indexOf(".")+1);
The Correct way would be to store all you money as integers or arbitrary precision objects that way you get no floating point errors too.
Convert to cents, multiply and convert back again.
e.g.
String dollarVal = "$1.16"
BigDecimal dollars = new BigDecimal(dollarVal.substring(1)); //1.16
BigDecimal cents = dollars.multiply(new BigDecimal(100)); //116
BigDecimal eurocents = cents.multiply(new BigDecimal(exchangeRate)); //86.9768
BigDecimal euros = eurocents.divide(new BigDecimal(100)); //0.869768
DecimalFormat formatter = new DecimalFormat("###.00");
String euroVal = "€" + formatter.format(euros);
You can use
String s[] = new Double(your number).toString().split(".");
The s[0] is the number before decimal point. and s[1] is the number after decimal point.
Both are in String, so you need to parse them into double using
double num1 = Double.parseDouble(s[0]);
double num2 = Double.parseDouble(s[1]);

Categories

Resources