How to convert from float to bigDecimal in java?
BigDecimal value = new BigDecimal(Float.toString(123.4f));
From the javadocs, the string constructor is generally the preferred way to convert a float into a BigDecimal, as it doesn't suffer from the unpredictability of the BigDecimal(double) constructor.
Quote from the docs:
Note: For values other float and double NaN and ±Infinity, this constructor is compatible with the values returned by Float.toString(float) and Double.toString(double). 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.
float f = 45.6f;
BigDecimal bd = BigDecimal.valueOf(f);
Quote from documentations:
Note: This is generally the preferred way to convert a double (or
float) into a BigDecimal, as the value returned is equal to that
resulting from constructing a BigDecimal from the result of using
Double.toString(double).
Reference: BigDecimal (Java Platform SE 6)
For a precision of 3 digits after the decimal point:
BigDecimal value = new BigDecimal(f,
new MathContext(3, RoundingMode.HALF_EVEN));
This is upto my knowledge :
public static BigDecimal floatToBigDecimal(Float a){
if(a == null || a.isInfinite() || a.isNaN()){
return BigDecimal.ZERO;
}
try{
return BigDecimal.valueOf(a);
}catch(Exception e){
return BigDecimal.ZERO;
}
}
*Note:This is generally the preferred way to convert a double (or float) into a BigDecimal, as the value returned is equal to that resulting from constructing a BigDecimal from the result of using Double.toString(double).
public static BigDecimal valueOf(double val)
Parameters:
val - double to convert to a BigDecimal.
Returns:
a BigDecimal whose value is equal to or approximately equal to the value of val.
Throws:
NumberFormatException - if val is infinite or NaN.
Since:
1.5
I have checked whether Infinite or Not a Number, so that there is less chances of NumberFormatException
Related
I am facing an issue related to converting double to float. Actually, I store a float type, 23423424666767, in a database, but when we get data from the database in the below code, getInfoValueNumeric(), it's of double type. The value we get is in the 2.3423424666767E13 form.
So how do we get a float format data like 23423424666767?
2.3423424666767E13 to 23423424666767
public void setInfoValueNumeric(java.lang.Double value) {
setValue(4, value);
}
#javax.persistence.Column(name = "InfoValueNumeric", precision = 53)
public java.lang.Double getInfoValueNumeric() {
return (java.lang.Double) getValue(4);
}
Just cast your double to a float.
double d = getInfoValueNumeric();
float f = (float)d;
Also notice that the primitive types can NOT store an infinite set of numbers:
float range: from 1.40129846432481707e-45 to 3.40282346638528860e+38
double range: from 1.7e–308 to 1.7e+308
I suggest you to retrieve the value stored into the Database as BigDecimal type:
BigDecimal number = new BigDecimal("2.3423424666767E13");
int myInt = number.intValue();
double myDouble = number.doubleValue();
// your purpose
float myFloat = number.floatValue();
BigDecimal provide you a lot of functionalities.
Convert Double to Float
public static Float convertToFloat(Double doubleValue) {
return doubleValue == null ? null : doubleValue.floatValue();
}
Convert double to Float
public static Float convertToFloat(double doubleValue) {
return (float) doubleValue;
}
This is a nice way to do it:
Double d = 0.5;
float f = d.floatValue();
if you have d as a primitive type just add one line:
double d = 0.5;
Double D = Double.valueOf(d);
float f = D.floatValue();
Converting from double to float will be a narrowing conversion. From the doc:
A narrowing primitive conversion may lose information about the
overall magnitude of a numeric value and may also lose precision and
range.
A narrowing primitive conversion from double to float is governed by
the IEEE 754 rounding rules (§4.2.4). This conversion can lose
precision, but also lose range, resulting in a float zero from a
nonzero double and a float infinity from a finite double. A double NaN
is converted to a float NaN and a double infinity is converted to the
same-signed float infinity.
So it is not a good idea. If you still want it you can do it like:
double d = 3.0;
float f = (float) d;
To answer your query on "How to convert 2.3423424666767E13 to
23423424666767"
You can use a decimal formatter for formatting decimal numbers.
double d = 2.3423424666767E13;
DecimalFormat decimalFormat = new DecimalFormat("#");
System.out.println(decimalFormat.format(d));
Output : 23423424666767
The problem is, your value cannot be stored accurately in single precision floating point type. Proof:
public class test{
public static void main(String[] args){
Float a = Float.valueOf("23423424666767");
System.out.printf("%f\n", a); //23423424135168,000000
System.out.println(a); //2.34234241E13
}
}
Another thing is: you don't get "2.3423424666767E13", it's just the visual representation of the number stored in memory. "How you print out" and "what is in memory" are two distinct things. Example above shows you how to print the number as float, which avoids scientific notation you were getting.
First of all, the fact that the value in the database is a float does not mean that it also fits in a Java float. Float is short for floating point, and floating point types of various precisions exist. Java types float and double are both floating point types of different precision. In a database both are called FLOAT. Since double has a higher precision than float, it probably is a better idea not to cast your value to a float, because you might lose precision.
You might also use BigDecimal, which represent an arbitrary-precision number.
Use dataType casting. For example:
// converting from double to float:
double someValue;
// cast someValue to float!
float newValue = (float)someValue;
Cheers!
Note:
Integers are whole numbers, e.g. 10, 400, or -5.
Floating point numbers (floats) have decimal points and decimal places, for example 12.5, and 56.7786543.
Doubles are a specific type of floating point number that have greater precision than standard floating point numbers (meaning that they are accurate to a greater number of decimal places).
Float.parseFloat(String.valueOf(your_number)
I'm trying to create a BigDecimal class that has always a fixed maximum fractions count.
But when printing that number, it is not cut to the fractions I defined in scale. Why?
class MyDecimal extends BigDecimal {
public MyDecimal(double val) {
super(val);
setScale(4, RoundingMode.HALF_UP);
}
}
Sysout(new MyDecimal(0.0001));
//0.000100000000000000008180305391403130954586231382563710212707519531254
BigDecimal is immutable, and should not be extended. setScale() does not modify the BigDecimal instance. It returns a copy of the BigDecimal instance with the scale modified (as every other "mutating" method of BigDecimal, since it's immutable). Calling it and ignoring the returned value is thus useless.
Instead of extending BigDecimal, create a factory method:
public static BigDecimal createWithScale4(double d) {
BigDecimal temp = new BigDecimal(d);
return temp.setScale(4);
}
The problem is that you are putting in your input as a double. This is from the javadoc:
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
Since you are using a double, it is being stored as a floating-point number, and not as a precision number. It then converts that non-precision floating-point number to a precision BigDecimal, which then puts it out as a precise number. It works if the input is a String, however, since a String is just text, and converts the string directly to a BigDecimal. See this from here:
Creating a big decimal from a (scalar) double is simple:
bd = new BigDecimal(1.0);
To get a BigDecimal from a Double, get its
doubleValue() first.
However it is a good idea to use the string constructor:
bd = new BigDecimal("1.5");
If you don't, then you'll get the following,
bd = new BigDecimal(1.5);
bd.toString(); // => 0.1499999999999999944488848768742172978818416595458984375
So do it like this:
Sysout(new MyDecimal("0.0001"));
Also, as #JBNizet points out, you're extending an immutable object, a BigDecimal. You're ignoring the return value of setting the scale. This could be changed by using a method such as the one below:
public static BigDecimal createBigDecimal(String s) {
BigDecimal bigdeci = new BigDecimal(s);
return bigdeci.setScale(4);
}
The problem is that you're passing the argument as a double instead of as a string. Before the argument reaches the Big Decimal, it has already been converted into binary form to store as a double, which introduces a tiny error (it's equivalent to trying to write 1/3 as a decimal and getting 0.3333333333; it won't be quite right unless you have infinite precision).
Instead, try:
Sysout((new BigDecimal("0.0001")).setScale(4,RoundingMode.HALF_UP));
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
I wanted to see if anyone can explain why the following code works with valueOf but not others.
import java.math.BigDecimal;
public class Change {
public static void main(String args[]) {
double a = 4.00d;
double b = 3.10d;
BigDecimal a1 = new BigDecimal(a);
BigDecimal b1 = new BigDecimal(b);
BigDecimal diff = a1.subtract(b1);
System.out.println("Double difference");
System.out.println(diff);
float c = 4.00f;
float d = 3.10f;
BigDecimal a2 = new BigDecimal(c);
BigDecimal b2 = new BigDecimal(d);
BigDecimal diff2 = a2.subtract(b2);
System.out.println("Float difference");
System.out.println(diff2);
System.out.println("Valueof Difference");
System.out.println(BigDecimal.valueOf(4.00).subtract(BigDecimal.valueOf(3.10)));
}
}
The output looks like:
>java Change
Double difference
0.899999999999999911182158029987476766109466552734375
Float difference
0.900000095367431640625
Valueof Difference
0.9
My question is: What does valueOf() do to get the precision?
Is there any other way of getting the correct result without rounding off to the 2 digits manually?
thanks,
Looking at the source code for BigDecimal, it does:
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
From its JavaDoc:
Translates a double into a BigDecimal,
using the double's canonical string
representation provided by the
Double.toString(double) method.
Note: This is generally the preferred way to
convert a double (or float) into a
BigDecimal, as the value returned is
equal to that resulting from
constructing a BigDecimal from the
result of using
Double.toString(double).
Because of floating-point representation, a double value is not exactly what you set it as. However, during String representation, it rounds off what it displays. (All of the rules are on it's JavaDoc).
Furthermore, because of this rounding, if you did:
BigDecimal d = BigDecimal.valueOf(4.00000000000000000000000000000000001));
you would get the wrong value. (d == 4.0)
So, it's pretty much always better to initialize these with strings.
BigDecimal.valueOf(double) first does a conversion from double to String, then String to BigDecimal.
In the first case, you're starting with a double or float, converting to BigDecimal, calculating the difference. In the second case, you're starting with double or float, converting to a String, then converting to BigDecimal, then calculating the difference.
From the Javadocs:
public static BigDecimal valueOf(double val)
Translates a double into a BigDecimal,
using the double's canonical string
representation provided by the
Double.toString(double) method. Note:
This is generally the preferred way to
convert a double (or float) into a
BigDecimal, as the value returned is
equal to that resulting from
constructing a BigDecimal from the
result of using
Double.toString(double).
I think this answers both of your questions.
Cheers,
The valueOf works because it calls Double.toString. from the Javadoc:
public static BigDecimal valueOf(double val)
Translates a double into a BigDecimal, using the double's
canonical string representation
provided by the
Double.toString(double) method.
When you pass a double into the BigDecimal constructor, the constructor takes the floating-point value and reproduces it exactly. The toString code finds an approximation for the floating point value.
In case you didn't notice, using System.out.println() to show a floating point number doesn't show the same results as if you wrap the floating point number in a BigDecimal first (using the BigDecimal constructor that takes a double).
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.