цикл for делает паузу каждые 8 миллионов итераций — почему?

#java

#java

Вопрос:

Когда я запускаю следующий код в Intellij с вводом 1000000000000, процесс задерживается на мгновение каждые 8 миллионов циклов.

Почему это так? Почему не выполняется в одном плавном потоке до конца?

 import java.util.*;

public class Main {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("Please type a number");
        long n = in.nextLong();
        System.out.println("Thanks.");

        long count = 0;
        for (long i=0; i<=n; i  ) {
            if ((n i) == (n^i)) {
                count  ;
                if (count % 1000000 == 0)
                System.out.println(count);
            }
        }
        System.out.println(count);
    }
}
  

Комментарии:

1. Как вы определили «паузу»?

2. Просто смотрю на стандартный вывод. Он останавливается каждые 8 миллионов итераций.

3. @RichArt это не «останавливается» каждые 8 миллионов итераций. Он все еще работает. Просто вы печатаете что — то только раз в миллион раз больше (n i) == (n^i) .

4. Да, но дело в том, что он печатает до 8 миллионов, а затем останавливается, затем снова печатает до 16 миллионов и снова останавливается, и так далее.

5. @AndyTurner Я полагаю, что он это понимает. У меня сложилось впечатление, что он говорит, что каждое восьмое печатное заявление, кажется, занимает больше времени, чем предыдущие 7.

Ответ №1:

Условие

 (n   i) == (n ^ i)
  

будет происходить в основном, когда в and нет перекрывающихся битов n i , поскольку в этом случае сложение и XOR — это, по сути, одно и то же.

Например, если n == 4 и i == 3 , то в двоичном n == 100 и i == 011 , так

  n   i == 100   011 == 111 == 7
 n ^ i == 100 ^ 011 == 111 == 7
  

Я не уверен, что нет чисел с общими битами, для которых также выполняется условие; но это «очевидные» случаи, для которых это верно.

Двоичная форма 1000000000000 равна

 1110100011010100101001010001000000000000
  

Наименее значимым установленным битом здесь является 12-й бит (начиная с нулевого справа).

12-я степень 2 равна 4096. Итак, все числа меньше 4096 не имеют общих битов с n , поэтому вы будете считать все числа 0-4095. С этого момента вы будете считать только те числа, для которых не установлен 12-й бит. Таким образом, скорость подсчета чисел будет замедляться.

Затем вы попадете на 16-й LSB. Теперь вы будете считать только числа без набора 12-го и 16-го битов. Таким образом, скорость подсчета чисел еще немного замедлится.

и т.д. и т.п.

Единственная причина этих «пауз» заключается в том, что внешний цикл for наивно перебирает все числа вплоть до n : он не просто переходит к следующему числу, для которого выполняется условие.

Комментарии:

1. И вы можете увидеть, что это действительно так, запустив программу с вводом, скажем, 1048576, который равен 1 << 20 и, следовательно, имеет все младшие биты равными нулю.

2. @Andy: вы написали: «Я не уверен, что нет чисел с общими битами, для которых также выполняется условие». Можете ли вы привести пример? Я не могу понять, что вы имеете в виду.

3. @RichArt если бы я мог привести пример, я был бы убежден, что такой пример существует! Возможно, этого не может быть; Я просто не хочу этого утверждать, потому что я не склонен это доказывать.

4. @RichArt Нет, время вычисления выражения здесь не оказывает существенного влияния. Просто есть все более и более длинные «пробелы», где ничего не печатается, потому что выражение вычисляется false .

5. @RichArt да, это так просто.