在Fortran代码中,我有一个数组a
,其值的范围从0.0
到1.2
一致,我正在寻找最接近1.0
的值的索引。
Fortran中似乎没有任何内部函数可以做到这一点,所以我用MINLOC做了一个巧妙的变通方法:(注意temp
和a
的形状相同)
do i=1,n
temp(i) = 1.0 - a(i)
end do
loc = 0 !note that loc is an integer array, declared as 'loc(1)'
index_1 = minloc(abs(temp(:))) !this is the index of a closest to 1.0
这似乎奏效了。
我对实现这一点的其他方法感兴趣,所以有几个问题:
- MINLOC是如何工作的
- 是否有其他例程可以直接到达那里(即不必制作第二个数组)
- 其他语言是如何处理的
谢谢。
EDIT:我之前链接到这篇文章,称其为寻找MINLOC
替代品的部分动机,但由于一些评论者指出它有些无关紧要,因此已将其删除。包括它似乎有损于我的目标,即寻找这种方法的替代品。
这不会比您的解决方案运行得更快,但它确实缩短了代码:
index_1 = minloc(abs(a - 1))
虽然您不必以这种方式自己设置临时数组,但编译器仍将在幕后进行设置。MINLOC是靠蛮力工作的:没有找到最小值的捷径。
如果您需要在此数组中重复搜索不同的值,那么首先对数组a
进行排序,然后执行二进制搜索会快得多。这将把运行时间从O(n)减少到O(log(n)),其中n是a
的大小。
首先要注意的是,链接的文章并没有批评MINLOC
本身的性能,而是批评它发现了特定值的性能。
在Fortran 2008中,有一个用于此目的的内在FINDLOC
,但它可能不适合这个问题。然而,对于参考文章中的问题,这将是正确的做法。另请参阅Fortran findloc内部
速度缓慢的一个原因是,在调用MINLOC(abs(temp(:)))
时,必须为abs(temp(:))
创建一个临时数组。另一个原因是,当找到匹配项时,文章中的循环可以立即退出。然而,这对您的申请并不重要。
内在的MINLOC
本身可能并不慢,它只是在一个简单的循环中搜索数组。
这些结果在编译器之间也会有所不同。你检查编译器的性能差异了吗?
最后的建议是:只需编写一个简单的循环,避免使用临时数组。
用于查找最近浮点元素的简单循环。简单的CS101东西。
min_diff = huge(1.0)
idx = 0
do i = 1, size(a)
diff = abs(a(i)-to_find)
if ( diff < min_diff) then
idx = i
min_diff = diff
end if
end do