ios - Comparing NSNumber instances with isEqualToNumber -
yes, i've read other posts on stackoverflow comparing nsnumber , none of them seem quite address particular situation.
solution particularly bad ... nsnumber compare: returning different results
because suggested solution doesn't work @ all. using abs(value1 - value2) < tolerance flawed start because fractional values stripped off, making tolerance irrelevant.
and apple documentation... nsnumber explicitly doesn't guarantee returned type match method used create it. in other words, if you're given nsnumber, have no way of determining whether contains float, double, int, bool, or whatever.
also, best can tell, nsnumber isequaltonumber untrustworthy method compare 2 nsnumbers.
so given these definitions...
nsnumber *float1 = [nsnumber numberwithfloat:1.00001]; nsnumber *double1 = [nsnumber numberwithdouble:1.00001];
if run debugger , 2 comparisons of these identical numbers using ==, 1 fails, , other not.
p [double1 floatvalue] == [float1 floatvalue] **// returns true** p [double1 doublevalue] == [float1 doublevalue] **// returns false**
if compare them using isequaltonumber
p [float1 isequaltonumber:double1] **// returns false**
so if isequaltonumber going return false, given creation of nsnumber black box may give other type on way out, i'm not sure method is.
so if you're going make test dirty, because existing value has been changed new value... what's simplest way that handle nsnumber comparisons.. not float , double, nsnumbers?
it seems converting string value, compariing useful, or perhaps whole lot of code using nsnumberformatter.
what thoughts?
it not possible reliably compare 2 ieee floats or doubles. has nothing nsnumber
. nature of floating point. discussed in context of simple c types @ strange problem comparing floats in objective-c. only correct way compare floating point numbers testing against tolerance. don't know mean "fractional values stripped off." digits always lost in floating point representation.
the particular test value you've provided demonstrates problems quite nicely. 1.00001 cannot expressed precisely in finite number of binary digits. wolfram alpha nice way explore this, double, 1.00001 rounds 1.0000100000000001. float, rounds 1.00001001. these numbers, obviously, not equal. if roundtrip them in different ways, should not surprise isequaltonumber:
fails. should make clear why 2 floatvalue
calls turn out equal. rounded precision of float, they're "close enough."
if want compare floating point numbers, must compare against epsilon. given recent advances in compiler optimization, 2 identical pieces of floating point c code can generate different values in least-significant digits if use -ofast
(we big performance benefits allowing that).
if need specific number of significant fractional digits, better work in fixed point notation. scale number of digits need , work in integers. if need floating point, want base-10 work (rather base-2), use nsdecimalnumber
or nsdecimal
. move problems things round badly in base-10. if you're working in floating point, must deal rounding errors.
for more extensive discussion, see "what every programmer should know floating-point arithmetic."
Comments
Post a Comment