ArrayIndexOutOfBounds после решения проблемы «возможной потери точности» ошибка компиляции

#java #arrays #long-integer

#java #массивы #длинное целое число

Вопрос:

работает: означает отсутствие ошибки точности :: Просто массив выходит за пределы

 long a[] =new long[1000000];
int no=2,n;
long i;
a[no]=i a[n];
if(a[no]>longChain)
{
    longChain = a[no];
    startNo = no;
}
  

и когда я делаю

 long a[] =new long[1000000];
long no=2,n;
long i,longChain=1,startNo;
a[no]=i a[n];
if(a[no]>longChain)
{
    longChain = a[no];
    startNo = no;
}
  

затем потеря точности

найдено: long

требуется: int

в чем проблема?

Мой код для вышеупомянутой проблемы, его проблема с ProjectEuler № 14

 class P14
{
    public static void main(String args[])
    {
        long a[] =new long[1000000];
        long no=2,n;
        long i,longChain=1,startNo;
        a[1]=1;
        while(no<1000000)
        {
            n=no;
            i=0;
            while(n>no-1)
            {
                if(n%2==0)
                    n=n/2;
                else
                    n=3*n 1;
                i  ;
                //System.out.println(n);
            }
            a[no]=i a[n];
            if (a[no] > longChain)
            {
                longChain=a[no];
                startNo=no;
            }
            no  ;
            //System.out.println(no);
        }
    }
}
  

Это мой код для того, где возникает вышеуказанная проблема

Ответ:: Замените [no] на [(int)n]

a[n],a[(int)n]

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

1. Пожалуйста, найдите время, чтобы правильно сделать отступ в вашем коде, чтобы форматирование блоков кода работало. Прямо сейчас читать ваш вопрос утомительно.

2. Вы не можете описать код, который становится ArrayIndexOutOfBounds рабочим. Ни один из опубликованных вами кодов даже не компилируется. На вопрос нельзя ответить в его текущей форме.

3. @EJP нет ошибок точности, вот что я имел в виду под работой, но ты прав, отредактировал мой вопрос

4. «Компилирует» — это не то же самое, что «работает». Ваш код по-прежнему не компилируется. Я предлагаю вам скопировать и вставить ваш фактический код, не пытайтесь его вводить.

5. @EJP Я опубликовал исходный код

Ответ №1:

ваши переменные no и n должны быть int, а не long . Массивы не могут быть проиндексированы long . Изменение кода на:

 int no=2,n;
  

заставляет код компилироваться.

Исключение ArrayIndexOutOfBoundsException вызвано тем, что вы написали алгоритм, предполагая, что он был длинным.

Этот код в конечном итоге приведет n к тому, что он станет отрицательным:

 n=3*n 1;
  

Трудно понять, почему, когда вы выполняете целочисленную арифметику. Небольшое изменение, чтобы заставить код использовать длинную арифметику и распечатать промежуточный результат, показывает, когда именно он становится отрицательным и как:

 while(n>no-1)
{
    long newN = n;

    if (n % 2 == 0) newN = newN / 2L;
    else newN = 3L * newN   1L;

    if (newN > Integer.MAX_VALUE) System.out.println("about to fail");

    //this is where the magic happens
    n = (int)newN;
    System.out.println("converted "   newN   " to "   n);

    i  ;
}
  

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

1. затем возникает исключение ArrayIndexOutOfBoundsException

2. хорошо, я должен буду использовать еще одну переменную, я полагаю, я буду обновлять по мере проверки

3. хорошо, спасибо, я использовал long nL; а затем после цикла я сохранил его в n; Моя программа работает!!!

4. Я только что закончил писать пример того, почему n становится отрицательным, чтобы подробнее объяснить, что происходит 🙂

Ответ №2:

Вероятно, это связано с тем, что индексация массива принимает an int в качестве индекса. Но все ваши переменные имеют тип long .

 a[no]
  

no является long .

Таким образом, использование long в качестве индекса массива является неявным понижением, что может привести к потере точности.

Итак, либо вы вручную отбрасываете его, либо меняете no на int .

РЕДАКТИРОВАТЬ: (после дополнительной информации в вопросе)

Я не уверен на 100%, является ли это причиной:

 n=3*n 1;
  

Вы используете n as в индексе. Но n для начала может стать довольно большим. Таким образом, a *3 может сделать его больше, чем размер массива.

Вероятно, вам следует перепроверить, каким бы ни был ваш алгоритм. (что я не могу понять из самого кода)

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

1. Вы никогда не инициализировали i и n . На что они установлены?

2. i, n инициализируются в цикле while, который я опубликовал исходный код

3. да, n станет очень большим, но оно опустится ниже 1000 000 до завершения цикла while

4. Когда вы получаете исключение за пределами, оно должно сообщить вам, к какому индексу вы пытались получить доступ?

5. спасибо, вы были правы, n = 3 * n 1; была причиной, так как n стало -ve , и вышел из цикла while, а затем попытался сохранить значение по индексу -ve

Ответ №3:

Проблема, с которой вы сталкиваетесь, заключается в том, что вы не можете сохранить все возможные значения, которые вы вычисляете в массиве. Числа могут вырасти за пределы 2 ^ 31-1, и вы получите переполнение.

Что вы можете сделать, это сделать

 long n;
  

и

 while (n > no - 1 || n >= a.length) {

}
// is safe as n < a.length;
a[no] = i   a[(int) n];
  

Это гарантирует, что вы будете искать только кэшированные значения, которые находятся внутри вашего массива.

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

1. @CoolEulerProject Итак, ваш индекс массива выходит за рамки. Итак, ваш алгоритм неверен.

2. Я опубликовал свой алгоритм, его проблему с ProjectEuler14

3. спасибо, да, индекс массива увеличился на n = n * 3 1 за пределы емкости массива Java, поэтому мне пришлось заменить [no] на [(int) no] и [n] на [(int) n], так как n, no оба были длинными… или используйте другую переменную, содержащую n int

Ответ №4:

n должно быть длинным, потому что оно может стать слишком большим для int. (Если вы используете int, он переполнится отрицательными числами и вызовет исключение ArrayIndexOutOfBoundsException .)

Вы должны объявить n as long и преобразовать его в int при использовании его в качестве индекса ( no может быть int)

 a[no]=i a[(int)n];