BigDecimal format with exponential - java

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

Related

Format a double to 6 decimal places precision

I want to format a double value to 6 places precision without rounding.
expected value after format to 6 decimal places
20790123833965.960938
I have tried using decimal format
DecimalFormat formatter = new DecimalFormat("#0.000000");
System.out.println(formatter.format(hashValue) );
And i got this
20790123833965.960000
As #Benoit already said in a comment, to keep the full precision of your number, you need a BigDecimal:
BigDecimal hashValue = new BigDecimal("20790123833965.960938");
DecimalFormat formatter = new DecimalFormat("#0.000000");
System.out.println(formatter.format(hashValue));
Output:
20790123833965.960938
Use this code, it will work.
public class JavaFormatter {
public static void main(String args[]) {
BigDecimal hashValue = new BigDecimal("20790123833965.960938");
DecimalFormat formatter = new DecimalFormat("#.######");
System.out.println(formatter.format(hashValue));
}
}

How can I convert an implied decimal point to a real decimal point in java?

I'm trying to take a string and convert into a currency. For example I would like to take the string 12579500 and convert it to $125,795.00. I am trying to use DecimalFormat("$#,###.00), to convert the string after I turn it into a double, but what I'm winding up with is $12,579,500.00.
How do I set the last 2 numbers at the end of the string to be decimal points?
Here is my code so far.
DecimalFormat df = new DecimalFormat("$#,###.00");
double ticketPriceNum = Double.parseDouble(ticketPrice);
System.out.print(df.format(ticketPriceNum));
This will make sure that your string is reduced by 2 characters
DecimalFormat df = new DecimalFormat("$#,###.00");
double ticketPriceNum = Double.parseDouble(ticketPrice.substring(0, ticketPrice.length()- 2));
System.out.print(df.format(ticketPriceNum));
try this please
public static void main(String[] args) {
DecimalFormat df = new DecimalFormat("$#,###,##.00");
//if last two digits of ticketprice should be decimal points
double ticketPriceNum = Double.parseDouble(ticketPrice/100);
System.out.println(df.format(ticketPriceNum ));
}

Different result in RoundingMode.HALF_UP

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.

Java - Is it possible to figure out the DecimalFormat of a string

I am trying to figure out how to, given a decimal through a String calculate the number of significant digits so that I can do a calculation to the decimal and print the result with the same number of significant digits. Here's an SSCCE:
import java.text.DecimalFormat;
import java.text.ParseException;
public class Test {
public static void main(String[] args) {
try {
DecimalFormat df = new DecimalFormat();
String decimal1 = "54.60"; // Decimal is input as a string with a specific number of significant digits.
double d = df.parse(decimal1).doubleValue();
d = d * -1; // Multiply the decimal by -1 (this is why we parsed it, so we could do a calculatin).
System.out.println(df.format(d)); // I need to print this with the same # of significant digits.
} catch (ParseException e) {
e.printStackTrace();
}
}
}
I know DecimalFormat is to 1) tell the program how you intend your decimal to be displayed (format()) and 2) to tell the program what format to expect a String-represented decimal to be in (parse()). But, is there a way to DEDUCE the DecimalFormat from a parsed string and then use that same DecimalFormat to output a number?
Use BigDecimal:
String decimal1 = "54.60";
BigDecimal bigDecimal = new BigDecimal(decimal1);
BigDecimal negative = bigDecimal.negate(); // negate keeps scale
System.out.println(negative);
Or the short version:
System.out.println((new BigDecimal(decimal1)).negate());
Find it via String.indexOf('.').
public int findDecimalPlaces (String input) {
int dot = input.indexOf('.');
if (dot < 0)
return 0;
return input.length() - dot - 1;
}
You can also configure a DecimalFormat/ NumberFormat via setMinimumFractionDigits() and setMaximumFractionDigits() to set an output format, rather than having to build the pattern as a string.
int sigFigs = decimal1.split("\\.")[1].length();
Computing the length of the string to the right of the decimal is probably the easiest method of achieving your goal.
If you want decimal places, you can't use floating-point in the first place, as FP doesn't have them: FP has binary places. Use BigDecimal, and construct it directly from the String. I don't see why you need a DecimalFormat object at all.
You could convert a number string to a format string using regex:
String format = num.replaceAll("^\\d*", "#").replaceAll("\\d", "0");
eg "123.45" --> "#.00" and "123" --> "#"
Then use the result as the pattern for a DecimalFormat
Not only does it work, it's only one line.

formating a number/string with decimal separator

I am trying to format a Number with DecimalFormat. But I want it to format a number, that is like
input: 1234. --> should be formatted to: 1,234.
But I get 1,234.0 or 1,234.00 depending on my rules for the decimal format
What do I have to do in order to get this done?
The methods that should help you are setMinimumFractionDigits and setMaximumFractionDigits.
format.setMinimumFractionDigits(0);
at a guess, is probably what your looking for.
To ensure that the decimal separator is always shown, use: DecimalFormat.setDecimalSeparatorAlwaysShown(true)
You could format the number regardless of whether it is a decimal or not by using
DecimalFormat f = new DecimalFormat("#,###");
f.format(whatever)...
If you don't want to display any decimal places, don't format a floating point value :) If you use BigInteger, int, or long, it should be fine:
import java.math.*;
import java.text.*;
public class Test {
private static final char p = 'p';
public static void main(String[] args) {
NumberFormat format = new DecimalFormat();
BigInteger value = BigInteger.valueOf(1234);
System.out.println(format.format(value));
System.out.println(format.format(1234));
System.out.println(format.format(1234L));
}
}
Try this:
DecimalFormat df = new DecimalFormat("#,###.", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
System.out.println(df.format(1234));

Categories