How to read a double value from a String with a certain precision (say 4) assuming the string contains something like "10.1234" using this api
If you want decimal precision, double is the wrong target type, as it is a binary format that cannot accurately represent most round decimal fractions. That double value will actually be rounded to something like 10.123399999999999999976
Instead, use BigDecimal all the way, or forget about runding while you read and manipulate the data, and round it only when you print the result.
Read The Floating-Point Guide for more information.
System.out.println(new Double(new BigDecimal("10.123456789").
setScale(4, BigDecimal.ROUND_DOWN). // choose precision and specify rounding policy
doubleValue()
));
>> run:
10.1234
I assume that your String also contains letters.
You can parse the number out of the String first:
String numberString = ...
int precision = ...
int index = numberString.indexOf(".");
numberString = numberString.substring(0, index+precision+1); // Maybe without "+1"
Double number = Double.valueOf(numberString);
You can use regular expression to truncate the String to at most 4 digits following the decimal point, then use Double.valueOf.
String[] tests = {
"12",
"12.",
"12.3",
"12.34",
"12.345",
"12.3456",
"12.34567",
"-123.45678",
"1.23456.789.0",
};
for (String test : tests) {
String truncated = test.replaceAll("(\\.\\d{4}).*", "$1");
System.out.printf("%15s %15s %15s%n",
test, truncated, Double.valueOf(truncated)
);
}
This prints:
12 12 12.0
12. 12. 12.0
12.3 12.3 12.3
12.34 12.34 12.34
12.345 12.345 12.345
12.3456 12.3456 12.3456
12.34567 12.3456 12.3456
-123.45678 -123.4567 -123.4567
1.23456.789.0 1.2345 1.2345
How the regex works
It captures a literal ., followed by up to four digits \d{4}, into \1. It also matches everything else that may follow .*, and replaces the whole thing with $1 (backreference to what \1 captured).
The advantage of this over, say, a simple indexOf approach is that it works even when there aren't 4 digits, or even when there isn't even a decimal point at all, without requiring special treatment.
See also
regular-expressions.info
Java Tutorials/Regular expressions
You can do something like
Math.round(number*100)/100
to get the precision, but this will probably not do what you want due to the internal representation of floats and doubles.
If you really need to work with a fixed number of digits after the decimal point consider using BigDecimal.
For formatting output you can use the C-like printf functionality as decribed in this article. It is not pretty but practical.
Related
This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 1 year ago.
Right now, Java is printing 7.1781566186590595E-6. I want it to print 7.17E-6.
I searched this up, but I only found how to reduce digits without scientific notation (so it will end up like 0.00 because the number is small).
Use format specifier "%.3g", tutorial here
float f = 7.1781566186590595E-6f;
System.out.format("%.3g", f);
Output
7.18e-06
Note, you mentioned 7.17E-6 in your question as desired output, but that's not correctly rounded - should be 7.18e-06
You can use String.format method to format and create your String, than you can use it like any String.
Therefore the "%.3g" format should be used like this:
double myDouble = 1/12345678d;
System.out.println(String.format("%.3g", myDouble));
Will result in: 8,10e-08.
Note: The ".3" in the format specifies the precision. In case you want more or less digits you can simply change the number to your needs like e.g. "%.5g" in case you want two extra digits.
You can also exchange the small "g" with "G" it'll print a capital "E" instead of the small "e".
In case you prefer the "." instead of the "," as a separator you can additionally explicitly specify the local to be used in the formatter like the following:
double myDouble = 1/12345678d;
System.out.println(String.format(Locale.ENGLISH, "%.3g", myDouble));
Will result in: 8.10e-08.
More information can be found in the JavaDoc of String.format here.
EDIT:
Interesting in your case:
When you use the format string as above (with the 'g') "%.3g" it'll round your value in the mathematical correct way. When you change the format string and use it with an 'e' "%.3e" it'll not round it and treat your number as a literal:
Code:
double myDouble = 7.1781566186590595E-6d;
System.out.println(String.format(Locale.ENGLISH, "%.3e", myDouble));
System.out.println(String.format(Locale.ENGLISH, "%.3g", myDouble));
Result:
7.178e-06 // using "%.3e" => literal, therefore not rounded
7.18e-06 // using "%.3g" => rounded
System.out.println(2e+5);
Above line's output is,
200000.0
While below line's,
System.out.println(2e-5);
output is,
2.0e-5
Why does 2e-5 is not solved down with -10^5 giving the output,
0.00002
Because that's how the designers of the Double class chose to implement it:
[...]
If m is greater than or equal to 10-3 but less than 107, then it is represented as the integer part of m, in decimal form with no leading zeroes, followed by '.' ('\u002E'), followed by one or more decimal digits representing the fractional part of m.
If m is less than 10-3 or greater than or equal to 107, then it is represented in so-called "computerized scientific notation." [...]
They could have made another choice, of course, but that's simply how it is.
As the documentation says, if you want a specific format, use a NumberFormat to format your double.
As already pointed out by #Nizet, when converting double to string, the output will have scientific notation if number of digits are large. And this is not just for decimals.
Consider:
double d = 1500000000;
System.out.println(String.valueOf(d));
This will print 1.5E9
If you want conversion to happen in readable format, use String.format
System.out.println(String.format ("%.0f", d));
will print 1500000000
Suppose I have money value represented as 10.000,00 in congo currency and I want it to be converted to a decimal amount like 10000.00. The money representation can be any from deferent countries and the outcome should be a decimal amount.
How do I achieve this in java?
It is better to keep money in integer format in minimal possible coin value - f.e. in US dollars - if you have 1$ and 25 cents - just save it as int 125 cents - it helps to avoid very common problems with java float/doubles precision errors.
You can use replace for example :
money.replace(",", "#").replace(".", "").replace("#", ".")
This will gives you:
10000.00
If you want to get the decimal value then you can use :
String money = "10.000,00";
NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse(money.replace(".", ""));
System.out.println(number);
double d = number.doubleValue();
System.out.println(d);
This will gives you:
10000.0
The method NumberFormat.getCurrencyInstance(Locale)
is made exactly for this purpose.
It takes care for all country-specific formatting (decimal point or comma, currency name, currency before or after number, thousands grouping, ...).
You use it like this, for example for Congo (Democratic Republic):
Locale locale = new Locale("", "CD");
NumberFormat currencyFormat= NumberFormat.getCurrencyInstance(locale);
String s = currencyFormat.format(10000.0);
Result is "CDF 10,000.00"
Note: For the following, I assume it will not necessarily be known beforehand which currency/locale to expect.
I did that just recently like this: Split the string by all possible markers (.,' should be enough). Then join the parts except for the last one. Before you add that, you add whatever decimal-sign you need. So, "10.000,00" => [[10],[000],[00]] => 10000.00. This can then be converted to BigDecimal.
(Don't use float or double for monetary values.)
The reason for doing it that way: You can handle most formats like
1.234,56
1,234.56
1'234.56
1234.567
And you automatically can handle numbers of fraction digits != 2.
You'd only have to be careful with whitespaces and currencies with no fractions (split array will be of size = 1). Also be careful with currencies with 3 fraction digits. It can be cumbersome to tell amounts apart using this approach that are not using a decimal at all and those that do ("1.234" =>"1234.000" and "1.234,567" => "1234.567"). You might need a little additional validation & correction for those cases.
I don't know if that's interesting for you, but Java 8 has a Currency class, that can give you number of fraction digits.
I also suggest writing a unit test, so you can be sure all expected input formats will end up in your desired format. And of course I suggest extensive documentation of what formats are accepted / allowed.
I am suprise to see the below program please advise how it is behaving like this as i aam very much concerened with poitn to precison after decimal point , below is the progrmam
double fixedRate = 0.997500000000; //**output --->0.9975
// BigDecimal fixedRate = new BigDecimal("0.997500000000");
double fixedRate1 = 0.1234567890123456789;
System.out.println(fixedRate);
System.out.println(fixedRate1);
and the output is
0.9975
0.12345678901234568
now please advise for the first the ouput is 0.9975 but late on for next it is not truncating after decimal points but why for first then.
The precision is not lost. It is just not printed because you do not need more digits to distinguish the printed value from any other double value.
If you do want to force a certain number of fractional digits, take a look at System.out.printf() or String.format().
See https://docs.oracle.com/javase/7/docs/api/java/util/Formatter.html for more details and possible formats.
The result may look like this:
System.out.printf("%.19f%n",fixedRate);
System.out.printf("%.19f%n", fixedRate1);
This is a printing problem.Please use this format to print your values and tell me the result:
double fixedRate = 0.997500000000;
double fixedRate1 = 0.1234567890123456789;
System.out.println(String.format("%.19f", fixedRate ));
System.out.println(String.format("%.19f", fixedRate1 ));
Good Luck !
According to your question
for the first the ouput is 0.9975 but late on for next it is not
truncating after decimal points but why for first then
Since double is numeric datatype and hence cannot hold the leading and trailing zeros.
A double doesn't care about formatting - it's about storage only. When you print it, it is converted to a String (using Double's static toString method).
In simple terms the value 0.9975 is not different from 0.997500000000or it is same as 0.997500000000 as zeros after a number will not have any value.
But consider if you had value like this 0.9975000000001 then all the numbers will be printed. Check it here.
If you want to format the value then you can see this question : How to properly display a price up to two decimals (cents) including trailing zeros in Java?
I want to convert this string "0.00071942446044" to double by using Double.parsedouble method but it always gives this answer 7.1942446044E-4
Is there any idea to convert it to double but keeping the same number as it is in the string?
Although both numbers are exactly the same, you could use DecimalFormat to manipulate the format in a way you like, only for presentation purpose. Here is an example:
String s = "0.00071942446044";
Double d = Double.parseDouble(s);
DecimalFormat df = new DecimalFormat("#.##############");
System.out.println("double: " + d);
System.out.println("formatted: " + df.format(d));
The out is:
double: 7.1942446044E-4
formatted: 0.00071942446044
Note that the number of # after decimal point is exactly the same as your example.
You can use new BigDecimal(myString), this is not the same but will keep the same representation. It provides API for doing different math, but is slower than doing arithmetical operations with doubles.
It's just a different way of displaying the number. The documentation does a reasonable job of explaining it exactly.
If you simply want to print it in the same format you can use printf or String.format:
Prints 0.000719:
System.out.printf("%f\n", Double.parseDouble("0.00071942446044"));
Prints 0.00071942446044: (with hard-coded precision, which is probably not idea)
System.out.printf("%.14f\n", Double.parseDouble("0.00071942446044"));
Also note that numbers aren't stored in terms of digits, so you won't get an exact large-precision representation for floating point types (float and double) (though double, as you can see can handle this amount of digits). Notice what happens if you use float:
Prints 7.1942444:
System.out.printf("%.7f\n", Float.parseFloat("7.1942446"));
Similar test case for double: (prints 7.1942446044352310)
System.out.printf("%.16f\n", Double.parseDouble("7.1942446044352312"));
If you want greater precision (at a price, obviously - memory and speed), you should use BigDecimal.