3 ms·
Dan Luu's article about transitive equality and floating point numbers is pretty amusing. (https://codewords.hackerschool.com/issues/one/when-is-equality-transi
by akanet 12y ago
Dan Luu's article about transitive equality and floating point numbers is pretty amusing. (https://codewords.hackerschool.com/issues/one/when-is-equality-transitive-and-other-floating-point-curiosities https://codewords.hackerschool.com/issues/one/when-is-equali...).
Here's a little tidbit from the article (notice that he's shown an example in Haskell where A == B, B == C, but A != C):
$ ghci
Prelude> -- Hi! I'm a comment!
Prelude> -- 2^53 == 2.0^53
Prelude> 9007199254740992 == 9007199254740992.0
True
Prelude> -- 2.0^53 == 2^53 + 1
Prelude> 9007199254740992.0 == 9007199254740993
True
Prelude> -- 2^53 == 2^53 + 1
Prelude> 9007199254740992 == 9007199254740993
False
- copascetic 12y agoThis example is misleading, and I don't think the article addresses the subtleties. Basically, the third line is not like the other two. Because none of the numbers involved in #3 are Doubles, Haskell will actually use the Integer type, which is basically a bignum (like integers in Python). The first two are comparing values of type Double, so the instance of Eq for Double is used, which necessarily has some inaccuracies, as shown in the second line, while the last one is using the instance of Eq for Integer. Therefore, the statement that (==) is not transitive for these types is false, because we are talking about different versions of (==) in the first two examples vs. the last one. The trick is that bare numeric literals have type Num a => a, and have their type inferred by their use. The first two examples cause the 2^53 to take on type Double, otherwise it wouldn't type check (literals with decimals in them have type Fractional a => a, of which Double is the default). The last one doesn't have any expressions with decimals, so it uses the Integer type.
- copascetic 12y agoWhen you specify the types of the numbers used, so that you are testing the transitivity of a single instance of Eq, you will find that transitivity does hold in this case. a :: Double a = 2^53 b :: Double b = 2.0^53 c :: Double c = 2^53 + 1 main :: IO () main = do print $ a == b -- True print $ b == c -- True print $ a == c -- True