浮点数、精度和秒差距
Floating point numbers, precision, and 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
有些浮点数不能在内存中精确表示,有些
操作很容易将“波动”引入浮点数。我们
都知道。但是,这个解析问题的原因似乎有所不同。
关于帮助我发现此…功能的测试的几句话。简单地说,
在这些测试中,生成、打印并解析回浮点值
(与秒差距)。例如,已知数字 9.2
不可能
表示为浮动
点值,
然而它通过了测试(显然是因为“智能”打印
功能)。为什么 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
Parsec 使用等于
的量转换为 Double
foldr (\d acc -> read [d] + acc / 10) 0 "423808622486133" :: Double
正如您所指出的,这不等于
423808622486133 / 100000000000000 :: Double
我同意这应该被视为 Parsec 中的错误。
这在 Parsec 中仍未修复。如果这个确切的问题让你一整天都不开心,请查看 Megaparsec,它是 Parsec 的一个分支,修复了许多错误和概念缺陷,提高了错误消息的质量等等。
如您所见,此问题已解决:
λ> parseTest float "4.23808622486133"
4.23808622486133
λ> parseTest float "4.2380862248613305"
4.2380862248613305
披露:我是 Megaparsec 的作者之一。
考虑以下代码:
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
有些浮点数不能在内存中精确表示,有些 操作很容易将“波动”引入浮点数。我们 都知道。但是,这个解析问题的原因似乎有所不同。
关于帮助我发现此…功能的测试的几句话。简单地说,
在这些测试中,生成、打印并解析回浮点值
(与秒差距)。例如,已知数字 9.2
不可能
表示为浮动
点值,
然而它通过了测试(显然是因为“智能”打印
功能)。为什么 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
Parsec 使用等于
的量转换为 Doublefoldr (\d acc -> read [d] + acc / 10) 0 "423808622486133" :: Double
正如您所指出的,这不等于
423808622486133 / 100000000000000 :: Double
我同意这应该被视为 Parsec 中的错误。
这在 Parsec 中仍未修复。如果这个确切的问题让你一整天都不开心,请查看 Megaparsec,它是 Parsec 的一个分支,修复了许多错误和概念缺陷,提高了错误消息的质量等等。
如您所见,此问题已解决:
λ> parseTest float "4.23808622486133"
4.23808622486133
λ> parseTest float "4.2380862248613305"
4.2380862248613305
披露:我是 Megaparsec 的作者之一。