Mansi
Mansi

Reputation: 1949

Android - avoid exponential in string to double conversion

I trying to get value from edittext and stored as string. Then it converts to double. While converting up to 7 characters functioning normally but if i try to add more than 7 result is 1.23456789E8. Here is my code

String value = txtData.txtSearch.getText().toString();
// value = "987654321.45"

double amount1 = Double.parseDouble(value);
// amount1 = 9.8765432145E8

double amount2 = 0.05;

double result = (amount1 * amount2) / 100;
// result = 4.3827160725E14

after calculation i got 4.3827160725E14 which is not correct correct answer is 493827.16

How can i get correct value without losing precision?

Upvotes: 4

Views: 3345

Answers (5)

mehmetdelikaya
mehmetdelikaya

Reputation: 109

if anyone is looking for vice versa, if you first convert to BigDecimal and then PlainString. By doing that you keep your expected double. e.g.

val yourDouble = -6.9452331E-4 

val bigDecimal = yourDouble.toBigDecimal()
//bigDecimal = -0.00069452331

val stringDecimal = bigDecimal.toPlainString()
//stringDecimal = "-0.00069452331"

Upvotes: 0

Stephen C
Stephen C

Reputation: 718936

How do you avoid exponential in string to double conversion?

I think we are all missing the point here.

Here is your example:

// value = "987654321.45"

double amount1 = Double.parseDouble(value);
// amount1 = 9.8765432145E8

Presumably, the stuff in comments was printed; e.g. using a debugger or calls to println.

So why are you seeing exponential / scientific notation?

Well it is NOT due to the way that the string was parsed to a double. It is actually happening when the double is converted back to a string in order to print it. Example:

$ cat Test.java
import java.text.DecimalFormat;

public class Test {
    public static void main(String[] args) {
        String value = "987654321.45";
        double amount = Double.parseDouble(value);
        System.out.println(amount);
        DecimalFormat format = new DecimalFormat("0.########");
        System.out.println(format.format(amount));
    }
}
$ java Test
9.8765432145E8
987654321.45

See? I started with "987654321.45", converted it to a double. Then printed it two different ways. And got two different string representations for the same double value


So why does println(double) print the number like that?

Well ...

  1. System.out is a PrintStream
  2. println(double) is equivalent to print(double) followed by println()
  3. print(double) converts the double to a String using String.valueOf(double)
  4. valueOf(double) returns the same representation as Double.toString(double)
  5. toString(double) is specified to use scientific notation if the magnitude of the number is less than 10-3 or greater or equal to 107.

This is all specified in the respective javadocs. The most salient is the javadoc for toString(double).


If you don't believe me, you can check the Java Language Specification, and the IEE 754 Standard for floating point representations; see Wikipedia.

If you want to, you can even use Double.doubleToRawLongBits(double) to examine the bit representation of a double value.


Finally

After calculation i got 4.3827160725E14 which is not correct correct answer is 493827.16.

When I repeat that calculation I get the answer 493827.1607250001 ... using System.out.println(double). (Note that there is no scientific notation ... because the number is less than 107. )

The exact answer for the calculation (1987654321.45 * 0.05) / 100 493827.160725. The difference between the the exact answer and what Java gives us is caused by computer floating point rounding error . It happens because the IEE 754 representation is actually binary representation with a binary mantissa and a binary exponent, and because the mantissa has a fixed number of binary digits of precision.

This rounding error is inherent to calculations using IEE 754 representations. If you want to mitigate it, you can use BigDecimal to represent your numbers. But you should be aware that even BigDecimal is not precise:

  • You can't represent Pi or any other irrational number precisely using BigDecimal.

  • Many rational numbers don't have a precise representation as a BigDecimal; e.g. the value of 1.0 / 3.0.

So you still (in theory) need to be concerned with rounding errors with BigDecimal.

Upvotes: 0

Mansi
Mansi

Reputation: 1949

I solved it. i use BigDecimal instead of double now my code is

String value = txtData.txtSearch.getText().toString();
// value = "987654321.45"

BigDecimal amount1 = new BigDecimal(value);
// amount1 = "987654321.45"

BigDecimal amount2 = new BigDecimal(0.05);

BigDecimal result = (amount1.multiply(amount2)).divide(new BigDecimal(100));
result = result.setScale(2, RoundingMode.FLOOR);
// result = 493827.16

Upvotes: 3

arianoo
arianoo

Reputation: 667

try this:

double result = (amount1 * amount2) / 100.0;
string resultInMyFormat =  new DecimalFormat("#.#").format(result);

Upvotes: 0

GreyBeardedGeek
GreyBeardedGeek

Reputation: 30088

The following code gives your expected result:

public class DoubleTest {
 public static void main(String[] args) {
      double amount1 = Double.parseDouble("987654321.45");
      double amount2 = 0.05;
      double result = (amount1 * amount2) / 100;
      System.out.println(result);
 }
}

So, are you sure that you're getting the value that you think you are from txtData.txtSearch.getText().toString(); ?

By the way, if you're really interested in arbitrary precision (e.g. when dealing with money), use BigDecimal.

Upvotes: 0

Related Questions