Как получить все варианты массива с элементами равными нулю или единице

Я собираюсь написать цикл do для возможных значений элементов массива. В частности, у меня есть массив, скажем, A(:) размера n, и любой элемент массива A может быть 0 или 1. Я хочу перебрать все возможные значения элементов A. Конечно, простой способ

do A(1)=0, 1
 do A(2)=0, 1
  ....
   ! do something with array A

 end do 
end do 

но размер моего массива большой и этот способ не очень подходит. Есть лучший способ это сделать?


person Math-fort    schedule 25.03.2016    source источник
comment
Я не уверен, что получил вопрос... Вы хотите иметь все возможные варианты массива с элементами, равными нулю или единице? Например: 00, 01, 10, 11 для массива длины два?   -  person Alexander Vogt    schedule 25.03.2016
comment
Уважаемый Александр, Да, именно так. Я хочу иметь все возможные варианты массива с элементами, равными нулю или единице. Но для экономии памяти не хочется сохранять все возможные конфигурации в Матрице большего размера.   -  person Math-fort    schedule 25.03.2016
comment
Насколько большим будет массив?   -  person Alexander Vogt    schedule 25.03.2016
comment
2^30 конфигураций. Действительно, размер A(:) равен 30, и, таким образом, общее количество конфигураций равно 2^30.   -  person Math-fort    schedule 25.03.2016
comment
Также обратите внимание, что вы не должны изменять индекс цикла внутри цикла! Кроме того, вы не можете использовать элементы массива в качестве счетчика циклов.   -  person Alexander Vogt    schedule 26.03.2016
comment
Связано (хотя и не для двоичных, а для произвольных значений): /questions/22285705/ и stackoverflow.com/questions/35544443/ и заголовок stackoverflow.com/questions/24364332/.   -  person Alexander Vogt    schedule 26.03.2016


Ответы (1)


Поскольку это только двоичный код, почему бы (неправильно) использовать целые числа для этой задачи? Просто увеличьте целое число на единицу для каждой из комбинаций и прочитайте соответствующие биты, используя btest:

program test
  implicit none
  integer, parameter  :: n = 3
  integer             :: i
  integer             :: A(n)
  integer             :: idx(n) = [(i, i=0,n-1)] ! bit positions start at zero

  ! Use a loop to increment the integer
  do i=0,2**n-1
    ! Get the bits at the lowest positions and map true to "1" and false to "0"
    A = merge( 1, 0, btest( i, idx ) )
    print *,A
  enddo
end program

Этот простой код заполняет A всеми комбинациями (по одной за раз) и печатает их последовательно.

./a.out 
           0           0           0
           1           0           0
           0           1           0
           1           1           0
           0           0           1
           1           0           1
           0           1           1
           1           1           1

Обратите внимание, что Фортран поддерживает только целые числа со знаком, поэтому старший бит здесь не используется. Это оставляет вам до 2^(32-1) комбинаций для (по умолчанию) 4-байтовых целых чисел, если вы начинаете с нуля, как показано здесь (длина массива до 31).

Чтобы получить полный диапазон, выполните цикл следующим образом:

  do i=-huge(1)-1,huge(1)

Это дает вам полные 2^32 различных вариантов для массивов длиной 32.

person Alexander Vogt    schedule 25.03.2016
comment
спасибо за интересное решение. В будущем мне придется обобщить свой код для недвоичных значений. Есть ли аналогичный трюк, если значения A(i) равны 0,1,...,M.? - person Math-fort; 26.03.2016
comment
@Math-fort Да, но на это общее решение был дан ответ, например, здесь :) - person Alexander Vogt; 26.03.2016
comment
Уважаемый Александр, Есть ли способ обработки массива длиной 2^(32)? спасибо, :-( - person Math-fort; 26.03.2016