浮点数,精度和Parsec

时间:2015-04-23 10:34:29

标签: haskell floating-point parsec

请考虑以下代码:

import Text.Parsec
import Text.Parsec.Language
import Text.Parsec.String
import qualified Text.Parsec.Token as Token

float :: Parser Double
float = Token.float (Token.makeTokenParser emptyDef)

myTest :: String -> Either ParseError Double
myTest = parse float ""

现在,感谢QuickCheck,我知道一个神奇的数字(我已经对齐了 方便):

λ> myTest "4.23808622486133"
Right      4.2380862248613305

有些浮点数无法在内存中准确表示 操作很容易将“波动”引入浮点数。我们 都知道。但是,这个解析问题的原因似乎不同。

关于帮助我发现这个特征的测试的几句话。简单地说, 在这些测试中,生成,打印和解析浮点值 (与Parsec)。例如,已知数字9.2impossible to represent as floating point value, 然而它通过了测试(显然是因为«智能»打印 功能)。为什么4.23808622486133会失败?

对于那些认为这些数字相同且4.23808622486133只是4.2380862248613305的最短明确表示的人:

a1 :: Double
a1 = 9.2000000000000003

a2 :: Double
a2 = 9.200000000000001

b1 :: Double
b1 = 4.23808622486133

b2 :: Double
b2 = 4.2380862248613305

现在:

λ> a1 == a2
True
λ> b1 == b2
False

2 个答案:

答案 0 :(得分:3)

Parsec使用等于

的转换为Double
foldr (\d acc -> read [d] + acc / 10) 0 "423808622486133" :: Double

正如您所指出的,这不等于

423808622486133 / 100000000000000 :: Double

我同意这应该被认为是Parsec中的一个错误。

答案 1 :(得分:0)

Parsec中仍然没有解决这个问题。如果这个确切的问题打破了你的一天,请看看Megaparsec,它是Parsec的一个分支,修复了许多错误和概念缺陷,提高了错误消息的质量等等。

正如您所看到的那样,问题已解决:

λ> parseTest float "4.23808622486133"
4.23808622486133
λ> parseTest float "4.2380862248613305"
4.2380862248613305

披露:我是Megaparsec的作者之一。