r中的索引,有些问题

时间:2017-01-03 09:25:03

标签: r function for-loop indexing

我创建了函数dystdystryb

dyst<- function(t,x)
{
  f<-1
  return(f)
}
dystryb<- function(x)
{
  x<-sort(x)
  s<- numeric(101)
  u<-seq(0,1, by = 0.01)
  for (t in u)
  {
    s[t*100+1]<-dyst(t,x)
  }
  return(s)
}

调用函数dystryb后,我得到了这个:

> x<-c(1,2,3,4,5,6,7)
> dystryb(x)
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [51] 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[101] 1

为什么这个函数不能用于参数30和59?当然,这不是关于制作一个“1”矢量的函数,但我想说清楚问题出在哪里。

2 个答案:

答案 0 :(得分:1)

根本原因是数值精度。有关与R相关的讨论,请参阅此SO post。 @ Dirk-eddelbuettel包含的链接提供了R的背景和一般涉及计算数值精度的最相关的论文之一。 This post提供了与此问题背后的计算机科学有关的SO的更详细的一般答案。

要显示根本原因是数值精度,请考虑您已创建的序列。首先,默认打印出序列。

print(seq(0,1, by = 0.01) * 100 + 1)
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19
 [20]  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38
 [39]  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57
 [58]  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76
 [77]  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95
 [96]  96  97  98  99 100 101

一切看起来都不错。现在,打印出你的序列,告诉R显示16位数字。

print(seq(0,1, by = 0.01) * 100 + 1, digits=16)
  [1]   1.000000000000000   2.000000000000000   3.000000000000000
  [4]   4.000000000000000   5.000000000000000   6.000000000000000
                                  ...
 [25]  25.000000000000000  26.000000000000000  27.000000000000000
 [28]  28.000000000000000  29.000000000000004  29.999999999999996
 [31]  31.000000000000000  32.000000000000000  33.000000000000000
 [34]  34.000000000000000  35.000000000000000  36.000000000000000
 [37]  37.000000000000000  38.000000000000000  39.000000000000000
 [40]  40.000000000000000  41.000000000000000  42.000000000000000
 [43]  43.000000000000000  44.000000000000000  45.000000000000000
 [46]  46.000000000000000  47.000000000000000  48.000000000000000
 [49]  49.000000000000000  50.000000000000000  51.000000000000000
 [52]  52.000000000000000  53.000000000000000  54.000000000000000
 [55]  55.000000000000000  56.000000000000007  57.000000000000007
 [58]  58.000000000000007  58.999999999999993  60.000000000000000
                               ...
[100] 100.000000000000000 101.000000000000000

你看到&#39; 30&#39;存储的值为29.999999999999996和&#39; 59&#39;存储值58.999999999999993。现在,如果我们将此序列转换为整数,我们将获得以下输出。

print(as.integer(seq(0,1, by = 0.01) * 100 + 1))
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19
 [20]  20  21  22  23  24  25  26  27  28  29  29  31  32  33  34  35  36  37  38
 [39]  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57
 [58]  58  58  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76
 [77]  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95
 [96]  96  97  98  99 100 101

此强制函数将29.999999999999996转换为29和58.99999999999999993至58,基本上执行截断。因此,在您的代码中,第29和第58个元素被引用两次,而第30和第59个元素根本没有被引用。

在这种情况下,输出与使用floor功能相同。

identical(trunc(seq(0,1, by = 0.01) * 100 + 1), floor(seq(0,1, by = 0.01) * 100 + 1))
[1] TRUE

您的特定问题的一个解决方案是在将序列转换为整数之前使用round

identical(1:101, as.integer(round(seq(0,1, by = 0.01) * 100 + 1)))
[1] TRUE

答案 1 :(得分:1)

以下显示究竟发生了什么,由于浮点精度误差,您将在位置15,29处有零...

which(seq(0,1, by = 0.01)*100+1 != 1:101)
# [1] 15 29 30 56 57 58 59