【问题标题】:In Fortran, what is the best way to choose a non-zero element at random from an array?在 Fortran 中,从数组中随机选择非零元素的最佳方法是什么?
【发布时间】:2020-05-27 00:53:13
【问题描述】:

我有一个整数的一维数组,在某些索引处具有非零值,其余为零。非零值等于索引。例如:

CHOOSEARRAY = (/0,0,0,4,0,6,7/)

我想从这个数组中随机选择任何非零元素。在这种情况下,我希望输出为 4,6 或 7 的概率相等。

我目前的方法有点复杂,工作方式如下:

计算可用选项的数量

NCHOICE = COUNT(CHOOSEARRAY.NE.0)

创建一个数组,并用非零值填充它

ALLOCATE(CHOICES(NCHOICE))
CHOICES = PACK(CHOOSEARRAY,CHOOSEARRAY.NE.0)

从这个新数组中选择一个随机元素

CHOSENVAL = CHOICES(FLOOR(1+GRND()*NCHOICE))

这里,GRND() 是一个随机数生成函数,输出一个均匀分布在 0 和 1 之间的实数。

此代码块必须重复多次,需要多次分配和解除分配操作,这可能很耗时。有没有更好的方法来解决这个问题?

或者,有没有办法返回随机选择的非零元素的索引?例如(/0,1,1,0,0,1/) 应该以相等的概率给出 2,3 或 6。

【问题讨论】:

  • 您可以在没有 choices 分配的情况下执行此操作,但您是否对此进行了分析以确定分配成本对您的案件或利益是否重要?
  • 你知道有多少个非零元素吗?
  • @IanBush,先验未知,因此分配和释放。
  • @francescalus 我没有对此进行分析,但该操作发生了超过 10,000 次。我的假设是,分配和解除分配通常不是提高速度的好主意。

标签: arrays indexing fortran


【解决方案1】:

如果您不害怕被零除数,这可能会很有吸引力。首先,让我们有一些随机数...

REAL, DIMENSION(SIZE(choosearray)) :: rands
CALL RANDOM_NUMBER(rands)

那么我们可以通过表达式从choosearray获取随机非零元素的位置

MAXLOC(rands * choosearray/choosearray)

然后用

得到它的值
choosearray(MAXLOC(rands * choosearray/choosearray))

我会留给你测试这个速度。

【讨论】:

  • 非常有趣的方法!我会尝试一下,看看效果如何。
  • 好的,这种方法似乎效果最好。我修改了我的选择数组,使其具有 1 或 0。乘以相同大小的随机数组并选择最大元素的位置非常有效。
【解决方案2】:

这取决于您的优化目标:速度、空间还是代码的可读性?

如果有空格,你可以数零的个数,然后从数组的长度中减去(只占用一个整数),然后生成一个介于 1 和 n 之间的随机索引 n,然后找到第 n 个非数组中的零个数。这大约是 O(2n)。

如果速度快,您可能应该遍历数组,边走边复制非零值,然后从结果数组中随机选择(它需要与原始数组的大小相同以容纳所有值) - 这是 O (n),但消耗与原始数组相同的内存量。

实际上是否更快取决于执行复制操作与读取操作的速度。 'big oh' 仅告诉您算法的顺序,您必须进行测试才能知道您使用的操作是否真正带来了您期望的好处。

【讨论】:

  • 感谢您的回答!我主要在这里优化速度。我不确定第二个建议将如何实施。假设我通过复制非零值得到一个数组 (/1,4,7,0,0,0,0/),但我如何随机选择一个?
猜你喜欢
  • 2018-12-03
  • 1970-01-01
  • 1970-01-01
  • 2012-02-26
  • 2015-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多