F#奇妙游(5):盘算π的值

打印 上一主题 下一主题

主题 845|帖子 845|积分 2535

F#到底有什么用?

奇妙游写到第五篇,前面的几篇都是开场白:

  • 一个用F#编写WinForm的例子
  • donet命令行工具,也就是F#的开发环境
  • 关于函数和函数式编程的碎碎念
  • 函数式编程的核心概念:值
下面,我们开始正式来搞点事情,看看F#能做些什么。在此之前,我们再复习F#的运行环境。
F# Interactive

那么F#到底有什么用呢?我们前面说了F#有一个命令行,可以用dotnet fsi打开。这个叫做交互式开发环境,比力当代的语言,都会提供一个交互式的环境,比如Java、Python,都有。而函数式的语言,则更加注重这个环境,缘故原由如下:
函数式的编程,注重由下向上来开发,为了实现一个体系的整体功能,先逐步实现更加底层的功能,慢慢把一个体系整合出来。相区别的是面向对象的步伐开发,一开始会投入大量的精力来规划类层次布局、设计类的接口。函数固然也是接口,但是函数的接口很轻。
每一个小函数的精确性比力轻易证明,而精确的函数组合在一起,加上的概念,整个软件体系的精确性也很轻易保证;
在反复实验和测试函数的过程,就十分有必要有一个可以输个函数得到一个值的盘算器。那些支持F#开发的环境,很轻易就设置一个F# Interactive,比如Rider中Shift+Shift,Start F# Interactive就是这个样子:

在下面的提示符里面就能输入命令,帮助命令输入
   #help;;
  通过帮助可以看到,F# 交互窗口指令:
  1. #r "file.dll";;                               // 引用(动态加载)给定的 DLL
  2. #i "package source uri";;                     // 搜索包时包含包源 uri
  3. #I "path";;                                   // 为被引用的 DLL 添加给定搜索路径
  4. #load "file.fs" ...;;                         // 像已编译和被引用的文件一样加载给定的文件
  5. #time ["on"|"off"];;                          // 启用/停止计时
  6. #help;;                                       // 显示帮助
  7. #r "nuget:FSharp.Data, 3.1.2";;               // 加载 Nuget 包 'FSharp.Data' 版本 '3.1.2'
  8. #r "nuget:FSharp.Data";;                      // 加载 Nuget 包 'FSharp.Data' 具有最高版本
  9. #clear;;                                      // 清除屏幕
  10. #quit;;                                       // 退出
复制代码
帮助还会告诉你,F# 交互窗口命令行选项:
  1.   请参阅“dotnet fsi --help”以了解各个选项
复制代码
总之,我们能够通过运行上面的命令运行一个开发环境,我们也能通过dotnet fsi filename.fsx来执行一个脚本。
盘算器

第一个作用:当然是高级盘算器。
比如,小朋侪问:1+2+3+…+100等于多少?
  1. [1..100] |> List.sum;;
复制代码
马上就有val it: int = 55。这个问题可以口算,但是更大的数字怎么办?你说你还是能口算……那算我没说。
上面这里有个奇怪的东西|>,这是一个运算符(术语:管道),实在很简朴,就是
  1. List.sum [1..100];;
复制代码
这么写是因为可以连着写,用|>,比如,100以内所有能被3整除的数和是多少?
  1. [1..100]
  2. |> List.filter (fun i -> i % 3 = 0)
  3. |> List.sum;;
复制代码
得到:
  1. val it: int = 1683
复制代码
还可以更加复杂:
                                         1                            −                                       1                               2                                      +                                       1                               3                                      −                                       1                               4                                      +                            …                                  1 - \frac{1}{2} + \frac{1}{3} - \frac{1}{4} + \ldots                     1−21​+31​−41​+…
  1. [1..1000000]
  2. |> List.map (fun i-> (-1.0) ** (float i+1.0) / float i)
  3. |> List.sum;;
复制代码
盘算                                   π                              \pi                  π

利用交互式盘算器,可以办理所有小学生的奇怪盘算。下面就来点严肃的,盘算一下                                   π                              \pi                  π。
利用的加拿大滑铁卢大学的Bouweins提出的公式。
                                                                                                                                                                             y                                           0                                                      =                                                       2                                                      −                                        1                                        ,                                                       α                                           0                                                      =                                        6                                        −                                        4                                                       2                                                                                                                                                                                                                            y                                           n                                                      =                                                                       1                                              −                                              (                                              1                                              −                                                               y                                                                   n                                                    −                                                    1                                                                  4                                                                               )                                                                   1                                                    /                                                    4                                                                                                           1                                              +                                              (                                              1                                              −                                                               y                                                                   n                                                    −                                                    1                                                                  4                                                                               )                                                                   1                                                    /                                                    4                                                                                                                                                                                                                                                                            α                                           n                                                      =                                        (                                        1                                        +                                                       y                                           n                                                                     )                                           4                                                                     α                                                           n                                              −                                              1                                                                     −                                                       2                                                           2                                              n                                              +                                              3                                                                                    y                                           n                                                      (                                        1                                        +                                                       y                                           n                                                      +                                                       y                                           n                                           2                                                      )                                                                                                                                                                                               π                                        =                                                                       lim                                              ⁡                                                                          n                                              →                                              ∞                                                                                    1                                                           α                                              n                                                                                                             \begin{split} &y_0 = \sqrt{2}-1, \alpha_0=6-4\sqrt{2}\\ &y_{n} = \frac{1-(1-y_{n-1}^4)^{1/4}}{1+(1-y_{n-1}^4)^{1/4}}\\ &\alpha_n = (1+y_n)^4\alpha_{n-1}-2^{2n+3}y_n(1+y_n+y_n^2)\\ &\pi = \lim_{n\to\infty}\frac{1}{\alpha_n} \end{split}                     ​y0​=2                     ​−1,α0​=6−42                     ​yn​=1+(1−yn−14​)1/41−(1−yn−14​)1/4​αn​=(1+yn​)4αn−1​−22n+3yn​(1+yn​+yn2​)π=n→∞lim​αn​1​​
这个盘算方法非常厉害,只必要迭代15次,精度就能到达20亿位。
那么我们编辑一个fsx文件:
  1. let sqrt (x: decimal) n =
  2.     let rec _sqrt (x: decimal) (rn: decimal) n =
  3.         match n with
  4.         | 0 -> rn
  5.         | _ -> _sqrt x ((rn + x / rn) * 0.5m) (n - 1)
  6.     _sqrt x (x / 3m) n
  7. let quad (x: decimal) = sqrt (sqrt x 32) 32
  8. let sqrt2 = sqrt 2m 32
  9. let yp (y: decimal) =
  10.     let y' = 1.0m - y * y * y * y
  11.     let y'' = quad y'
  12.     (1m - y'') / (1m + y'')
  13. let ap (alpha: decimal) (y: decimal) (n: int) =
  14.     let term1 = (1m + y) * (1m + y) * (1m + y) * (1m + y) * alpha
  15.     let term2 = 2.0 ** (2.0 * float n + 1.0)
  16.     let term3 = y * (1m + y + y * y)
  17.     term1 - (decimal term2) * term3
  18. let alpha n =
  19.     let rec y_a n =
  20.         match n with
  21.         | 0 -> sqrt2 - 1m, 6m - 4m * sqrt2
  22.         | _ ->
  23.             let y_1, alpha_1 = y_a (n - 1)
  24.             let y = yp y_1
  25.             let a = ap alpha_1 y n
  26.             y, a
  27.     let _, a = y_a n
  28.     1m / a
  29. seq {0..10}
  30. |> Seq.map (fun i -> i, alpha i)
  31. |> Seq.iter (fun (i, pi) -> printfn $"%4i{i}\t%A{pi}")
复制代码
为了得到更多的有效精度,我们接纳了decimal数据,这个数据类型最少可以确保28位的精确盘算。
首先我们定义了一个参数是decimal的开方运算符,因为.NET针对这个数据类型只有加减乘除等运算,没有开方。
接纳迭代法:
                                                    x                               0                                      =                            a                            /                            3                                                x                                           n                                  +                                  1                                                 =                                       1                               2                                      (                                       x                               n                                      +                                       a                                           x                                  n                                                 )                                                a                                      =                                                   lim                                  ⁡                                                      n                                  →                                  ∞                                                            x                               n                                            x_0 = a/3 \\ x_{n+1} = \frac{1}{2}(x_n + \frac{a}{x_n})\\ \sqrt{a} = \lim_{n\to\infty}x_n                     x0​=a/3xn+1​=21​(xn​+xn​a​)a             ​=n→∞lim​xn​
这里使用了尾递归,而不接纳循环。在F#中,尾递归会被编译器优化为循环,以是不用担心性能问题和栈溢出问题。
从下面的代码可以看到,F#在体例步伐时,会把一小段一小段数学形貌实现为一个个函数,如许的代码更加清晰,更加轻易理解。
总结


  • F#可以作为一个交互式盘算器,可以办理所有小学生的奇怪盘算。
  • 利用F#很直观地实现数学表达式,所接纳的代码不接纳循环、不使用变量,而是接纳递归,这是函数式编程的典型思考方式。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

三尺非寒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表