0

I have the following code ""+((Double) cellValue).longValue()+" "+ cellValue

Cell value is 6.2284800183620495E18 The output I get is...

Now I am no expert but I use this it outputs 6228480018362050000 which I would expect but Java gives me...

6228480018362049536 6.2284800183620495E18 6.2284800183620495E18

Why is it 6228480018362049536 and not 6228480018362050000 and how can I get the real number?

I am using Java8

Jackie
  • 21,969
  • 32
  • 147
  • 289
  • 1
    Try using BigDecimal see what that gives you. Double are approximate values not actual ones. The reason that the tool you used and java give you different numbers is they handle floating point numbers in different ways. – BevynQ Dec 08 '16 at 21:28
  • 3
    Possible duplicate of [Why Are Floating Point Numbers Inaccurate?](http://stackoverflow.com/questions/21895756/why-are-floating-point-numbers-inaccurate) I recommending search and reading "What Every Computer Scientist Should Know About Floating-Point Arithmetic" – Zong Dec 08 '16 at 21:28
  • 2
    Your title is nonsense. Doubles aren't 'in scientific notation'. You are getting scientific notation *when converting to String*. – user207421 Dec 08 '16 at 21:32
  • @EJP does that help? – Jackie Dec 08 '16 at 23:54

2 Answers2

3

Floating point

The float, Float, double, and Double types all use floating point technology. This technology trades away accuracy to get speed-of-execution. This technology also has limits when handling very large or very small numbers.

BigDecimal

For accurate numbers, or for very large/small numbers, use the BigDecimal class (or its whole number cousin, BigInteger class). Very slow in execution when compared to floating point, but accurate and with much vaster size limits. This pair of classes is one of the best things about Java, a major advantage over other development environments lacking an arbitrary precision arithmetic facility.

The BigDecimal class supports:

Example code.

String input = "6.2284800183620495E18" ;
BigDecimal bd = new BigDecimal( input );

bd.toString(): 6.2284800183620495E+18

bd.toEngineeringString(): 6.2284800183620495E+18

bd.toPlainString(): 6228480018362049500

See live code in IdeOne.com.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Having used Python, Lisp and C++, all of which allow arbitrary precision to use the same arithmetic operators as built-in numbers, 'a major advantage over other development environments.' is not how I'd describe BigDecimal. It's adequate, but far less usable. – Pete Kirkham Dec 08 '16 at 23:03
  • @PeteKirkham I added a qualifier to my statement; thanks. Some development environments lack any such feature. – Basil Bourque Dec 08 '16 at 23:14
  • So assuming this goes through a framework or library is there any way to convert it back once that accuracy has been lost using floating point? – Jackie Dec 08 '16 at 23:56
  • Per your suggestion I tried... `new BigDecimal(cellValue.toString()).toBigInteger()` and the response I got was `6228480018362049500` where are the last 2 zeros? Should I open another question? – Jackie Dec 09 '16 at 00:03
  • @Jackie You never explained what is `cellValue`, so how can we advise you? Edit your Question to provide all relevant details. But in short, avoid the floating point types; stick with String and BigDecimal. Lastly, what extra zeros? You have 16 decimal places with a scientific notation of `+18`, which means a pair of zeros on the end of a plain number: `6228480018362049500`. Is that not correct? – Basil Bourque Dec 09 '16 at 00:34
1

The double precision number which prints as 6.2284800183620495E18 has the representation of 0x43D59C0064EA45A9 = 01000011 11010101 10011100 00000000 01100100 11101010 01000101 10101001

(play with this converter)

This means it is 1.0101100111000000000001100100111010100100010110101001₂ * 2 to the power of 10000111101₂ - 1023₁₀ (see wikipedia for how it works) which works out as 6082500017931689 * 1024 = 6228480018362049536 which is the answer you get.

So the answer given by the conversion to long is correct - 6228480018362049536 is the decimal representation of a 64 bit integer value equivalent to the given double precision value.

Which raises the question of why is the decimal representation of the number is given as 6.2284800183620495E18?

This is because each floating point value represents not a point on the number line, but a range - a one-bit change ( called a unit in the last place ) will change the value by 1024. The numbers from 6228480018362049536-512 to 6228480018362049536+511 all correspond to this same double precision value. Java picks the value with the least number of digits to print which falls into this range and no other - 6228480018362049000 - and writes it as scientific notation as 6.228480018362049E18.

If you don't want the approximations, follow Basil Bourque's advise to use arbitrary precision, or (if your use case allows it ) use a fixed point or integer representation based on long.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171