What is decimal format exactly doing? - java

This is my code:
float result=(float) ( (new Float(result1)*0.3)+(new Float(result2)*0.7));
String a=dec.format(result);
vprosvasis.setText(a);
If I use vprosvasis somewhere else in my app, it will have the price a.
For example, if my result is 12,34, a will be 12,3 so vprosvasis will be 12,3 if I write
float genikosvathmos = ((new Float(vprosvasis.getText().toString()) +
new Float(vprosvasis2.getText().toString()) +
new Float(vprosvasis3.getText().toString()) +
new Float(vprosvasis4.getText().toString()) +
new Float(vprosvasis5.getText().toString()) +
new Float(vprosvasis6.getText().toString())) / 6);

Would suggest using primitives (specifically, double) rather than Object wrappers (unless you have some need that you're not showing here).
Then look at the Double javadoc, especially the static utility methods:
http://download.oracle.com/javase/6/docs/api/java/lang/Double.html
double myDouble = Double.parseDouble(myString);
String s = Double.toString(myDouble);

The purpose of DecimalFormat is to format numbers as text in a locale-specific way. (It can also be used to parse a locale-specific number format to a suitable Number type.) For example, in the American English locale, a period ('.') is used as a decimal point, rather than a comma (',').
It is important to note that the String produced by a DecimalFormat is very likely to be incompatible with the format required for the Float(String) constructor. The string format consumed by Float is not locale-specific; it is a fixed format that is the same as that specified by the Java Language Specification for float literals in Java source code.
If you are doing calculations with money, don't use a floating-point type like float or double. Use instances of java.math.BigDecimal instead. This type performs exact arithmetic, and when rounding is performed, you can control the rounding to conform with your accounting practices.

Like Daniel, I'm not quite sure what you're trying to get from this post. But I will answer the question you asked in your title at face value.
You don't include the code where dec is declared, or any code where it's operated on, but from context it seems to be an instance of the DecimalFormat class. If so, it's taking result, which is a float, and doing the following things:
widening it to long
using the method format(double number) inherited from NumberFormat to get the String representation of result
storing the result in a

Related

Java initialize doubles from floats [duplicate]

I have a primitive float and I need as a primitive double. Simply casting the float to double gives me weird extra precision. For example:
float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375
However, if instead of casting, I output the float as a string, and parse the string as a double, I get what I want:
System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35
Is there a better way than to go to String and back?
It's not that you're actually getting extra precision - it's that the float didn't accurately represent the number you were aiming for originally. The double is representing the original float accurately; toString is showing the "extra" data which was already present.
For example (and these numbers aren't right, I'm just making things up) suppose you had:
float f = 0.1F;
double d = f;
Then the value of f might be exactly 0.100000234523. d will have exactly the same value, but when you convert it to a string it will "trust" that it's accurate to a higher precision, so won't round off as early, and you'll see the "extra digits" which were already there, but hidden from you.
When you convert to a string and back, you're ending up with a double value which is closer to the string value than the original float was - but that's only good if you really believe that the string value is what you really wanted.
Are you sure that float/double are the appropriate types to use here instead of BigDecimal? If you're trying to use numbers which have precise decimal values (e.g. money), then BigDecimal is a more appropriate type IMO.
I find converting to the binary representation easier to grasp this problem.
float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;
System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));
You can see the float is expanded to the double by adding 0s to the end, but that the double representation of 0.27 is 'more accurate', hence the problem.
111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000
This is due the contract of Float.toString(float), which says in part:
How many digits must be printed for
the fractional part […]? There
must be at least one digit to
represent the fractional part, and
beyond that as many, but only as many,
more digits as are needed to uniquely
distinguish the argument value from
adjacent values of type float. That
is, suppose that x is the exact
mathematical value represented by the
decimal representation produced by
this method for a finite nonzero
argument f. Then f must be the float
value nearest to x; or, if two float
values are equally close to x, then f
must be one of them and the least
significant bit of the significand of
f must be 0.
I've encountered this issue today and could not use refactor to BigDecimal, because the project is really huge. However I found solution using
Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()
And this works.
Note that calling result.doubleValue() returns 5623.22998046875
But calling doubleResult.doubleValue() returns correctly 5623.23
But I am not entirely sure if its a correct solution.
I found the following solution:
public static Double getFloatAsDouble(Float fValue) {
return Double.valueOf(fValue.toString());
}
If you use float and double instead of Float and Double use the following:
public static double getFloatAsDouble(float value) {
return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}
Use a BigDecimal instead of float/double. There are a lot of numbers which can't be represented as binary floating point (for example, 0.1). So you either must always round the result to a known precision or use BigDecimal.
See http://en.wikipedia.org/wiki/Floating_point for more information.
Floats, by nature, are imprecise and always have neat rounding "issues". If precision is important then you might consider refactoring your application to use Decimal or BigDecimal.
Yes, floats are computationally faster than decimals because of the on processor support. However, do you want fast or accurate?
A simple solution that works well, is to parse the double from the string representation of the float:
double val = Double.valueOf(String.valueOf(yourFloat));
Not super efficient, but it works!
For information this comes under Item 48 - Avoid float and double when exact values are required, of Effective Java 2nd edition by Joshua Bloch. This book is jam packed with good stuff and definitely worth a look.
Does this work?
float flt = 145.664454;
Double dbl = 0.0;
dbl += flt;
There is a way to convert Float value into Double without adding the extra precision
Float aFloat= new Float(0.11);
String s = aFloat.toString();
Double aDouble = Double.parseDouble(s);
This Approach will not add an extra precisions to your Float value while converting. The only Problem with this approach is memory usage of the JVM by creating an extra tamp String object.
When calling an toString() (aDouble.toString()) on Double will never add an extra precisions. The precisions will be added while type conversion.

How to convert String to BigInteger when var contains ".0"

I've got a String variable that may contain a number such "2015.0".
When I try to convert it to int with
int i = Integer.parseInt(myVar)
or BigInteger with
BigInteger bi = new BigInteger(myVar)
I get the error
java.lang.NumberFormatException: For input string: "2015.0"
How can I achieve a correct cast?
Thanks!
You can parse it as a BigDecimal and then convert to BigInteger
BigInteger bi = new BigDecimal("2015.0").toBigInteger()
Just note that you may lose precision information when doing this:
...any fractional part of this BigDecimal will be discarded. Note that this conversion can lose information about the precision of the BigDecimal value.
To have an exception thrown if the conversion is inexact (in other words if a nonzero fractional part is discarded), use the toBigIntegerExact() method.
As suggested in the quoted javadocs, use toBigIntegerExact() to prevent accidental losses of precision such as the one that would result from converting "2.5" to BigInteger (thanks to Ole V.V.'s comment for this remark).
You can also just parse it to a double and then drop the decimal part by casting it to int
int i = (int) Double.parseDouble(myVar);
You can't convert a float to a BigInteger, and your string has a decimal point, so it's automatically considered to be a float. You have a couple of options, but the easiest might be to strip off the decimal portion from the string to get "2015", and then use that to construct your BigInteger.
That's assuming that the decimal portion of the number doesn't matter, of course. If it does, consider using BigDecimal, instead.

String.format(%.2f,double) works only in half of the tests

I am trying to format double values, so it they would have only 2 decimal spaces:
remainingAmount = Double.parseDouble(String.format("%.2f",remainingAmount - calculatePrincipalPayment()));
As you can see, this code formats double value remainingAmount - calculatePrincipalPayment() using String.format(), then transfers it from String to Double and assigns it to the double variable remainingAmount (which was declared). remainingAmount is double and calculatePrincipalPayment() returns double.
The problem is that it formats only part of the values, for example it can return 401.37 (which is the required formatting) as well as 403.71999999999997.
I also already tried to do formatting by using DecimalFormat df = new DecimalFormat("#.##").
A double (or its boxed counterpart Double) has no capacity to store a specific format to be used when rendering as a String. It is just a raw value.
I suspect you believe that a double value obtained by parsing from a specific format somehow retains that format. This is not the case.
Floating point types are imprecise; not all values can be accurately stored. In cases where the exact value cannot be stored, the closest storable value is used - as is the case with some of your results.

NumberFormat doesn't like more than 340 decimal places

I want to format a double with a certain number of decimal places in Java. My code currently looks like this:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(decimalPlaces);
format.setMaximumFractionDigits(decimalPlaces);
format.setGroupingUsed(false);
String s = format.format(value);
but when decimalPlaces is more than 340, this method just prints 340 digits and ignores the rest. Is there a way to work around this limitation?
Specifically in my case they're all 0s (and probably would be with any number after a certain point since the precision is not that high) but it seems wrong to me that the function just silently ignores what I want instead of throwing an exception or something.
Yes, I'm aware that a double can't actually hold that many decimal places, but it's also true that an int can't hold any decimal places at all yet I'm able to print it with some.
The documentation of setMinimumFractionDigits contains this statement:
The concrete subclass may enforce an upper limit to this value appropriate to the numeric type being formatted.
Most likely the subclass returned by NumberFormat.getInstance is DecimalFormat, which tells us in the JavaDocs
For formatting numbers other than BigInteger and BigDecimal objects, the lower of newValue and 340 is used. Negative input values are replaced with 0.
So to solve your problem, convert your number to a BigDecimal before formatting it.
In case of double the value is getting truncating. Use/declare value as BigDecimal
Try this sample code:
final NumberFormat format = NumberFormat.getInstance();
format.setMinimumFractionDigits(355);
format.setMaximumFractionDigits(400);
format.setGroupingUsed(false);
System.out.println(format.getMinimumFractionDigits());
BigDecimal bd=new BigDecimal(10L);
String s = format.format(bd);
System.out.println(s.length());
System.out.println(s);

Converting string to double always gives me wrong representation

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.

Categories

Resources