属性 针对 F# 中的 nan 值进行测试的简明通用方法是什么?
What is a concise, general method of property testing against nan values in F#?
我正在使用 FsCheck 在 F# 中进行一些 属性 测试。因此,我希望保证某些条件始终成立,无论输入参数如何。
假设我为 float
个值定义了一个简单的恒等式函数。
let floatId (x : float) = x
然后我定义了这个函数的测试,我知道它应该始终保持:
let ``floatId returns input float`` x = floatId x = x
这是一个简单的测试,我只是检查调用我的 float 身份函数 returns 与输入 float 相同。
然后我将这个函数插入到 FsCheck 中:
Check.Quick ``floatId returns input float``
不幸的是,这个 属性 测试失败了!
Falsifiable, after 21 tests (0 shrinks) (StdGen (1872424299,296201373)):
Original:
nan
当然,回想起来,很明显这会发生,我们知道 nan <> nan
。
由于 F# 中的结构比较,这也会困扰(稍微)更复杂的涉及集合的测试用例。
如果我为浮动列表设计类似的功能:
let listFloatId (lst : float list) = lst
let ``listFloatId returns input float list`` lst = listFloatId lst = lst
Falsifiable, after 6 tests (3 shrinks) (StdGen (1874889363,296201373)):
Original:
[nan; 2.0; 2.25; 4.940656458e-324]
Shrunk:
[nan]
又是同样的问题!
显然,我可以通过创建自己的相等性测试函数来解决这个问题,这对 float
值很好,但是扩展到 list
这样的集合变得更加复杂,因为我必须开始使用List.forall2
使用我的自定义相等函数,并且通常将我的代码专门针对每个单独的集合类型。
在 F# 中是否有解决此问题的通用方法?
您可以使用LanguagePrimitives.GenericEqualityER
函数解决这个问题。这使用等价关系语义检查相等性。这个函数实际上是比较[nan]
列表的具体例子。
测试用例可以这样定义:
let ``ER : floatId returns input float`` x = LanguagePrimitives.GenericEqualityER (floatId x) x
let ``ER : listFloatId returns input float list`` lst = LanguagePrimitives.GenericEqualityER (listFloatId lst) lst
这次:
Ok, passed 100 tests.
Ok, passed 100 tests.
(我问和回答这个问题是因为上面的 属性 是在 FSharp Software Foundation Slack 频道中提出的,我认为记录这个解决方案会很有用。我几乎可以找到除了 LanguagePrimitives
模块的文档外,没有在线提及此功能。
我正在使用 FsCheck 在 F# 中进行一些 属性 测试。因此,我希望保证某些条件始终成立,无论输入参数如何。
假设我为 float
个值定义了一个简单的恒等式函数。
let floatId (x : float) = x
然后我定义了这个函数的测试,我知道它应该始终保持:
let ``floatId returns input float`` x = floatId x = x
这是一个简单的测试,我只是检查调用我的 float 身份函数 returns 与输入 float 相同。
然后我将这个函数插入到 FsCheck 中:
Check.Quick ``floatId returns input float``
不幸的是,这个 属性 测试失败了!
Falsifiable, after 21 tests (0 shrinks) (StdGen (1872424299,296201373)): Original: nan
当然,回想起来,很明显这会发生,我们知道 nan <> nan
。
由于 F# 中的结构比较,这也会困扰(稍微)更复杂的涉及集合的测试用例。
如果我为浮动列表设计类似的功能:
let listFloatId (lst : float list) = lst
let ``listFloatId returns input float list`` lst = listFloatId lst = lst
Falsifiable, after 6 tests (3 shrinks) (StdGen (1874889363,296201373)): Original: [nan; 2.0; 2.25; 4.940656458e-324] Shrunk: [nan]
又是同样的问题!
显然,我可以通过创建自己的相等性测试函数来解决这个问题,这对 float
值很好,但是扩展到 list
这样的集合变得更加复杂,因为我必须开始使用List.forall2
使用我的自定义相等函数,并且通常将我的代码专门针对每个单独的集合类型。
在 F# 中是否有解决此问题的通用方法?
您可以使用LanguagePrimitives.GenericEqualityER
函数解决这个问题。这使用等价关系语义检查相等性。这个函数实际上是比较[nan]
列表的具体例子。
测试用例可以这样定义:
let ``ER : floatId returns input float`` x = LanguagePrimitives.GenericEqualityER (floatId x) x
let ``ER : listFloatId returns input float list`` lst = LanguagePrimitives.GenericEqualityER (listFloatId lst) lst
这次:
Ok, passed 100 tests. Ok, passed 100 tests.
(我问和回答这个问题是因为上面的 属性 是在 FSharp Software Foundation Slack 频道中提出的,我认为记录这个解决方案会很有用。我几乎可以找到除了 LanguagePrimitives
模块的文档外,没有在线提及此功能。