ArrayExceptionOutOfBounds when returning the method - java

I am attempting to create a fillArray method that fills and array with 20 random values and sums every third value. I am getting an ArrayExceptionOutOfBounds at line 21 which is when the method is called. Through the debug I have watched the array fill with proper values and the sum properly calculated. I am wondering what the error is.
public static void fillArray(){
//adding up A[0], A[3], A[6}, ...
double[] A = new double[20];
for(int i = 0; i < A.length; i++)
A[i] = Math.random();
double sum = 0;
int k = 0;
do{
k += 3;
sum += A[k];
}while(k < 20);
System.out.println("sum = " + sum);
}
Again I am looking to determine the reason for the error not necessarily a way to fix it.

Here is your problem:
do{
k += 3;
sum += A[k];
}while(k < 20);
K will be equal to 0, then 3, then 6, etc, up until it reaches 21 and then you try and access A[21] which is out of bounds.
This is because when k = 18 on the 6th iteration of the while loop, (k < 20) is true and therefore the while loop continues and adds another 3 to k making it 21. After that, the while loop stops as k is not less than 20 anymore leaving k with a value of 21.

You're getting the error because you're hitting 21 on a array with the size of 20. To fix:
do{
k += 3;
if(k <= 20){
sum += A[k];
}
}while(k < 20);

Your second loop, where you calculate the sum, is a do/while loop, meaning the condition will always get checked after the loop body is executed. You count k up in steps of 3, meaning it will reach 21 at some point before the while (k < 20) condition returns false, resulting in your error.

I think the problem is that k is incrementing and being used as an array index, before the <20 test.
something like this might work better:
for (int k = 0; k < 20; k = k + 3) {
sum += A[k];
}
In general, i think the do while construct here is a bit of unnecessary complexity. The version above is easier to read and is a more common pattern.

With the current logic, k will be 3,6,9,12,15,18 and 21. The last value is responsible for the out of bounds exception. Your loop will not stop at 18 as it is smaller than 20. You could resolve the bug by changing your code to this:
do{
k += 3;
sum += A[k];
}while(k < 18);

You increment the array index before using it. So you are not only going beyond the array index in last pass, you are also not adding the element at 0 index.

Related

How can I use a value from inside a for loop in Java?

I'm creating a method that's essentially trying to grab the mean of an array. I initialized an integer sum to 0 outside of the for loop, ran the for loop, and tried returning the sum.
This is what my code looks like:
int sum = 0;
for (int i = 0; i < array2.length; i++)
{
sum += array2[i];
return sum;
}
return sum / array2.length;
Upon running, it only returns the value I originally initialized sum to.
(I didn't include the code for array2, just assume I initialized it beforehand.)
int sum = 0;
for (int i = 0; i < array2.length; i++)
{
sum += array2[i]; // sum is increased, but only for i==0
return sum; // loop is left first time, making loop futile
}
return sum / array2.length; // never reached for length > 0
The problem is the return inside the loop, which cannot ever be what you want.
Just delete the return sum; to have the second return do what you intend it to,
i.e. loop over the length of the array, accumulate sum and after the loop retrn the average.
By the way, if you observe that sum is returned as initialised, it can be if array[0] is 0, otherwise not.

Manual array copy in a nested for loop

I trying to find all 2s, move them to the back of the array, and turn them into 0s without loosing the order of the array. For example, [1,2,3,2,2,4,5] would become [1,3,4,5,0,0,0]. My code works fine but the IDE is telling me that the nested for loop is copying the array manually and wants me to replace it with System.arraycopy(). How would I go about that?
Code looks like this:
int[] numbers = {1,2,3,2,2,4,5};
for (int i = 0; i < numbers.length; i++){
if (numbers[i] == 2){
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
numbers[numbers.length-1] = 0;
i --;
}
}
The following statement:
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
Can be replaced by:
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
IDEs like IntelliJ should suggest that automatically when you press alt + enter (default key combination).
Now about arraycopy()
From the documentation, java.lang.System.arraycopy() will copy n elements (last argument) from the source array (1st argument) to the destination array (3rd argument) with the corresponding indexes to start from (2nd and 4th arguments).
More specifically, when calling arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i) the arguments are:
numbers: The source array.
i + 1: The starting position in the source array.
numbers: The destination array.
i: The starting position in the destination data.
numbers.length - 1 - i: The number of array elements to be copied.
In your case, elements will be copied from your array, to itself, but the fact that source starting position is shifted from the destination starting position will induce the global shifting you're after (moving elements to the left).
About the number of elements to be moved, it should move i elements minus the first one that doesn't move and only gets overwritten. Hence the length - 1 - i.
The inner loop could be replaced with an arraycopy, however, you don't need an inner loop:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int i = 0; i < numbers.length; i++){
if (numbers[i] != 2){
numbers[j++] = numbers[i];
}
}
while (j < numbers.length) {
numbers[j++] = 0;
}
UPDATE
Or even:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int n: numbers){
if (n != 2){
numbers[j++] = n;
}
}
Arrays.fill(numbers,j,numbers.length,0);
The key thing is pretty simple: if you can reduce the lines of code you are responsible for (for example by using utility methods such as Arrays.arraycopy()) - then do that.
Keep in mind: each line that you write today, you have to read and understand tomorrow, and to probably modify in 5 weeks or months from now.
But then: I think you are over-complicating things here. I would use a temporary list, like this:
List<Integer> notTwos = new ArrayList<>();
int numberOfTwos = 0;
for (int i=0; i<source.length; i++) {
if (source[i] == 2) {
numberOfTwos++;
} else {
notTwo.append(source[i]);
}
}
... simply append `numberOfTwo` 0s to the list, and then turn it into an array
You see: you are nesting two for-loops, and you are repeatedly copying around elements. That is inefficient, hard to understand, and no matter how you do it: way too complicated. As shown: using a second list/array it is possible to "solve" this problem in a single pass.
After replacing your inner loop with System.arrayCopy the code should look like:
int[] numbers = { 1, 2, 3, 2, 2, 4, 5 };
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == 2) {
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
numbers[numbers.length - 1] = 0;
i--;
}
}

Formatting equations?

I'm new to Java, and I'm trying to format an equation with int elements in an array (I keep getting the error "not a statement"). This is the bit of code:
int n = 0;
int[] time = {mins, mins2, mins3, mins4, mins5};
for(int j = 0; j <= 3; j++){
if (time[j] < time[j+1]){
n = time[j];
}
}
for(int k = 0; k <= 4; k++){
time[k] - n;
}
I found the smallest int (all elements are from a random number generator), and now I want to subtract the smallest from every element and permanently change the elements of the given array to those smaller numbers. I don't know how to format the "time[k] - n;" segment correctly.
Thank you for your help.
The line:
time[k] - n
Does nothing. It takes the value time[k] and subtracts the value n from it. It then discards the result.
What you want is to subtract n from the variable and assign the result back to the same variable:
time[k] = time[k] - n
In Java, this is equivalent to a compound assignment operator:
time[k] -= n
If you have Java 8 you could in fact do:
int[] time = {mins, mins2, mins3, mins4, mins5};
int min = IntStream.of(time).min().getAsInt();
int[] normalised = IntStream.of(time).map(i -> i - min).toArray();
And even with earlier versions of Java I would recommend:
int[] time = {mins, mins2, mins3, mins4, mins5};
int n = Integer.MAX_VALUE;
for (int t : time) {
n = Math.min(n, t);
}
for (int i = 0; i < time.length; ++i) {
time[i] -= n;
}
i.e. use a foreach loop where you can and otherwise use the length property of the array rather than hardcoding the length.
Change time[k] - n; to time[k] =- n;. So it will store time[k] - n in time[k]

BitSet(JAVA) is throwing outofBoundsException in the implementation of Sieve Of Eratosthenes

Here is my function for the implementation of Sieve Of Eratosthenes,
void solve() throws IOException {
int n = 200000;
ArrayList<Integer> primes = new ArrayList<Integer>();
BitSet bs = new BitSet(n + 1);
for(int i = 0; i <= n + 1; i++)
bs.set(i);
//setting bits at 0 and 1 to 0, since these are not considered as primes
bs.clear(0);
bs.clear(1);
for(int i = 2; i <= n + 1; i++) {
if(bs.get(i)) {
//cross out multiples of i starting from i*i (lesser one would have always been crossed out)
for(int j = i*i; j <= n + 1; j += i)
{
bs.clear(j);
}
primes.add(i); //add this prime to the list
}
}
for(int e : primes)
out.println(e);
}
When I run this I get and arrayOutOfBoundsException during the inner for loop, i.e.
for(int j = i*i; j <= n + 1; j += i)
{
bs.clear(j); //EXCEPTION is raised here
}
Error Message that I am getting is:
Exception in thread "main" java.lang.IndexOutOfBoundsException: bitIndex < 0: -2146737495
at java.util.BitSet.clear(BitSet.java:532)
at ERATOSTHENES.solve(ERATOSTHENES.java:45)
I dont understand where is the problem, if I reduce n to 20000, then my code works fine, but after n = 168000 (approx.), it shows this OutofBoundsException.
Is it something specific to BitSet, some property that I am not getting?
You are initialising (in the worst case) the variable i to be a large number close to 200,000 (specifically a large prime number?). That means j, which is initialised as i * i, will be in excess of 40,000,000,000, which is significantly over the max value of int (approx. 2,147,000,000) That means they will overflow over to negative values, which will definitely be out of range.
To solve the problem in this case, declare your variables to be of type long which is 64-bit and can hold much larger values.
You are getting an integer overflow in this line (i*i is negative):
for(int j = i*i; j <= n + 1; j += i)
Example:
System.out.println(168000 * 168000);
Prints:
-1840771072
Which is negative, so is less than n + 1 and passes cycle condition.
I think it could be because you are using an int and the number is getting too big i.e.
200,000 * 200,000 is a huge number and should probably be a long instead.

Find Duplicates In Arrays

I am writing a method that would take the values and the array and find duplicates. If there are duplicates, like for instance two values have the same value, I will multiple that value by 2. If two values have the same value, I will multiple that value by 3. This will continue until if seven values are the same. I will multiple that value by 7.
This is my source code.
public static double calculateWinnings(int[]numbers)
{
double total = 0;
for (int i = 0; i < numbers.length - 1; i++)
{
for (int j = i + 1; j < numbers.length; j++)
{
if(numbers[i] == numbers[j])
{
total = numbers[i] * .01;
System.out.println("Total is " + total);
return total;
}
}
}
return total;
}
If order doesn't matter, you should sort first, then analyze.
Sorting will put identical values next to each other, where you could more easily notice them in a for loop.
The Java Collections classes may also be of use here.
See for instance http://download.oracle.com/javase/tutorial/collections/intro/index.html
For instance, if you don't want to sort first and use a loop, you could use a HashMap from the collections classes.
HashMap<Integer, Integer> counts = new HashMap<Integer, Integer>();
for(int i=0; i < numbers.length; ++i){
Integer before = counts.get(numbers[i]);
if (before == null) before=0;
counts.put(numbers[i], before+1);
}
now you have a mapper from numbers to counts
later you can use something like max(counts.valueSet()) to find the maximum count
and then loop back through your hash to see which number caused that.
If you have same values at index 1, 4, 6, you will find them with
i j conclusion
--------------
1 4 2 values
1 6 3 values
4 6 4 values // oops! already counted
and so on. Well you would - but there is no so on, since you return on the first hit:
if(numbers[i] == numbers[j])
{
total = numbers[i] * .01;
System.out.println("Total is " + total);
return total; // oops!
}
Do you mean break?
You should provide some example inputs and outputs. It's not clear exactly what output you expect. Are you just looking to find the most duplicates and then multiply that number by the frequency it appears? For example:
1 2 5 5 5 7 8 8 = three 5's = 15
Or perhaps the two 8's wins because their total is 16? Or are you going to sum all of the duplicates? In any case I'd start with this, where MAX_NUM is the highest number you expect in the array:
int[] counts = new int[MAX_NUM];
for (int i = 0; i < numbers.length; i++) {
counts[numbers[i]]++;
}
Now you have the counts of each number. If you're looking for the number with the highest count:
int num = 0;
int best = 0;
for (int i = 0; i < counts.length; i++) {
if (counts[i] > best) {
num = i;
best = counts[i];
}
}
Now num * best would be 15 for my example. Now num will contain the number that occurs the most and best will be the count for it. If there are two numbers with the same count then the higher number will win. Perhaps though in my example above you want 16 instead of 15 because the two 8's have a greater sum:
int max = 0;
for (int i = 0; i < counts.length; i++) {
max = Math.max(i * counts[i], max);
}
Now max would have 16.

Categories

Resources