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:
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
Post a Comment