File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Java in General and the fly likes What actual Double.toString(double d) does? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Soft Skills this week in the Jobs Discussion forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "What actual Double.toString(double d) does?" Watch "What actual Double.toString(double d) does?" New topic
Author

What actual Double.toString(double d) does?

Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
Hi, folks.

I'm amazed about Double.toString(double d)
at first it prints maximum 20 characters
at second if I write
d = 1231230.10000203093000002876;
System.out.println("Double.toString(d) " + Double.toString(d));
output is "Double.toString(d) 1231230.1000020308"
but if I write
d = 1231230.10000203003000002876;
System.out.println("Double.toString(d) " + Double.toString(d));
output is "Double.toString(d) 1231230.1000020301"

Black magic isn't it? Didn't found any explaination of this in javadoc. Clear minds, please explain.

P.S. I use jdk 1.6.0_12.

Thank you.
Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 19059
    
  40

Black magic isn't it?


I'm not sure what "black magic" you are referring to here. It just looks like you are trying to assign a double with more precision than it is capable of holding, and it got lost. I bet you would get similar results just by printing the double -- you don't need to convert it to a string first.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
Try converting it to a BigDecimal, then you can see how many decimal places of imprecision you have got

There is something more helpful in our FAQ (look at no 20).
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
well, maybe another question.

All this happens because I had this:

double d = 0.1
BigDecimal(d);

which was return not 0.1 in BigDecimal

and then I wondered, why

BigDecimal(Double.toString(d))

works perfectly. I mean that
Double.toString(d) returns "0.1"
but actual value of d is 0.1000000000000000055511151231257827021181583404541015625
what I'm trying to say is that just before the place where non-zero value happens, toString() truncates the remainder part.

I just, don't understand the logic of all this happenings.

Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
well, what exactly I'm trying to ask is that absolutely safe to write the code like

double d;
//d = 0.1; (e.g) setting value to d
BigDecimal bd = new BigDecimal(Double.toString(d));

instead of writing

double d;
//d = 0.1; (e.g) setting value to d
BigDecimal bd = new BigDecimal(d);
bd = bd.setScale(5, BigDecimal.ROUND_DOWN); // rounding and scale exact values are set here only for example


And if I can use first method without cautions, why?

Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
None of those methods looks reliable. Try new BigDecimal("0.1"); Did you find the FAQ link I quoted earlier?
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
yes, I mean, that the value is passed to this method. I can't just write "0.1", because value could be 1, 2, 3, 1.2, or any other.
salvin francis
Ranch Hand

Joined: Jan 12, 2009
Posts: 928

Its Black magic.

Extreme dark, most wizards will never ever dare to reveal.

In thy simplest of thee terms. you tried to fit an elephant into a matchbox, and in doing so,
thou hadth wispered the witch's charm. This turned the elephant into a tiny mouse.

hence when you opened thee matchbox to reveal the elephant, you happened to find a mouse.

d >> elephant
Double.toString(d) >> witch's charm ( never utter it loud )
1231230.1000020301 >> mouse

I hope in thy quest for knowledge, thou have gained the meaning of the above ..


My Website: [Salvin.in] Cool your mind:[Salvin.in/painting] My Sally:[Salvin.in/sally]
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
well, actually, I red many faqs about that, not exactly that what you're pointed to.
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
Campbell Ritchie wrote:None of those methods looks reliable. Try new BigDecimal("0.1"); Did you find the FAQ link I quoted earlier?

actually, third link in 20th faq section is broken.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
You should know by now that any floating-point values carry the risk of slight imprecision; when you use Double#toString or the BigDecimal constructor, you can demonstrate those imprecisions. That is why you get values ending with 99999.... or 0000.... You always risk getting those imprecisions. The only way to avoid them is to stick to integer arithmethic and BigDecimal, never using double or float at all. In fact, of those values you quoted, you can probably get 1, 2, 3 represented exactly in a double, never 1.2, but 1.25, 1.125 and 1.5 will probably show correctly too.

Doubles are designed for engineers. When I was an undergraduate they joked that an engineer is somebody whom you ask what 2 times 2 means. He gets his slide rule out, works it out, says, "3.99 . . . oh, that's 4 near as makes no difference."
And mention of slide rules dates me. So people who don't mind there being no difference between 3.99 and 4 can happily use floating-point arithmetic. Anybody who expects 4 and isn't happy with 4.000000000000045935098395 or 3.999999999999998374659120375 must avoid doubles and floats.

And take no notice of people writing about black magic
salvin francis
Ranch Hand

Joined: Jan 12, 2009
Posts: 928

Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
The nearest I can find to the broken link is this search on the IBM website. Try results nos 4 5 6 and 7.

Unless you are rounding, you cannot expect a nice simple fractional number from doubles or floats. The BigDecimal simply shows the errors more clearly. If you go through your Java installation folder, you will find a file called src.zip. Unzip that, find the java folder, the lang folder, the Double.java file, and inspect that with a text editor. That will show you how the toString method is written, but I suspect it won't show you what you want to know.
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
well, probably, I'm lack of very basic knowledge of all this numbers to build solid knowledge basis about how all this works in java and how to use the meanings that java provide to operate on them. If someone advise me what I shall read (from very simple to complex, preferably), I'll be very appreciate.
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
what I found that I think I can rely on, is to use BigDecimal.ROUND_HALF_UP, when I know exactly what number of decimal points I should provide.

d = 1.19;
dc = new BigDecimal(d);
dc = dc.setScale(5, BigDecimal.ROUND_HALF_UP);

(here, I know, that I should guarantee 5 dp precision).

Thanks.
Ulf Dittmer
Marshal

Joined: Mar 22, 2005
Posts: 42908
    
  69
Gasan Gouseinov wrote:actually, third link in 20th faq section is broken.

The link has been fixed.
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
new BigDecimal(123456789012.3456789).setScale(5, BigDecimal.ROUND_HALF_UP)?
new BigDecimal("123456789012.3456789").setScale(5, BigDecimal.ROUND_HALF_UP)?

That won't guarantee 5 places' precision. Try it. You will very probably get 5 places' precision if you confine your values to a small range, but it is by no means guaranteed.
Gasan Guseynov
Ranch Hand

Joined: Jan 03, 2006
Posts: 67
you're right. Just can't understand it. It's seems to be too complex to understand by an ordinary mind. But luckily I have a small numers (or I don't but want to believe that I do
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40028
    
  28
There's nothing complicated about it. A double is usually precise to 15 significant figures (sig-fig), may be precise at 16 sig-fig, and is definitely imprecise at 17 sig-fig. All I did was provide a number which even when scaled to 5 decimal places had 17 significant figures in. So an error was bound to occur.
The String constructor for BigDecimal can take any value entered, even millions of digits.

You are trying to represent 0/1 (1 / 10) in terms of ½ 1/4 1/8 1/16 etc etc. Try as you will, you will never get an exact representation. Like working out 1 / 3 in decimal. It is 0.3, 0.33, 0.333, 0.3333, 0.33333, 0.33333333333333333333333333333333333333333333333333333333333333333, but all those figures differ from the true value of 1 / 3. When you pass the double value 0.1 to the BigDecimal constructor, it can accurately translate the ½ 1/4 1/8 etc to decimal, which has an error of ...55511151231257827021181583404541015625 in. If you take that error and keep doubling it you eventually get to 0.1.

Try thisPass 0.1 as a command-line argument, multiply the error by 10, and you find that after 54 doublings, you get to 1: that means the error beginning with 555 is 0.1*2^-54. Remember a double has effectively 53 bits' precision. So that is 1/10 of ½ bit at the very last position. If you pass a small whole number, eg 1, you find no error at all, and there is no error for 0.75 because ¾ can be exactly represented in binary (0.11b).

And thank you for fixing the link, Ulf.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: What actual Double.toString(double d) does?