Weird double parsing

  • Thread starter Thread starter Jimmy
  • Start date Start date
J

Jimmy

Hi!

Simply put, the following code:

bool systemOk = true;
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");

if (!s.ToString("0.00").Equals("-606,11"))
{
systemOk = false;
Console.WriteLine("On iteration #{0}. '606,11' was parsed as {1}", i, s);
}
}

if (systemOk)
{
Console.WriteLine("No error found!");
}

Console.WriteLine("Press enter to exit...");
Console.ReadLine();

....outputs the following the first run:
On iteration #2373. '606,11' was parsed as -606,01
On iteration #8949. '606,11' was parsed as -606,01
On iteration #9338. '606,11' was parsed as -606,01
On iteration #9643. '606,11' was parsed as -606,01
On iteration #9817. '606,11' was parsed as -606,01
Press enter to exit...

....and the following on the second run:
On iteration #4944. '606,11' was parsed as -606,01
On iteration #5911. '606,11' was parsed as -606,01
On iteration #8302. '606,11' was parsed as -606,01
On iteration #8518. '606,11' was parsed as -606,01
On iteration #8681. '606,11' was parsed as -606,01
Press enter to exit...

Should I consider suspect a hardware error? I've ran it on other computes
with no errors. Any hints on how to test the hardware to verify such
hypothesis?
 
Jimmy said:
Hi!

Simply put, the following code:

bool systemOk = true;
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");

if (!s.ToString("0.00").Equals("-606,11"))
[...]

Maybe I'm silly, but wouldn't this never be true? Shouldn't it be:

if (!s.ToString("0,00").Equals("-606,11"))


Chris.
 
Thanks Chris!

I see your point. You really should be getting curious when you look at the
output. Given your question, there should be no output at all... :)

I apologize if this was a bit misleading. The reason is cultural
differences, I use a danish culture. Hence, "0.00" becomes "0,00".
Console.WriteLine(s.ToString("0.00",
System.Globalization.CultureInfo.CreateSpecificCulture("en-US")));
outputs: "-606.11"
Console.WriteLine(s.ToString("0.00",
System.Globalization.CultureInfo.CreateSpecificCulture("da-DK")));
outputs: "-606,11"

Perhaps the parsing problem itself has something to do with culture
settings. I don't know... I've tried different numbers and a common
denominator is that it is always a '1' that is wrongly parsed as a '0'. The
position of the digit differs from time to time, e.g., 11,11 could be parsed
as 11,01 or 10,11



Chris Shepherd said:
Jimmy said:
Hi!

Simply put, the following code:

bool systemOk = true;
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");

if (!s.ToString("0.00").Equals("-606,11"))
[...]

Maybe I'm silly, but wouldn't this never be true? Shouldn't it be:

if (!s.ToString("0,00").Equals("-606,11"))


Chris.
 
if (!s.ToString("0.00").Equals("-606,11"))
[...]

Maybe I'm silly, but wouldn't this never be true? Shouldn't it be:

if (!s.ToString("0,00").Equals("-606,11"))

Nope. The format string uses only the period for decimal, regardless of
what the actual decimal separator is set to for the system, and the comma
is specifically for something else (thousand separator or number scaling,
depending on context). This allows a format string to be
language-independent.

The output from the program proves that the if() condition works as
expected, since it is true occasionally.

Unfortunately, I don't have any useful information regarding the behavior
the OP is seeing. Hardware errors are rare, and I have seen at least one
other example of floating point operations being affected by other things
going on in the computer (code that leaves the FPU in an unusual state).
But the error in this case is much greater than that noted in the other
example I saw; a floating point error that's just part of the normal
operation of the FPU should be _much_ smaller than that.

One thing about the posted code is that it relies on the formatting code,
which means the error could be happening in the parse, or the format back
to a string. It would be useful and interesting to change the test so
that it's two different loops, one that repeatedly parses the string, but
compares it to a constant double instead of formatting it again, and
another that starts with a constant double and repeatedly parses it.

That would help narrow down the problem, to identify whether it happens
only when parsing, only when formatting, or in neither case separately (in
other words, the two operations are interacting somehow to cause the
error). I suppose it's possible the test would reveal errors in both
operations, but that seems unlikely to me.

I don't have enough knowledge to know how to _use_ that information, but
it would at least hopefully help understand the error better.

Pete
 
Jimmy said:
I see your point. You really should be getting curious when you look at the
output. Given your question, there should be no output at all... :)
I apologize if this was a bit misleading. The reason is cultural
differences, I use a danish culture. Hence, "0.00" becomes "0,00".
Console.WriteLine(s.ToString("0.00",
System.Globalization.CultureInfo.CreateSpecificCulture("en-US")));
outputs: "-606.11"
Console.WriteLine(s.ToString("0.00",
System.Globalization.CultureInfo.CreateSpecificCulture("da-DK")));
outputs: "-606,11"

It wasn't misleading of you, and I was aware it's a cultural difference,
I just assumed that you would have to use the culture-specific proper
syntax on ToString. That appears to be completely wrong of me.
It's odd your code doesn't work, because if I create a culture object
for da-DK it works fine -- this code is working correctly for me:


CultureInfo dk = CultureInfo.CreateSpecificCulture("da-DK");
string stringVal = "-606,11";

bool systemOk = true;
for (int i = 0; i < 10000; i++)
{
double s = double.Parse(stringVal, dk);

if (!s.ToString("0.00",dk).Equals(stringVal))
{
systemOk = false;
Console.WriteLine("On iteration #{0}. '{1}' was parsed as {2}", i,
stringVal, s);
}
}

if (systemOk)
{
Console.WriteLine("No error found!");
}

Console.WriteLine("Press enter to exit...");
Console.ReadLine();




Chris.
 
Peter said:
Nope. The format string uses only the period for decimal, regardless of
what the actual decimal separator is set to for the system, and the
comma is specifically for something else (thousand separator or number
scaling, depending on context). This allows a format string to be
language-independent.

The output from the program proves that the if() condition works as
expected, since it is true occasionally.

Actually, it was *always* true for me. I could never get it to not
always either be true or false, even over 90000 iterations instead of
10000.

Are you seeing different results?

Chris.
 
Chris said:
It wasn't misleading of you, and I was aware it's a cultural difference,
I just assumed that you would have to use the culture-specific proper
syntax on ToString. That appears to be completely wrong of me.
It's odd your code doesn't work, because if I create a culture object
for da-DK it works fine -- this code is working correctly for me:
[...]

To be clear, by "this code is working correctly for me" I mean that I
simply get the "No errors found!" message followed by "Press enter to
exit..." with no appearance of any of the "On iteration #" messages.

Chris.
 
Good idea. Tested with code:
bool systemOk = true;
Console.WriteLine("Testing with string comparison...");
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");
if (!s.ToString("0.00").Equals("-606,11"))
{
systemOk = false;
Console.WriteLine("On iteration #{0}. '-606,11' was parsed as {1}", i, s);
}
}

const double doubleCompare = -606.11d;
Console.WriteLine("Testing with double comparison...");
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");
if (s!=doubleCompare)
{
systemOk = false;
Console.WriteLine("On iteration #{0}. '-606,11' was parsed as {1}", i, s);
}
}

if (systemOk)
{
Console.WriteLine("No error found!");
}

Console.WriteLine("Press enter to exit...");
Console.ReadLine();

Result:
Testing with string comparison...
On iteration #1016. '-606,11' was parsed as -606,01
On iteration #1055. '-606,11' was parsed as -606,01
On iteration #3110. '-606,11' was parsed as -606,01
On iteration #4366. '-606,11' was parsed as -606,01
On iteration #7388. '-606,11' was parsed as -606,01
On iteration #9022. '-606,11' was parsed as -606,01
Testing with double comparison...
On iteration #5. '-606,11' was parsed as -606,01
On iteration #594. '-606,11' was parsed as -606,01
On iteration #2242. '-606,11' was parsed as -606,01
On iteration #3648. '-606,11' was parsed as -606,01
On iteration #9918. '-606,11' was parsed as -606,01
Press enter to exit...

Weird!

Peter Duniho said:
if (!s.ToString("0.00").Equals("-606,11"))
[...]

Maybe I'm silly, but wouldn't this never be true? Shouldn't it be:

if (!s.ToString("0,00").Equals("-606,11"))

Nope. The format string uses only the period for decimal, regardless of
what the actual decimal separator is set to for the system, and the comma
is specifically for something else (thousand separator or number scaling,
depending on context). This allows a format string to be
language-independent.

The output from the program proves that the if() condition works as
expected, since it is true occasionally.

Unfortunately, I don't have any useful information regarding the behavior
the OP is seeing. Hardware errors are rare, and I have seen at least one
other example of floating point operations being affected by other things
going on in the computer (code that leaves the FPU in an unusual state).
But the error in this case is much greater than that noted in the other
example I saw; a floating point error that's just part of the normal
operation of the FPU should be _much_ smaller than that.

One thing about the posted code is that it relies on the formatting code,
which means the error could be happening in the parse, or the format back
to a string. It would be useful and interesting to change the test so
that it's two different loops, one that repeatedly parses the string, but
compares it to a constant double instead of formatting it again, and
another that starts with a constant double and repeatedly parses it.

That would help narrow down the problem, to identify whether it happens
only when parsing, only when formatting, or in neither case separately (in
other words, the two operations are interacting somehow to cause the
error). I suppose it's possible the test would reveal errors in both
operations, but that seems unlikely to me.

I don't have enough knowledge to know how to _use_ that information, but
it would at least hopefully help understand the error better.

Pete
 
[...]
The output from the program proves that the if() condition works as
expected, since it is true occasionally.

Actually, it was *always* true for me. I could never get it to not
always either be true or false, even over 90000 iterations instead of
10000.

Are you seeing different results?

I haven't even tried to run it. By "is true occasionally" I just mean on
the OP's computer.

I assume you mean that the result of the Equals() method is true. The
clause itself should always be _false_ on a computer that doesn't
demonstrate the error (and as the OP says, so far he's only been able to
reproduce it on his own computer...the code doesn't detect any error on a
different computer).

Pete
 
Good idea. Tested with code:

Well, the code you posted isn't exactly what I meant. Try this:

bool systemOk = true;
Console.WriteLine("Testing formatting...");
const double doubleCompare = -606.11d;
for (int i=0; i<10000; i++)
{
string strT = doubleCompare.ToString("0.00");

if (!strT.Equals("-606,11"))
{
systemOk = false;
Console.WriteLine("On iteration #{0}. '-606,11' was formatted as {1}",
i, strT);
}
}

Console.WriteLine("Testing parsing...");
for (int i=0; i<10000; i++)
{
double s = double.Parse("-606,11");
if (s!=doubleCompare)
{
systemOk = false;
// WARNING: if there's an error in the formatting, then
the output here is
// suspect, because it relies on the formatting to display
the double! :)
Console.WriteLine("On iteration #{0}. '-606,11' was parsed as {1}", i,
s);
}
}

if (systemOk)
{
Console.WriteLine("No error found!");
}

Console.WriteLine("Press enter to exit...");
Console.ReadLine();
 
Ah, I see. The error only occur in relation to double.Parse. A ToString from
a double will not produce this error.

Here's probably the strangest piece of code I've written - the workaround
(taken from its context of course) :)

string tmpStr = thedoublestring; // eg. -606.11
double s;
string sStr;
do
{
s = double.Parse(tmpStr);
sStr = s.ToString("0.000000");
} while (!sStr.Equals(columns[selectedBeloebColumns]));
 
Back
Top