开始使用Nim(二)

来源:互联网 发布:网站流量统计软件 编辑:程序博客网 时间:2024/06/02 05:50


原文:https://akehrer.github.io/nim/2015/01/14/getting-started-with-nim-pt2.html


       上一次写了关于我学习Nim的兴趣为了增强我的技能,并且以创建一个简单的统计模块开始。我们跳过了一些的学习语言的细微差别,以建立一个高斯分布模型为开始。今天我们来看看一些事情,我发现我弄懂了在模块中的其他一些过程。


NaN


       在内嵌的math 模块中一些过程以NaN作为返回值,但是我不能在Nim中找到一种容易的方法验证它。幸好math.h 标准库包含 isnan()过程,我们能够重用它。在这种情况下我创建了一个附加过程,从C过程把整型结果转换为布尔型。你能看到我用我的代码创建了一个NAN常量。

import mathconst  NAN = 0.0/0.0 # floating point not a number (NaN)proc cIsNaN(x: float): int {.importc: "isnan", header: "<math.h>".}  ## returns non-zero if x is not a numberproc isNaN*(x: float): bool =  ## converts the integer result from cIsNaN to a boolean  if cIsNaN(x) != 0: true  else: false

More Statistics


随着NaN问题的解决,我开始写更多的描述统计的过程,比如mediankurtosis和 quantile.下面是median的代码:


import algorithm  # needed for `sort`proc median*(x: openArray[float]): float =   ## computes the median of the elements in `x`.   ## If `x` is empty, NaN is returned.    var sx = @x # convert to a sequence since sort() won't take an openArray  sx.sort(system.cmp[float])    try:    if sx.len mod 2 == 0:      var n1 = sx[(sx.len - 1) div 2]      var n2 = sx[sx.len div 2]      result = (n1 + n2) / 2.0    else:      result = sx[(sx.len - 1) div 2]  except IndexError:    result = NAN

       · median 过程用一个openArray 类型作为它的输入,与math 模块中mean 过程是相似的。Nim中的Open arrays 使不同大小的数组能够传入到过程。openArray类型有一些基本的操作符可以使用,但是我们不能传送一个openArray类型到sort过程,因此我们首先要把它转换为一个序列(通过使用 @功能在 x 上)。

     ·当计算排序后的序列的下标是使用了div 过程,因为它做的是整数除法,不像 / 会得到一个float值。

      · Nim有一个与python 相似的 try....except 语法,它用在这是为了捕获空数组被传进这个过程中。

      ·同样记录我们上面创建的正在使用的NAN常量。


现在我们有一个正在工作的median 过程,让我们添加一些测试:

when isMainModule:  # Setup some test data  var data1: array[0..6, float]  var data2: array[0..7, float]  var data3 = newSeq[float]()  var data4: array[1, float]  var data5: array[2, float]  data1 = [1.4, 3.6, 6.5, 9.3, 10.2, 15.1, 2.2]  data2 = [1.4, 3.6, 6.5, 9.3, 10.2, 15.1, 2.2, 0.5]  data4 = [2.3]  data5 = [2.2, 2.5]    # Test median()  assert(abs(median(data1) - 6.5) < 1e-8)  assert(abs(median(data2) - 5.05) < 1e-8)  assert(isNaN(median(data3)))  # test an empty sequence  assert(abs(median(data4) - 2.3) < 1e-8)  assert(abs(median(data5) - 2.35) < 1e-8)

       得到的值是浮点数,我们不能用 "== "测试,我也回去和确定了在第一篇中用于GaussDist的测试。


       当我使用其它过程时我遇上了Nim的静态类型,有时代码看起来足够像python以至于我忘记检查过程正在使用的适当类型。下面是以quantile过程作为例子的代码:

1 proc quantile*(x: openArray[float], frac: float): float =  2   ## Computes the quantile value of `x` determined by the fraction `frac` 3   ## If `x` is empty, NaN is returned. 4   ## `frac` must be between 0 and 1 so for the 25th quantile  5   ## the value should be 0.25, any other value returns `NaN` 6   if x.len == 0: 7     result = NAN   8   elif frac < 0.0 or frac > 1.0: 9     result = NAN10   elif frac == 0.0:11     result = x.min12   else:13     var sx = @x # convert to a sequence since sort() won't take an openArray14     sx.sort(system.cmp[float])15 16     var n = sx.len - 1  # max index17     var i = int(math.floor(float(n) * frac))  # quantile index18 19     if i == n:20       result = sx[n]21     elif sx.len mod 2 == 0:22       # even length23       var n1 = sx[i]24       var n2 = sx[i+1]25       result = (n1 + n2) / 2.026     else:27       # odd length28       result = sx[i]

         你能够看到在17行,我们需要在n与 frac(a float) 相乘前把n转换为一个float型。这是因为Nim 将不会自动的转换一个int型到float型[ref]。结果然后再转换为int 型,所以它才能作为一个序列的标号。值得庆幸的是当程序运行错误时Nim会提供有用的反馈,还会试着指出正确的方向。这里是没有把n转换为float时编译出现的错误。

Error: type mismatch: got (int, float)but expected one of:system.*(x: set[T], y: set[T]): set[T]system.*(x: int, y: int): intalgorithm.*(x: int, order: SortOrder): intsystem.*(x: int64, y: int64): int64system.*(x: int32, y: int32): int32system.*(x: int8, y: int8): int8system.*(x: float, y: float): floatsystem.*(x: float32, y: float32): float32system.*(x: int16, y: int16): int16

        所以可以看到 *过程需要的是两个相同类型的参数,但是它得到了一个int型和一个float型。解决这个问题程序将能正确运行。


       总而言之,我喜欢目前已经了解到的Nim。我感觉它是容易学会和开始的。它的文档是充足的但是还不完整,这对于一个年轻的语言来说并不奇怪。到目前为止,我使用它更像是在编译python,还没有太深入其独特的特性。对于它是否可以用来创建python模块,这将是有趣的,也许能通过cython接口。但这是之后要做的事。

你能在这里找到我的 nim-statistics 模块代码。


Reference


Part 1




1 0