c# - Why does a parsed double not equal an initialized double supposedly of the same value? -


when execute line:

double dparsed = double.parse("0.00000002036"); 

dparsed gets value: 0.000000020360000000000002

compared line,

double dinitialized = 0.00000002036; 

in case value of dinitialized 0.00000002036

here in debugger: difference between double.parse , initializer

this inconsistency trifle annoying, because want run tests along lines of:

[subject("parsing doubles")] public class when_parsing_crazy_doubles     {     static double dinitialized = 0.00000002036;     static double dparsed;     because of = () => dparsed = double.parse("0.00000002036");     should_match = () =>  dparsed.shouldbelike(dinitialized);     } 

this of course fails with:

 machine.specifications.specificationexception "":   expected: [2.036e-08]   was:  [2.036e-08] 

in production code, 'parsed' doubles read data file whereas comparison values hard coded object initializers. on many hundreds of records, 4 or 5 of them don't match. original data appears in text file this:

0.00000002036 0.90908165072 6256.77753019160

so values being parsed have 11 decimal places. ideas working around inconsistency?

while accept comparing doubles equality risky, i'm surprised compiler can exact representation when text used object initializer, double.parse can't exact representation when parsing same text. how can limit parsed doubles 11 decimal places?

compared line,

double dinitialized = 0.00000002036; 

in case value of dinitialized 0.00000002036


if have remotely resembling commodity computer, dinitialized not initialized 0.00000002036. can't because base 10 number 0.00000002036 not have finite representation in base 2.

your mistake expecting 2 doubles compare equal. that's not idea. unless have reasons , know doing, best not compare 2 doubles equality or inequality. instead test whether difference between 2 lies within small epsilon of zero.

getting size of epsilon right bit tricky. if 2 numbers both small, (less one, example), epsilon of 1e-15 might appropriate. if numbers large (larger ten, example), small of epsilon value equivalent testing equality.


edit: didn't answer question.

how can limit parsed doubles 11 decimal places?

if don't have worry small values,

static double epsilon = 1e-11; if (math.abs(dparsed-dinitialized) > epsilon*math.abs(dinitialized)) {     notetestasfailed(); } 

you should able safely change epsilon 4e-16.


edit #2: why compiler , double.parse produce different internal representations same text?

that's kind of obvious, isn't it? compiler , double.parse use different algorithms. number in question 0.00000002036 close being on cusp of whether rounding or rounding down should used yield representable value within half ulp of desired value (0.00000002036). "right" value 1 within half ulp of desired value. in case, compiler makes right decision of picking rounded-down value while parser makes wrong decision of picking rounded-up value.

the value 0.00000002036 nasty corner case. not representable value. 2 closest values can represented ieee doubles 6153432421838462/2^78 , 6153432421838463/2^78. value halfway between these 2 12306864843676925/2^79, very, close 0.00000002036. that's makes corner case. suspect of values found compiled value not identically equal value double.parse corner cases, cases desired value halfway between 2 closest representable values.


edit #3:

here number of different ways interpret 0.00000002036:

  • 2/1e8 + 3/1e10 + 6/1e11
  • 2*1e-8 + 3*1e-10 + 6*1e-11
  • 2.036 * 1e-8
  • 2.036 / 1e8
  • 2036 * 1e-11
  • 2036 / 1e11

on ideal computer of these same. don't count on being case on computer uses finite precision arithmetic.


Comments

Popular posts from this blog

php - regexp cyrillic filename not matches -

c# - OpenXML hanging while writing elements -

sql - Select Query has unexpected multiple records (MS Access) -