哪一个更快,为什么?

时间:2010-03-11 09:26:57

标签: performance haskell

(n >= 3 ) && (n <= 99)

OR

 n `elem` [3..99]

哪一个更快,为什么?

4 个答案:

答案 0 :(得分:18)

第一个更快

 (n >= 3) && (n <= 99)

正在进行3次操作

 n >= 3
 n <= 99
 and

elem正在查找数组中的项目时,最多执行(99 - 3)* 2操作。

index = 0
isFound = false
array[] = { 3, 4, 5, 6, ... 98, 99 }

while isFound == false
   isFound = (n == array[index++])

答案 1 :(得分:11)

(n> = 3)&amp;&amp; (n <= 99)更快,因为它仅涉及两个平凡的比较。如果编译器/解释器没有做任何真正的黑魔法优化,它必须构造列表([3..99]),因为懒惰的评估不能使用(通常“拉”下一个值,直到你完成,在这种情况下会有O(n / 2)的复杂度。

答案 2 :(得分:8)

这两个表达并不是一回事。一个微妙的区别是,一个依赖于Ord而另一个依赖于Enum

> :t \n -> (n >= 3) && (n <= 99)
\n -> (n >= 3) && (n <= 99) :: (Num a, Ord a) => a -> Bool

> :t \n -> n `elem` [3..99]
\n -> n `elem` [3..99] :: (Num a, Enum a) => a -> Bool

所以,例如,如果n是3.14159,那么第一个测试将通过,但第二个测试不会:

> (pi >= 3) && (pi <= 99)
True

> pi `elem` [3..99]
False

此外,虽然四个Prelude Num个实例(IntIntegerFloatDouble)都是{{1}的实例}和Ord,可以想象一个数字类型,它是Enum但不是Ord的实例。在这种情况下,第二次测试甚至不合法。

因此,一般情况下,编译器不能将第二个显示为与第一个一样快,除非它知道给定类型,它是Enum并且该范围内的所有有序值也在由Ord创建的列表枚举。对于enumFromToFloat,这不是真的,对于DoubleInt,编译器无法派生它,编译器和库程序员必须手工编码并确保在所有情况下都能保留。

答案 3 :(得分:-2)

取决于机器和编译器(或解释器)。