Formatting Decimal Number - java

I am formatting a decimal number and I have the following criteria to format it:
Number should be at most two decimal places (10.1234=>10.12)
If there is only one digit after decimal then it will ends up with an extra 0 (10.5=>10.50)
Thousand separator will be comma (12345.2345 => 12,345.23)
I have written following logic:
double x = Double.parseDouble(value.toString());
String dec = x % 1 == 0 ? new java.text.DecimalFormat("###,###.##").format(x) : new java.text.DecimalFormat("###,###.00").format(x);
Now it is printing:
11111111111110.567=>11,111,111,111,110.57
111111111111110.567=>111,111,111,111,110.56
1111111111111110.567=>1,111,111,111,111,110.60
11111111111111110.567=>11,111,111,111,111,110
111111111111111110.567=>111,111,111,111,111,104
1111111111111111110.567=>1,111,111,111,111,111,170
I don't understand why the behavior changes. How should I print 1111111111111111110.567 as 1,111,111,111,111,111,110.57?

The problem is that you can't represent 1111111111111111110.567 exactly as a double in the first place. (You can't even represent your shortest value exactly, but the inaccuracy will increase significantly as you increase the magnitude.)
A double only has about 17 significant digits of useful data anyway - you're trying to get 22 digits.
Use BigDecimal if you want more precision - but be aware that this will change other things too. What kind of value are you trying to represent, anyway? Natural values (weights, distances etc) are appropriate for double; artificial values (particularly currency values) are appropriate for BigDecimal.

I managed to get this (You have to use BigDecimal):
import java.math.BigDecimal;
import java.text.NumberFormat;
public class Sandbox {
public static void main(String[] args) {
BigDecimal x = new BigDecimal("1111111111111111110.567");
DecimalFormat formatter = new DecimalFormat("###,###.00");
System.out.println(formatter.format(x));
}
}
OUTPUT:
1,111,111,111,111,111,110.57
Resource Links: DecimalFormat and BigDecimal
One more thing, you have to enter the BigDecimal number as a String or else it will cause problems.
BigDecimal x = new BigDecimal(1111111111111111110.567) will output the following.
1,111,111,111,111,111,168.00

Related

How to always keep 2 decimal places in Java

I want to round off any double to a String with 2 decimal places in Java.
I have tried using DecimalFormat but it doesn't give the expected results.
Any help would be appreciated.
Ex: I/P: 3402100.5323
I want to convert this to:
O/P: 34.02
I've tried using DecimalFormat("##,##,##0.00", new DecimalFormatSymbols(Locale.US))
but this results in 34,02,100.53 whereas I want it to output 34.02
PS: If the I/P is 34.02 I would expect it to remain same even after applying the formatting
In my opinion, this can be achieved in 2 steps:
Transform the number into your customised
round-off. (3402100.5323 to 34.021005323). Divide the input with power of 10 to make it round to 2 digits.
Then transformed number can be pretty-printed to truncate value after 2 decimals (34.021005323 to 34.02)
public static void main(String[] args) {
double input = 3402100.5323;
double output = input / getDivisor(input);
System.out.printf("%.2f%n", output);
}
private static double getDivisor(double input) {
int length = String.valueOf((long) input).length();
return Math.pow(10, length - 2) ;
}
Output: 34.02
String.format("%0.2f", 34.021005323)
See
https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#format(java.lang.String,%20java.lang.Object...) and
https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax
Turning one number into something completely different is, naturally, not the job of decimalformat.
To get from a number representing 3402100.5323 to the string "34.02", first you'd have to get a number that is closer to "34.02". In other words, divide by 10000.0 first.
From there, String.format("%.2f") seems like an easy path: That renders any double to a string, but never using more than 2 digits after the decimal separator. If you want 3400000.123 to turn into "34.00" and not "34", you can make that String.format("%.02f") to force the zeroes.
public String renderWhateverThatIs(double in) {
return String.format("%.02f", in / 100000.0);
}
renderWhateverThatIs(3402100.5323);
> 34,02
Note that the machine locale will dictate if you see a dot or a comma as separator. You can force the issue by explicitly passing a locale to format.
I think what you're looking for is the java.math.BigDecimal class (https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html).
In your case, it would look like this:
BigDecimal rounded = BigDecimal.valueOf(yourDoubleValueHere).setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println(rounded); // 34.02
It can replace doubles (with more complex syntax though) by basically storing numbers in their decimal form, which means you could make operations on it and keep having two decimal places and avoid rounding issues.
EDIT: after thinking about it, it's probably overkill since you only want to get a String with the rounded value, but I'll leave it there just in case.
I don’t believe you can achieve what you want (First 4 digits converted into a 2 digit double with 2 decimal places) in a single step. I’ll break down the steps for an approach that I would try:
Convert the input double to a string
double d = 3402100.5323;
String dStr1 = String.valueOf(d); // dStr1 will be “3402100.5323”
Next, remove the decimal from the string
String dStr2 = dStr1.replace(‘.’,’’); // dStr2 will be “34021005323”
Then, grab the first 4 digits you are interested in
String dStr3 = dStr2.substring(0,4); // dStr3 will be “3402”
Finally, insert a decimal point
String result = dStr3.substring(0,2) + “.” + dStr3.substring(2); // result will be “34.02”
You can use format for this try this out it work 100% for me.
String.format("%.2f", value)
Helpful link
https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax

java removing trailing decimal digits causing .0 become .99

I want to simply have a function that converts a double with as many decimal places into 4 decimal places without rounding.
I have this code that has been working fine but found a random instance where it turned .0 into .99
Here are some sample outputs
4.12897456 ->4.1289
4.5 ->4.5
4.5231->4.5231
5.53->5.53
5.52->5.199 (Wrong conversion, I want it to be 5.52)
private static double get4Donly(double val){
double converted = ((long)(val * 1e4)) / 1e4;
return converted
}
EDIT: This conversion is called thousands of times, so please suggest a method where I dont have to create a new string all the time.
You can use DecimalFormat
import java.text.DecimalFormat;
import java.math.RoundingMode;
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
DecimalFormat df = new DecimalFormat("#.####");
df.setRoundingMode(RoundingMode.DOWN);
for (Number n : Arrays.asList(4.12897456, 4.5, 4.5231, 5.53, 5.52)) {
Double d = n.doubleValue();
System.out.println(df.format(d));
}
}
}
RoundingMode.DOWN rounds towards zero, new DecimalFormat("#.####") creates a DecimalFormat instance that formats numbers to a maximum of 4 decimal places. Put those two together and the above code produces the following output, which I believe matches your expectations:
4.1289
4.5
4.5231
5.53
5.52
Doubles just don't work like you think they do.
They are stored in a binary form, not a decimal form. Just like '1 divided by 3' is not representable in a decimal double (0.3333333333 is not enough, it's infinite 3s, so not representable, so you get a rounding error), but '1 divided by 5' is representable just fine, there are numbers that are representable, and numbers that end up rounded when storing things in a double type, but crucially things that seem perfectly roundable in decimal may not be roundable in binary.
Given that they don't match up, your idea of 'eh, I will multiply by 4, turn it to a long, then convert back to a double, then divide by 1000' is not going to let those digits go through unmolested. This is not how you round things, as you're introducing additional loss in addition to the loss you already started out with due to using doubles.
You have 3 solutions available:
Just print it properly
A double cannot be considered to 'have 4 digits after the decimal separator' because a double isn't decimal.
Therefore, it doesn't even make sense to say: Please round this double to at most 4 fractional digits.
That is the crucial realisation. Once you understand that you'll be well along the way :)
What you CAN do is 'please take this double and print it by using no more than 4 digits after the decimal separator'.
String out = String.format("%.4f", 5.52);
or you can use System.printf(XXX) which is short for System.print(String.format(XXX)).
This is probably what you want
forget doubles entirely
For some domains its better to ditch doubles and switch to longs or ints. For example, if you're doing finances, it's better to store the atomic unit as per that currency in a long, and forego doubles instead. So, for dollars, store cents-in-a-long. For euros, the same. For bitcoin, store satoshis. Write custom rendering to render back in a form that is palatable for that currency:
long value = 450; // $4.50
String formatCurrency(long cents) {
return String.format("%s%s%d.%02d", cents < 0 ? "-" : " ", "$", Math.abs(cents) / 100, Math.abs(cents) % 100);
}
Use BigDecimal
This is generally more trouble than it is worth, but it stores every digit, decimally - it represent everything decimal notation can (and it also cannot represent anything else - 1 divided by 3 is impossible in BigDecimal).
I would recommend using the .substring() method by converting the double to a String. It is much easier to understand and achieve since you do not require the number to be rounded.
Moreover, it is the most simple out of all the other methods, such as using DecimalFormat
In that case, you could do it like so:
private static double get4Donly(double val){
String num = String.valueOf(val);
return Double.parseDouble(num.substring(0, 6));
}
However, if the length of the result is smaller than 6 characters, you can do:
private static double get4Donly(double val){
String num = String.valueOf(val);
if(num.length()>6) {
return Double.parseDouble(num.substring(0, 6));
}else {
return val;
}
}

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())

I want to store one digit after floating point

if I user entered 5.123 how can I store it in memory like 5.1
in java
NOTE : I don't need to display it I want to (store) it in one digit after floating point only !!
ex:
6.334213 => 6.3
7.23947 => 7.2
100.123123 = > 100.1
0.123123 => 0.1
Great question. Here's an example. You can use the DecimalFormat object.
import java.text.DecimalFormat;
import java.math.RoundingMode;
import java.util.*;
public class HelloWorld {
public static void main(String []args) {
DecimalFormat df = new DecimalFormat("##.#");
df.setRoundingMode(RoundingMode.DOWN);
float number = 6.334213f;
float fixedNumber = Float.parseFloat(df.format(number));
System.out.println(number);
System.out.println(fixedNumber);
}
}
First, you create the DecimalFormat object and determine the format, as well as the rounding mode. Then, you can use the format function to convert it. However, this function returns a StringBuffer object (see it here), so to store it in a float again, we need to convert it back to a float with Float.parseFloat().
UPDATE: (a better way)
This is probably a more performant way to do this... multiply the number by its base (because it's a decimal (regular) number, the base is 10), raised to how many digits after the decimal point you want to keep.
So, in the example below, we want to truncate everything except 1 significant digit to the right of the '.', so we multiply by ten to the 1 (which is just 10), use the Math.floor() function to remove the decimal, and then divide again by the same number you multiplied by.
public class HelloWorld {
public static void main(String []args) {
double number = 6.334213d;
double fixedNumber = Math.floor(number * 10.0) / 10.0;
System.out.println(fixedNumber); // 6.3
number = 6.334213d;
fixedNumber = Math.floor(number * 1000.0) / 1000.0;
System.out.println(fixedNumber); // 6.334
}
}
If we want to keep 3 digits after the '.', multiply by 10^3 (which is 1000), and then divide by the same number.
As far as I know there isn’t a good way to do this, so I tend to do this: Multiply by ten, then round it, then divide it by ten.
You can use:
DecimalFormat df = new DecimalFormat("###.#");
For more details on rounding off double values, please read this tutorial by Mkyong.com.

Matching a value upto 8 decimal places

I have a value/rate. I need it to match to 8 decimal places.
I don't want to use Regex.
Is there any other way to do it?
I tried finding a lot online but couldn't figure it out.
Thanks in advance
Sample input 65.2341234567
I just need to compare it to a value upto 8 decimal places. i.e. 64.23412345 .
import java.math.BigDecimal;
public class Compare {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal("65.2341234567").setScale(8, BigDecimal.ROUND_FLOOR);
BigDecimal bd2 = new BigDecimal("65.234123456799").setScale(8, BigDecimal.ROUND_FLOOR);
System.out.println( "equals " + bd1.equals(bd2));
}
}
Because of the unpredictable machine precision you won't be always able to compare in this range of precision with standard data types.
I think it would be wiser to compare in a range with an epsilon value that marks the "lost" precision.
value < value-epsilon
and
value > value+epsilon
let there be epsilon a small enough value like 0.002
as example.
I hope this helps.

Categories

Resources