Converting numeric value with currency symbol back to Decimal with NumberFormat - java

I would like to convert a possibly Decimal value prefixed with currency symbol into only numeric value.
For example -
The value can be like any of the following
String s1 = "£32,847,676.65";
String s2 = "£3,456.00";
String s3 = "£831,209";
I would like the result after conversion to be like - 32847676.65, 3456.00 and 831209.
I tried using the parse() method of the NumberFormat in this way -
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.UK);
numberFormat.setMinimumFractionDigits(2);
Number num = nf.parse(s1);
double dd = num.doubleValue();
BigDecimal gg = new BigDecimal(dd);
System.out.println(gg);
But the result is - 32847676.649999998509883880615234375 which is not quite exactly the correct one.
I need it to be numeric so that may be I can perform some kind of calculation.
Can you guys guide me with what else can I try

You already parse the value correctly. The problem is this:
BigDecimal gg = new BigDecimal(dd);
You covnert the value to BigDecimal, and the rounding problems of doubles account for the decimal places after the dot. Use:
BigDecimal gg = new BigDecimal(dd).setScale(2);
or
BigDecimal gg = new BigDecimal(dd).setScale(2,RoundingMode.HALF_UP);

When playing with BigDecimal, the appropriate constructor is BigDecimal(String val)
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.UK);
BigDecimal gg = new BigDecimal(nf.parse(s1).toString());
System.out.println(gg);
BigDecimal(double val) does construct an exact decimal representation of the double value, which is not the human readable value you expected.
"The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
[...]
Therefore, it is generally recommended that the String constructor be used in preference to this one"
Source : BigDecimal javadoc

You can try the following without BigDecimal or NumberFormat. ;)
String s1 = "£32,847,676.65";
// remove the £ and ,
String s2 = s1.replaceAll("[£,]", "");
// then turn into a double
double d = Double.parseDouble(s2);
// and round up to two decimal places.
double value = (long) (d * 100 + 0.5) / 100.0;
System.out.printf("%.2f%n", value);
prints
32847676.65
If youw ant to avoid rounding error in your calculations but don't want the heavy weight BigDecimal you can use long cents.
// value in cents as an integer.
long value = (long) (d * 100 + 0.5);
// perform some calculations on value here
System.out.printf("%.2f%n", value / 100.0);

It is not guaranteed to work, but according to the NumberFormat API documentation, its getXyzInstance methods will return a DecimalFormat instance for "the vast majority of locales". This can probably be interpreted as "for all locales, unless proprietary locale service providers are installed".
If you can cast your NumberFormat to DecimalFormat, you can tell it to parse to a BigDecimal directly, reducing your code to:
DecimalFormat nf = (DecimalFormat) NumberFormat.getCurrencyInstance(Locale.UK);
nf.setParseBigDecimal(true);
BigDecimal gg = (BigDecimal) nf.parse(s1);
System.out.println(gg);
In this case, you will have no problem with the inaccuracy of binary floating point numbers.

Related

keep trailing zeros for doubla value java [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 8 years ago.
If the value is 200.3456, it should be formatted to 200.34.
If it is 200, then it should be 200.00.
Here's an utility that rounds (instead of truncating) a double to specified number of decimal places.
For example:
round(200.3456, 2); // returns 200.35
Original version; watch out with this
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
This breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)). Thanks to Sloin for pointing this out.
I've been using the above to round "not-too-big" doubles to 2 or 3 decimal places happily for years (for example to clean up time in seconds for logging purposes: 27.987654321987 -> 27.99). But I guess it's best to avoid it, since more reliable ways are readily available, with cleaner code too.
So, use this instead
(Adapted from this answer by Louis Wasserman and this one by Sean Owen.)
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Note that HALF_UP is the rounding mode "commonly taught at school". Peruse the RoundingMode documentation, if you suspect you need something else such as Bankers’ Rounding.
Of course, if you prefer, you can inline the above into a one-liner:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
And in every case
Always remember that floating point representations using float and double are inexact.
For example, consider these expressions:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
For exactness, you want to use BigDecimal. And while at it, use the constructor that takes a String, never the one taking double. For instance, try executing this:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
Some excellent further reading on the topic:
Item 48: "Avoid float and double if exact answers are required" in Effective Java (2nd ed) by Joshua Bloch
What Every Programmer Should Know About Floating-Point Arithmetic
If you wanted String formatting instead of (or in addition to) strictly rounding numbers, see the other answers.
Specifically, note that round(200, 0) returns 200.0. If you want to output "200.00", you should first round and then format the result for output (which is perfectly explained in Jesper's answer).
If you just want to print a double with two digits after the decimal point, use something like this:
double value = 200.3456;
System.out.printf("Value: %.2f", value);
If you want to have the result in a String instead of being printed to the console, use String.format() with the same arguments:
String result = String.format("%.2f", value);
Or use class DecimalFormat:
DecimalFormat df = new DecimalFormat("####0.00");
System.out.println("Value: " + df.format(value));
I think this is easier:
double time = 200.3456;
DecimalFormat df = new DecimalFormat("#.##");
time = Double.valueOf(df.format(time));
System.out.println(time); // 200.35
Note that this will actually do the rounding for you, not just formatting.
The easiest way, would be to do a trick like this;
double val = ....;
val = val*100;
val = Math.round(val);
val = val /100;
if val starts at 200.3456 then it goes to 20034.56 then it gets rounded to 20035 then we divide it to get 200.34.
if you wanted to always round down we could always truncate by casting to an int:
double val = ....;
val = val*100;
val = (double)((int) val);
val = val /100;
This technique will work for most cases because for very large doubles (positive or negative) it may overflow. but if you know that your values will be in an appropriate range then this should work for you.
Please use Apache commons math:
Precision.round(10.4567, 2)
function Double round2(Double val) {
return new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue();
}
Note the toString()!!!!
This is because BigDecimal converts the exact binary form of the double!!!
These are the various suggested methods and their fail cases.
// Always Good!
new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - WRONG - new BigDecimal(val).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - TRY AGAIN - Math.round(val * 100.d) / 100.0d
Double val = 256.025d; //EXPECTED 256.03d
256.02 - OOPS - new DecimalFormat("0.00").format(val)
// By default use half even, works if you change mode to half_up
Double val = 256.025d; //EXPECTED 256.03d
256.02 - FAIL - (int)(val * 100 + 0.5) / 100.0;
double value= 200.3456;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value));
If you really want the same double, but rounded in the way you want you can use BigDecimal, for example
new BigDecimal(myValue).setScale(2, RoundingMode.HALF_UP).doubleValue();
double d = 28786.079999999998;
String str = String.format("%1.2f", d);
d = Double.valueOf(str);
For two rounding digits. Very simple and you are basically updating the variable instead of just display purposes which DecimalFormat does.
x = Math.floor(x * 100) / 100;
Rounding a double is usually not what one wants. Instead, use String.format() to represent it in the desired format.
In your question, it seems that you want to avoid rounding the numbers as well? I think .format() will round the numbers using half-up, afaik?
so if you want to round, 200.3456 should be 200.35 for a precision of 2. but in your case, if you just want the first 2 and then discard the rest?
You could multiply it by 100 and then cast to an int (or taking the floor of the number), before dividing by 100 again.
200.3456 * 100 = 20034.56;
(int) 20034.56 = 20034;
20034/100.0 = 200.34;
You might have issues with really really big numbers close to the boundary though. In which case converting to a string and substring'ing it would work just as easily.
value = (int)(value * 100 + 0.5) / 100.0;

Double in 2 decimal format [duplicate]

This question already has answers here:
How to round a number to n decimal places in Java
(39 answers)
Closed 8 years ago.
If the value is 200.3456, it should be formatted to 200.34.
If it is 200, then it should be 200.00.
Here's an utility that rounds (instead of truncating) a double to specified number of decimal places.
For example:
round(200.3456, 2); // returns 200.35
Original version; watch out with this
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
long factor = (long) Math.pow(10, places);
value = value * factor;
long tmp = Math.round(value);
return (double) tmp / factor;
}
This breaks down badly in corner cases with either a very high number of decimal places (e.g. round(1000.0d, 17)) or large integer part (e.g. round(90080070060.1d, 9)). Thanks to Sloin for pointing this out.
I've been using the above to round "not-too-big" doubles to 2 or 3 decimal places happily for years (for example to clean up time in seconds for logging purposes: 27.987654321987 -> 27.99). But I guess it's best to avoid it, since more reliable ways are readily available, with cleaner code too.
So, use this instead
(Adapted from this answer by Louis Wasserman and this one by Sean Owen.)
public static double round(double value, int places) {
if (places < 0) throw new IllegalArgumentException();
BigDecimal bd = BigDecimal.valueOf(value);
bd = bd.setScale(places, RoundingMode.HALF_UP);
return bd.doubleValue();
}
Note that HALF_UP is the rounding mode "commonly taught at school". Peruse the RoundingMode documentation, if you suspect you need something else such as Bankers’ Rounding.
Of course, if you prefer, you can inline the above into a one-liner:
new BigDecimal(value).setScale(places, RoundingMode.HALF_UP).doubleValue()
And in every case
Always remember that floating point representations using float and double are inexact.
For example, consider these expressions:
999199.1231231235 == 999199.1231231236 // true
1.03 - 0.41 // 0.6200000000000001
For exactness, you want to use BigDecimal. And while at it, use the constructor that takes a String, never the one taking double. For instance, try executing this:
System.out.println(new BigDecimal(1.03).subtract(new BigDecimal(0.41)));
System.out.println(new BigDecimal("1.03").subtract(new BigDecimal("0.41")));
Some excellent further reading on the topic:
Item 48: "Avoid float and double if exact answers are required" in Effective Java (2nd ed) by Joshua Bloch
What Every Programmer Should Know About Floating-Point Arithmetic
If you wanted String formatting instead of (or in addition to) strictly rounding numbers, see the other answers.
Specifically, note that round(200, 0) returns 200.0. If you want to output "200.00", you should first round and then format the result for output (which is perfectly explained in Jesper's answer).
If you just want to print a double with two digits after the decimal point, use something like this:
double value = 200.3456;
System.out.printf("Value: %.2f", value);
If you want to have the result in a String instead of being printed to the console, use String.format() with the same arguments:
String result = String.format("%.2f", value);
Or use class DecimalFormat:
DecimalFormat df = new DecimalFormat("####0.00");
System.out.println("Value: " + df.format(value));
I think this is easier:
double time = 200.3456;
DecimalFormat df = new DecimalFormat("#.##");
time = Double.valueOf(df.format(time));
System.out.println(time); // 200.35
Note that this will actually do the rounding for you, not just formatting.
The easiest way, would be to do a trick like this;
double val = ....;
val = val*100;
val = Math.round(val);
val = val /100;
if val starts at 200.3456 then it goes to 20034.56 then it gets rounded to 20035 then we divide it to get 200.34.
if you wanted to always round down we could always truncate by casting to an int:
double val = ....;
val = val*100;
val = (double)((int) val);
val = val /100;
This technique will work for most cases because for very large doubles (positive or negative) it may overflow. but if you know that your values will be in an appropriate range then this should work for you.
Please use Apache commons math:
Precision.round(10.4567, 2)
function Double round2(Double val) {
return new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue();
}
Note the toString()!!!!
This is because BigDecimal converts the exact binary form of the double!!!
These are the various suggested methods and their fail cases.
// Always Good!
new BigDecimal(val.toString()).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - WRONG - new BigDecimal(val).setScale(2,RoundingMode.HALF_UP).doubleValue()
Double val = 260.775d; //EXPECTED 260.78
260.77 - TRY AGAIN - Math.round(val * 100.d) / 100.0d
Double val = 256.025d; //EXPECTED 256.03d
256.02 - OOPS - new DecimalFormat("0.00").format(val)
// By default use half even, works if you change mode to half_up
Double val = 256.025d; //EXPECTED 256.03d
256.02 - FAIL - (int)(val * 100 + 0.5) / 100.0;
double value= 200.3456;
DecimalFormat df = new DecimalFormat("0.00");
System.out.println(df.format(value));
If you really want the same double, but rounded in the way you want you can use BigDecimal, for example
new BigDecimal(myValue).setScale(2, RoundingMode.HALF_UP).doubleValue();
double d = 28786.079999999998;
String str = String.format("%1.2f", d);
d = Double.valueOf(str);
For two rounding digits. Very simple and you are basically updating the variable instead of just display purposes which DecimalFormat does.
x = Math.floor(x * 100) / 100;
Rounding a double is usually not what one wants. Instead, use String.format() to represent it in the desired format.
In your question, it seems that you want to avoid rounding the numbers as well? I think .format() will round the numbers using half-up, afaik?
so if you want to round, 200.3456 should be 200.35 for a precision of 2. but in your case, if you just want the first 2 and then discard the rest?
You could multiply it by 100 and then cast to an int (or taking the floor of the number), before dividing by 100 again.
200.3456 * 100 = 20034.56;
(int) 20034.56 = 20034;
20034/100.0 = 200.34;
You might have issues with really really big numbers close to the boundary though. In which case converting to a string and substring'ing it would work just as easily.
value = (int)(value * 100 + 0.5) / 100.0;

how to multiply two doubles

I am working on an currency converter android application in which I am trying to multiply a double with another double value but after multiplying I am not getting the correct value. i also tried BigDecimal and still didn't get the correct amount. What would be best way to multiply doubles?
second_amount = Double.parseDouble(second.getText().toString());
first_amount = Double.parseDouble(first.getText().toString());
result = first_amount * second_amount;
second.setText("" + df.format(result));
after using BigDecimal
second_amount = Double.parseDouble();
bdf = new BigDecimal(second.getText().toString());
//first_amount = Double.parseDouble(first.getText().toString());
bds = new BigDecimal(second.getText().toString());
BigDecimal bdr = bdf.multiply(bds);
//result = first_amount * second_amount;
second.setText("" + bdr);
If you are doing something like currency calculations, where exact representation of short decimal fractions matters, it is best not to involve double at all. Pass the original string representation of the number directly to the BigDecimal constructor, and do your arithmetic in BigDecimal.
For example, new BigDecimal("0.1") has the value 0.1, but new BigDecimal(0.1) has the very slightly different value 0.1000000000000000055511151231257827021181583404541015625, due to rounding on the conversion of the literal to double.

Convert double to BigDecimal and set BigDecimal Precision

In Java, I want to take a double value and convert it to a BigDecimal and print out its String value to a certain precision.
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
double d=-.00012;
System.out.println(d+""); //This prints -1.2E-4
double c=47.48000;
BigDecimal b = new BigDecimal(c);
System.out.println(b.toString());
//This prints 47.47999999999999687361196265555918216705322265625
}
}
It prints this huge thing:
47.47999999999999687361196265555918216705322265625
and not
47.48
The reason I'm doing the BigDecimal conversion is sometimes the double value will contain a lot of decimal places (i.e. -.000012) and the when converting the double to a String will produce scientific notation -1.2E-4. I want to store the String value in non-scientific notation.
I want to have BigDecimal always have two units of precision like this: "47.48". Can BigDecimal restrict precision on conversion to string?
The reason of such behaviour is that the string that is printed is the exact value - probably not what you expected, but that's the real value stored in memory - it's just a limitation of floating point representation.
According to javadoc, BigDecimal(double val) constructor behaviour can be unexpected if you don't take into consideration this limitation:
The results of this constructor can be somewhat unpredictable. One
might assume that writing new BigDecimal(0.1) in Java creates a
BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with
a scale of 1), but it is actually equal to
0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that
matter, as a binary fraction of any finite length). Thus, the value
that is being passed in to the constructor is not exactly equal to
0.1, appearances notwithstanding.
So in your case, instead of using
double val = 77.48;
new BigDecimal(val);
use
BigDecimal.valueOf(val);
Value that is returned by BigDecimal.valueOf is equal to that resulting from invocation of Double.toString(double).
It prints 47.48000 if you use another MathContext:
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64);
Just pick the context you need.
You want to try String.format("%f", d), which will print your double in decimal notation. Don't use BigDecimal at all.
Regarding the precision issue: You are first storing 47.48 in the double c, then making a new BigDecimal from that double. The loss of precision is in assigning to c. You could do
BigDecimal b = new BigDecimal("47.48")
to avoid losing any precision.
Why not :
b = b.setScale(2, RoundingMode.HALF_UP);
It's printing out the actual, exact value of the double.
Double.toString(), which converts doubles to Strings, does not print the exact decimal value of the input -- if x is your double value, it prints out exactly enough digits that x is the closest double to the value it printed.
The point is that there is no such double as 47.48 exactly. Doubles store values as binary fractions, not as decimals, so it can't store exact decimal values. (That's what BigDecimal is for!)
The String.format syntax helps us convert doubles and BigDecimals to strings of whatever precision.
This java code:
double dennis = 0.00000008880000d;
System.out.println(dennis);
System.out.println(String.format("%.7f", dennis));
System.out.println(String.format("%.9f", new BigDecimal(dennis)));
System.out.println(String.format("%.19f", new BigDecimal(dennis)));
Prints:
8.88E-8
0.0000001
0.000000089
0.0000000888000000000
BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
In Java 9 the following is deprecated:
BigDecimal.valueOf(d).setScale(2, BigDecimal.ROUND_HALF_UP);
instead use:
BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
Example:
double d = 47.48111;
System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111
BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
System.out.println(bigDecimal); //Prints: 47.48

Truncating a Float Value Without Using SetRoundingMode()

I am truncating a float here.But my value is getting rounded.I do not want that.E.g If my value is 12.989 -> it should be printed as 12.98 only. Can someone help
I cannot use decimal format's SetRoundingMode because that is supported from java 1.6 only.
Mine is 1.5 JDK. CAn someone help me out without using SetRoundingMode() Method????
String pattern = "##,##0.00";
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat)nf;
double fPart;
Float value=233.989f;
String dstr = String.valueOf(value);
dstr = dstr.substring(dstr.indexOf(".")+1);
Long db = Long.valueOf(dstr);
if(db > 0){
df.applyPattern(pattern);
System.out.println("input="+value+", fPart="+dstr);
}
String output = df.format(value);
System.out.println(output);
You can always use old school trick, multiply by 10^n, truncate, divide by 10^n:
float x = 233.989f;
x = (float)(Math.floor(x * 100) / 100);
I've also experimented with BigDecimal:
MathContext mc = new MathContext(5, RoundingMode.FLOOR)
BigDecimal decimal = new BigDecimal(233.989, mc);
System.out.println(decimal);
It does the job but you have to specify total number of digits. You can't just say I want 2 decimal places and I don't care about digits left of decimal point. That's way first parameter of MathContext is 5, not 2. If you opt for this approach, you can quickly calculate non decimal digits with Math.Ceil(Math.log10(x)).
Note:
When dividing (first approach) at least one of operands must be floating point (float or double)
When working with strings (you code), it's not safe to presume that '.' is decimal separator
Truncating decimals with Math.floor only works for positive values
Not sure If I understood you problem correclty. But If you want to truncate without rounding up or down, you can use just like
DecimalFormat df = new DecimalFormat("##.##");
df.format(12.912385);
You can use regular expressions to get the second digit after "." and then subtract the string from the beginning to that position and then transform the string into a float or double.
Pattern pattern = Pattern.compile("regular expression");
Matcher matcher = pattern.matcher("your string");
if(matcher.find())
{
int poz_begin = matcher.start();
int poz_end = matcher.end();
}

Categories

Resources