我想找出满足
的第一个n,如果我用另一种语言,比如c/c ++,这是一件简单而容易的事情,但是我不知道如何在Haskell中实现它。
#include <iostream>
long double term(int k) { return 1.0/(k*k+2.0*k); }
int main() {
long double total = 0.0;
for (int k=1;;k++) {
total += term(k);
if (total>=2.99/4.0) {
std::cout << k << std::endl;
break;
}
}
return 0;
}
我使用dropWhile处理一个有序列表,并取1来获取第一个列表。
term k = 1.0/(k*k+2.0*k)
termSum n = sum $ take n $ map term [1..]
main = do
let [(n,val)] = take 1 $ dropWhile (\(a,b)->b <= 2.99/4.0) $ map (\n->(n,termSum n)) [1..]
print n
我知道这很可怕。什么是最好的和直观的方式来写这个?
回复:谢谢你的伟大的答案!一个使用修复功能似乎是最快的在我的机器(Redhat 6. 4 64bit/80GB内存)
method#0取1并dropWhile(我初始实现)
threshold=0.74999 n=99999 time=52.167 sec
方法#1使用修复函数
threshold=0.74999 n=99999 time=0.005 sec
threshold=0.74999999 n=101554197 time=1.077 sec
threshold=0.7499999936263 n=134217004 time=1.407 sec
方法#2反向工作
threshold=0.74999 n=99999 time=0.026 sec
threshold=0.74999999 n=101554197 time=21.523 sec
threshold=0.7499999936263 n=134217004 time=25.247 sec
方法#3命令式方法
threshold=0.74999 n=99999 time=0.008 sec
threshold=0.74999999 n=101554197 time=2.460 sec
threshold=0.7499999936263 n=134217004 time=3.254 sec
回复回复:我注意到无论我用什么实现(修复、命令式或递归方式),如果阈值大于0.7499999936264 ...则永远不会结束..为了使f(n)大于0.7499999936264,我以为我们只需要计算到150,000的项,000以来![f(n)=\frac_{3n^2 + 5n} ^{4n^2 + 12n +8}]。我使用Integer代替Int,但它也没有帮助。如果我将阈值设置为大于0.7499999936264 ...,是否有任何原因导致它无法完成?
4条答案
按热度按时间ldxq2e6h1#
在这种情况下,我喜欢倒推:
工作原理:
terms
是一个无限列表,但由于Haskell很懒,我们只计算我们需要的每一项:partialSums
是另一个无限列表,它基于terms
的内容(使用scanl1
),它允许我们分摊计算termSum
所做的工作:然后
takeWhile (< (2.99/4))
确定我们需要生成partialSums
的多少项,从而确定我们需要生成terms
的多少项:如果我们检查一下,我们可以看到,第398个
terms
之和都小于2.99 / 4
,但第399个却把它撞过来了:或者,第397个部分和(从0开始的索引)小于目标,而第398个部分和不是:
q3aa05252#
本质上是显式递归,但我喜欢
fix
for循环,如下所示:mm9b1k5b3#
如果我使用另一种语言,比如c/c++,这是一件简单而容易的事情
好吧,那我们就用同样的方法。
是的,上面的答案与其说是严肃的答案,不如说是一个玩笑。不过,很高兴看到,至少在理论上,用Haskell编写命令式代码是可能的。
这只会导致非惯用的Haskell,这并不比原始代码难读或难写多少。毕竟,朋友之间的一两次
callCC
又有什么关系呢?:-Penyaitl34#
我同意显式递归是最简单的编写方法,但是使用fix会让所有程序员感到困惑,除非是非常老练的程序员。
使用更高阶的函数直到可能被看作更接近C++代码。因此
此外,C++代码中的中断也是多余的,因为该代码可以编写为
最后,关于为什么计算150,000,000以下的项不会得到大于0.7499999936264的结果,这是浮点运算的固有特性。将一个非常小的项添加到一个相对较大的总数中不会改变总数:
为了避免这种情况,您必须以相反的顺序添加项,从最小到最大。