all groups > dotnet clr > may 2005 >
You're in the

dotnet clr

group:

Double.ToString round-trip: "R" vs. "G17"


Double.ToString round-trip: "R" vs. "G17" Jason Frank
5/25/2005 1:38:44 PM
dotnet clr: One aspect of an application I'm working on requires doubles to be sent to a
browser in XML, and therefore the doubles have to be represented as strings.
We also need to be able to take the XML back from the browser and parse the
doubles, and have them turn into the "same" double as before it was sent to
the browser. So we're using the double as a kind of identifier. Let's
leave aside whether this is a good design -- clearly it is not, given
various issues with double equality comparison and translation to and from
decimal string representation, but at this point it would be a major
investment to revamp our application to use some other way of identifiying
the entities we are passing back and forth.

Using the normal Double.ToString() call in creating the XML does not get the
job done -- there are doubles that do not parse back to the same value when
round-tripped using plain Double.ToString(). I have read about the "R"
format string, which is guaranteed to create a string representation of a
double that will parse back to the same double (apart from possible outliers
like Double.MaxValue, which do not parse). However, the description for the
"R" format makes me wonder why it wouldn't be better to use a format like
"G17" instead. The description for "R" indicates that it will output the
number with 15 decimals, parse that back to a double, and if it's the same
as the original double, it's done, otherwise output it with 17 decimals.
This sounds expensive. Why not just go straight to 17? You might think
that the resulting string will be bigger than necessary. However, my
experience with "G17" is that it will not output 17 decimals unless the
number actually needs 17 decimals. For example, if you take the number 1.0,
and output it using "G17", you get "1". Perhaps it's doing the same thing
behind the scenes as "R" -- outputting the number with fewer decimals,
parsing it back and checking for equality, etc, in which case I still don't
see what the advantage of using "R" is.

Basically, my question boils down to this: if the "R" format uses 17
decimals as a worst case in order to ensure round-trip preservation, how
could there be a number such that "G17" does not preserve its value in a
round trip? Why would I use the "R" format instead of "G17"?

Thanks for any light you can shed on this issue.

RE: Double.ToString round-trip: "R" vs. "G17" v-jetan NO[at]SPAM online.microsoft.com (
5/26/2005 12:00:00 AM
Hi Jason,

Thanks for your post!!

If we use Reflector to view the source code of Double.ToString(string)
method, we will be redirected to an internal method: Number.FormatDouble,
which is marked with the attribute:
[MethodImpl(MethodImplOptions.InternalCall)]
means: An internal call is a call to a method implemented within the common
language runtime itself.(from MSDN topic "MethodImplOptions Enumeration")

So double.ToString's internal implementation is kept in the CLR.

Actually, if you just want to be able to parse a double string
representation back to the double type itself, I think there is no
difference between "R" and "G17" options, they both allow the string to be
correctly parsed back to the double type.

However, there is still some difference between "R" and "G17" options. If a
certain double value's memory binary representation costs more than 15
digits but less than 17(which is the maximum allowed digits), and a string
representation less than 15 will not prevent it from parsing back to the
double value, then "R" will output a string less than 15 digits(get rid of
the non-sense last "0"s), while "G17" will always display the digits
between 15 and 17, whatever if it is valuable for the re-parsing.(that is:
"G17" will always output all the 17 digits and get rid of the non-sense
"0"s). Let's take some examples:

1. For double d=1.0
All the other digits after 1 will be non-sense "0", so both "R" and "G17"
will get rid of the "0"s for output, and both output will be "1"

2. For double d=0.1, code snippet below:
double d=0.1;
string dr=d.ToString("R");
string dg17=d.ToString("G17");
MessageBox.Show(dr);
MessageBox.Show(dg17);

After translating into decimal, it will be like this: 0.10000000000000001,
however, for double.Parse implementation(note again, we do not know the
exact implementation, because it is kept by CLR), all the digits after 0.1
will not be neccessary for parsing, so "R" output just gets rid of it,
displays: 0.1
However, "G17" will output all the 17 valid digits, like this:
0.10000000000000001

All in all, "G17" will always display the valid, make-sense 17 digits of
the double value, while "R" will only display the NEEDED digits for
double.Parse method.

For more information of "R" and "G17" standard formatting, please refer to:
"Standard Numeric Format Strings"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/htm
l/cpconstandardnumericformatstrings.asp

Also, the article below gives us a detailed description of the internal
implementation of .Net floating point, for your information:
"Binary floating point and .NET"
http://www.yoda.arachsys.com/csharp/floatingpoint.html
======================================================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
Re: Double.ToString round-trip: "R" vs. "G17" Jason Frank
5/26/2005 9:34:49 AM
This was useful, thank you. It sounds like the tradeoff to be made is one
of space vs. speed, as is often the case. "G17" will produce a longer
string than "R" for some numbers, but will most likely be faster as it will
not do a parse to check whether a shorter string is sufficient. For my
purposes, I will accept the occasional verbosity of "G17" to avoid the extra
parsing. Thanks again.

[quoted text, click to view]

Re: Double.ToString round-trip: "R" vs. "G17" v-jetan NO[at]SPAM online.microsoft.com (
5/27/2005 12:00:00 AM
Hi Jason,

Thanks for your feedback.

It seems that your concern is on the ToString method performance? First, I
do not think there is much performance difference between "R" and "G17"
options, because they are both small operations.

Also, I can not make the conclusion that: "G17" will be faster than "R"
option. Because "G17" may result in a long string representation, and the
.Net have to alloc more memory space for it. This may also have performance
cost. Below is a little test for this:

private void button1_Click(object sender, System.EventArgs e)
{
DateTime first=DateTime.Now;
double d=0.1;
for(int i=0;i<1000000;i++)
{
d.ToString("R");
}
TimeSpan time=DateTime.Now.Subtract(first);
MessageBox.Show(time.TotalMilliseconds.ToString());
}

private void button1_Click(object sender, System.EventArgs e)
{
DateTime first=DateTime.Now;
double d=0.1;
for(int i=0;i<1000000;i++)
{
d.ToString("G17");
}
TimeSpan time=DateTime.Now.Subtract(first);
MessageBox.Show(time.TotalMilliseconds.ToString());
}

In a PIII 733 512RAM machine, it costs 2437.1442ms for "R", while
2517.3794ms for "G17". So it seems that "G17" is even worse than "R",
although the difference is very few.

Also, "R" will result in a string representation much similiar with the
actual value we can see(for example, 0.1 will in "0.1"), so I think "R" is
more reasonable for the usage.

Anyway, you are making the decision for the choice. Thanks
=======================================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
Re: Double.ToString round-trip: "R" vs. "G17" Jon Skeet [C# MVP]
5/27/2005 12:00:00 AM
[quoted text, click to view]

It all depends on how often you're doing it, of course.

[quoted text, click to view]

So would doing it twice and throwing away the first string though,
wouldn't it?

[quoted text, click to view]

Here's another one which doesn't just use the same value every time -
your test is biased in favour of "R" by giving it a value which *does*
comfortably fit without having to calculate the longer version.

using System;

class Test
{
const double FirstDouble = 1.0;
const int Iterations = 10000000;

static void Main()
{
long firstLong = BitConverter.DoubleToInt64Bits(FirstDouble);
long longBound = firstLong+Iterations;

{
DateTime start = DateTime.Now;
for (long x = firstLong; x < longBound; x++)
{
BitConverter.Int64BitsToDouble(x);
}
DateTime end = DateTime.Now;
Console.WriteLine ("Time to convert longs to doubles: {0}",
end-start);
}

{
DateTime start = DateTime.Now;
for (long x = firstLong; x < longBound; x++)
{
BitConverter.Int64BitsToDouble(x).ToString("R");
}
DateTime end = DateTime.Now;
Console.WriteLine ("Format with R: {0}", end-start);
}

{
DateTime start = DateTime.Now;
for (long x = firstLong; x < longBound; x++)
{
BitConverter.Int64BitsToDouble(x).ToString("G");
}
DateTime end = DateTime.Now;
Console.WriteLine ("Format with G17: {0}", end-start);
}
}
}


[quoted text, click to view]

Results of mine:
Time to convert longs to doubles: 00:00:00.1718750
Format with R: 00:00:09.9687500
Format with G17: 00:00:06.3906250

[quoted text, click to view]

That's only because 0.1 happens to be what was in the program. You
could equally have written the program with:

0.10000000000000001

at which point the argument reverses :)

--
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet
Re: Double.ToString round-trip: "R" vs. "G17" Jason Frank
5/27/2005 5:46:32 PM
Thanks for the additional food for thought. My main concern was to make
sure that by using G17 we are guaranteed that the double will round-trip to
the same value. This appears to be the case. The issue of performance is
important but less so. We have already started using G17 in production, so
to avoid any data migration, I believe we will stick with that.

Thanks again for all the help, most informative.

[quoted text, click to view]

Re: Double.ToString round-trip: "R" vs. "G17" v-jetan NO[at]SPAM online.microsoft.com (
5/28/2005 12:00:00 AM
Hi Jon,

Oh, yes, it seems you are right. I have chosen the too specific test
argument...

Thanks for the information you sharing with the community!

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
Re: Double.ToString round-trip: "R" vs. "G17" v-jetan NO[at]SPAM online.microsoft.com (
5/28/2005 12:00:00 AM
Hi Jason,

Yes, I also think the correctness is the most important option in your
design.
Also, Jon has corrected some problem in my performance test :-), it may
give you some useful information on performance comparison of these 2
options.

If you need further help, please feel free to feedback, thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
AddThis Social Bookmark Button