I receive the 'n must be positive error' on this for loop:
for(int i = 0; i < 8; i++){
array2[i] = CS2004.numbers.get(rand.nextInt(randomNumbers.size()));
}
Whenever I change it to the following, however, it seems to work well.
for(int i = 0; i < 8; i++){
array2[i] = CS2004.numbers.get(rand.nextInt(1000 + randomNumbers.size()));
}
Brief background on the method: it reads in a file containing the first 1000 prime numbers and then randomly adds them to an array of size 8.
Also, if I add the number 1 in place of 1000, it provides me with an answer of 2.0 for every index in the array. If I change it to 10, then the following is the output: [29.0, 29.0, 17.0, 11.0, 5.0, 19.0, 29.0, 2.0]. For the sake of completing the example, when 100 is entered, the following is the result: [61.0, 107.0, 433.0, 193.0, 257.0, 29.0, 463.0, 127.0].
Does the number (10, 100, 1000, ..., n) 'tell' the result that it can add numbers which are up to the length of n? Or is it another explanation altogether?
Can anybody tell me why this error comes up?
Thank you.
The first time rand.nextInt() is called I assume randomNumbers.size() is 0. You are saying you want a random number from 0, which is less than 0 (the number you gave) which is non-sense. You have to give it a positive number so it can give you a sensible result.
My guess is the line should read
array2[i] = CS2004.numbers.get(rand.nextInt(CS2004.numbers.size()));
Here is what JavaDoc has to say about Random#nextInt(int)
Note that the pseudo code has if (n <= 0) throw new IllegalArgumentException("n must be positive");
quoting the excerpts here:
Returns a pseudorandom, uniformly
distributed int value between 0
(inclusive) and the specified value
(exclusive), drawn from this random
number generator's sequence. The
general contract of nextInt is that
one int value in the specified range
is pseudorandomly generated and
returned. All n possible int values
are produced with (approximately)
equal probability. The method
nextInt(int n) is implemented by class
Random as if by:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be
positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
Related
Can somebody help me with this problem?
Statement: - What is the maximum possible n digit number starting from 0 we can make in K steps
using only 2 operations:-
multiplying by 3 or incrementing by 2.
EXAMPLE :
N =2 K = 5;
-> (0->2->6->8->24->72) 72 IS THE ANSWER
N = 2 , K = 51 -> (0->2->6->8->10->30->32->96->98). 98 is the maximum we can get so need to check for rest of the moves.
My 2 state-recursive solution:-
public static void largestNDigitNumber(long[] highest, long maxValue, long k, long currentValue) {
if (highest[0] == (maxValue - 2)) return; //no need to do anything as we get 98 as highest.
if (k < 0) return; //checking for steps
if (highest[0] < currentValue && currentValue <= (maxValue - 2)) {
highest[0] = currentValue;
}
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue * 3));
largestNDigitNumber(highest, maxValue, (k - 1), (currentValue + 2));
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long maxValue = (long) Math.pow(10, n);
long[] highest = new long[1];
largestNDigitNumber(highest, maxValue, (k - 1), 2);
if (highest[0] < (long) Math.pow(10, (n - 1))) {
System.out.println("-1"); // if it is not possible to make n digit in given steps
} else System.out.println(highest[0]);
}
when "k" is small it is giving the correct answer but for bigger values of "k", it does not show any input. for n=2 and k = 51, it does not show anything.
please help me to improve this code
The question is equivalent to asking what is the largest base 3 number that is less than 10^n/2, and has digit sum plus length less than or equal to k+1. (The answer is then double the base 3 number).
For example, N=2 K=5. What's the largest base 3 number that's less than 50, with length plus digit sum less than or equal to 6. Answer: 1100 (36 decimal), so the answer to the original question is 36*2=72.
For N=2, K=51, the largest base-3 number that's less than 50 is 2001 (49 decimal) and has length sum plus digit sum = 7, which is way less than K+1.
Given this representation, it's easy to solve the problem in O(n) time (in fact, you can solve it using pencil and paper). The length d of the base-3 number is as large as possible such that 3^d < 10^n/2 and d<=K. Then fill in the digits of the number greedily from the most-significant first until you have digit sum K+1-d (or you run out of digits).
Equivalence
First note that without loss of generality you can assume you never have three +2 operations in a row, since that can be done more efficiently by inserting a single +2 operation to before the most recent *3 (or simply replacing it by +2 * 3 if there's no *3 operation). Suppose you have represented the current number as a doubled base-3 number. A +2 operation corresponds to adding 1 to the bottom digit (this never overflows into the next column thanks to the observation above). A *3 operation moves all the digits up one column, introducing a 0 as the bottom digit. Note that because the number is doubled, the +2 operation adds just 1 to the base-3 number!
From this, you can see that you can count the number of operations from observation of the doubled base-3 number. Because *3 introduces a new digit, and +2 increases the digit sum by 1, so the number of operations is equal to the number of digits plus 1, plus the digit sum.
As an example. Suppose you have the doubled base-3 number 2 * 2101, then this is equivalent to 2 * (1+3*3*(1+3*(1+1)))) = (2 + 3*3*(2+3*(2+2))).
I tried something like this. it seems to work fine.
getMaxNumber(2, 5) ==> 72
getMaxNumber(2, 51) ==> 98
private int getMaxNumber(int n, int k){
int N = 0;
for (int i = 0; i < n; i++) {
N = N * 10 + 9;
}
int[] result = new int[1];
helper(N, k, 0, 0, result);
return result[0];
}
private void helper(int N, int K, int n, int k, int[] result){
if(n > N) return;
if(k <= K){
result[0] = Math.max(result[0], n);
}
if(n > 0)
helper(N, K, n * 3, k + 1, result);
helper(N, K, n + 2, k + 1, result);
}
Keeping with the style of your original recursive method. I modified it a bit to produce a working solution:
public static long largestNDigitNumber(int n, long currentK, long maxK, long currentValue) {
if (currentK > maxK || n < 1 || maxK < 1) return 0;
if (currentValue >= Math.pow(10, n))
return 0;
long c1 = largestNDigitNumber(n, currentK + 1, maxK, currentValue * 3);
long c2 = largestNDigitNumber(n, currentK + 1, maxK, currentValue + 2);
if (c1 == 0 && c2 == 0)
return currentValue;
return c1 > c2 ? c1 : c2;
}
public static void main(String[] args) {
int n = 2;
long k = 51;
long largest = largestNDigitNumber(n, 0, k, 0);
System.out.println(largest); //98
}
This recursive method returns values here instead of using an array. Hence the check if one returned value is bigger than the other or they are both 0 before returning.
Both the +2 and *3 operations preserve odd/even parity, so starting from 0 we can only reach even numbers. We could start our search at the highest even number: 8, 98, 998, 9998 etc. and see what the shortest distance to 0 is.
If we are looking for the shortest distance, then there are less choices to make. If the current number is a multiple of 3 then there are two choices, either we divide by 3 or subtract 2. Otherwise the only choice is to subtract 2. I suspect that in the majority of cases, dividing by 3 is the better option, so that might be the first to try to keep the tree smaller.
If the minimum number of steps is less than K then as many divide by 3 operations as needed can be used to make the correct K
If the minimum number of steps is equal to K then the problem is solved.
If the minimum number of steps is more than K then you need to pick a lower starting number. Some even numbers will already have been covered as part of the initial calculation. You get those 'for free', provide you include a small amount of record keeping. You only need to examine large even numbers that were missed earlier due to a 'divide by 3' step.
Not sure if anyone can explain this to me or help me.
I have a 15 Digit Number of which I want to multiply each even number by 2 unless the even number is greater than 9. If it is this needs to be subtracted by 9 to give me an integer that again I can multiply by 2. Once I have all the even numbers multiplied by 2 i need to add them all together with the odd numbers.
Does that make sense.
UPDATE ***
so i have a number say 49209999856459. for that number I am looking to get the even integer so for example the first even one would be 4 then the second would be 2 and so on.
If one of those even numbers are multiplied by 2 then it might be above 9 so I want to subtract 9 to then use the remainder as the even number in its place.
SO !!!
Multiply by 2 the value of each even digit starting from index 0 and then each even index. In each case, if the resulting value is greater than 9, subtract 9 from it (which reduces larger values to a single digit). Leave the values of the digits at the odd indexes unchanged.
public String calculateCheckNumber()
String firstFifteen = longNumber.substring(0,15) ;
int i, checkSum = 0, totalSum = 0;
for (i = 0; i<firstFifteen.length(); i += 2) {
while (i < 9)
i *= 2;
if (i > 9)
i -= 9 ;
}
Was one option I was trying but it honestly I cant seem to get my head around it.
Any Help would be greatly appreciated.
Well, here is one approach. This uses the ternary (?:) operator to condense the operations. Edited base on clarification from the OP. The example you gave is actually a 14 digit string. But the following will work with any number of digits if they start out in a string. If you have a long value, then you can create the character array using:
long v = 49209999856459L;
char[] d = Long.toString(v).toCharArray();
Here is the main algorithm.
String s = "49209999856459";
int sum = 0;
char[] d = s.toCharArray();
for (int i = 0; i < d.length; i++) {
int v = d[i] - '0';
// The even digit will only be greater than 9 after
// doubling if it is >= 5 before.
sum += ((i % 2) == 1) ? v : (v >= 5) ? v+v-9 : v+v;
}
System.out.println(sum);
Prints
86
sorry for that title but I wanted to pack as much information about my problem in as little space as possible without being too confusing.
So, I have a loop which runs n times and each time it uses a = r.nextInt(int y); to generate an int and if all n integers generated are even numbers, then the program "returns true".
The weird thing is: if I chose n to be 18 or higher while y is and even number which is not a power of 2, then the programm will not "termintate successfully".
I love to help you help me, and can take a heavy dose of criticism.
(I know I'm asking about the Random/nextInt(int) topic but I will also take tips for better coding)
EDIT: I looked into the Documentation for Java8 befor I posted here and for powers of two the method uses a different way of producing the random number.
What I don't understand is why is 18 the breakpoint for consecutive even numbers and why does it work with odd numbers for nextInt(int)?
So the following code will work with howManyInts = 16 or 17 but not 18 (or higher) when nextIntValue is an even number which is not a power of two (6,10,12...)
It works with howManyInts = 25 and nextIntValue = 8 in less than 20 seconds
import java.util.*;
class test{
public static void main(String[] args) {
boolean win = false;
int areEven = 0;
long loopCounter = 0; // The loopCounter is used to control the maximum number of loops should be run incase the loop is endless
int howManyInts = 18;
int nextIntValue = 6; // nextIntValue = 6 or 10 won't work while all powers of 2 work fine
// also, I don't want an odd value as that would change to odds towards odd values...
while(win == false){
loopCounter += 1;
areEven = 0;
Random r = new Random();
int[] num = new int[howManyInts];
for(int a = 0; a < num.length; a++){
num[a] = r.nextInt(nextIntValue);
if(num[a] % 2 == 0){
areEven += 1;
}
}
if(areEven == num.length || loopCounter >= 10000000){
win = true;
System.out.println("It took " + loopCounter + " loops to get " + num.length + " random values which are all even.");
}
}
}
}
If you use SecureRandom instead of Random, your program will finish fairly quickly.
Another way would be to use nextDouble instead
num[a] = (int) (r.nextDouble() * nextIntValue);
The problem with Random.nextInt(int n) is I believe hidden within its implementation and you can read about it in its javadoc.
The algorithm is slightly tricky. It rejects values that would result
in an uneven distribution (due to the fact that 2^31 is not divisible
by n). The probability of a value being rejected depends on n. The
worst case is n=2^30+1, for which the probability of a reject is 1/2,
and the expected number of iterations before the loop terminates is 2.
The algorithm treats the case where n is a power of two specially: it
returns the correct number of high-order bits from the underlying
pseudo-random number generator. In the absence of special treatment,
the correct number of low-order bits would be returned. Linear
congruential pseudo-random number generators such as the one
implemented by this class are known to have short periods in the
sequence of values of their low-order bits. Thus, this special case
greatly increases the length of the sequence of values returned by
successive calls to this method if n is a small power of two.
The implementation looks like this:
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
While the next method looks like this (I've replaced the constants with literals)
protected int next(int bits) {
long oldseed, nextseed;
AtomicLong seed = this.seed;
do {
oldseed = seed.get();
nextseed = (oldseed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
} while (!seed.compareAndSet(oldseed, nextseed));
return (int)(nextseed >>> (48 - bits));
}
(I suppose that 48-31 == 17 is purely coincidental)
Interesting question!
I have added some statistic-gathering to the code:
import java.util.*;
public class J {
static Random r = new Random();
private static class Stats {
long s[];
public Stats(int n) { this.s = new long[n]; }
public String toString() {
return Arrays.toString(s);
}
}
public static void test(int target, int options) {
boolean win = false;
Stats s = new Stats(target);
for (long iterations = 0; !win; iterations ++) {
int even = 0;
for (int i = 0; i < target; i++) {
if ((r.nextInt(options) % 2) != 0) {
s.s[i] ++;
break;
} else {
even ++;
}
}
if (even == target) {
win = true;
System.out.println(
"It took " + iterations + " loops to get " + target
+ " random values which are all even. Stats: " + s);
} else if (iterations >= 1E8) {
win = true;
System.out.println(iterations + ": " + s);
}
}
}
public static void main(String args[]) {
test(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
}
}
The code now ends if no sequence is found after 100M tries; and always stores how far it managed to get before failing (= drawing an odd number).
These are some runs:
18 9: It took 57235 loops to get 18 random values which are all even. Stats: [25401, 14081, 7864, 4328, 2508, 1366, 747, 390, 263, 126, 76, 38, 28, 4, 8, 4, 2, 1]
18 8: It took 48612 loops to get 18 random values which are all even. Stats: [24285, 12336, 6066, 2981, 1436, 738, 385, 197, 95, 43, 23, 10, 8, 7, 1, 0, 0, 1]
18 7: It took 23302 loops to get 18 random values which are all even. Stats: [10062, 5712, 3174, 1877, 1101, 590, 331, 190, 98, 59, 44, 31, 18, 8, 5, 2, 0, 0]
18 6: Aborted after 100000000 tries: [49997688, 24993911, 12503043, 6272129, 3113557, 1544194, 788879, 393680, 205236, 89264, 45016, 35858, 5340, 9155, 763, 1525, 0, 763]
So, for those particular values (100M attempts at runs of 18 even numbers, throwing 6-sided dice), there were 0 cases where the run bailed out because of the 17th number, but 763(!) where it bailed out because of the last number!
It definitely looks like a higher-quality PRNG is needed, such as the one mentioned by #radoh.
Probabilistically speaking, you would expect to find runs of N even throws of a fair coin with probability 1/(2^N); and you would expect to collect stats where each entry would be 1/2 the previous one. Encountering 0, 763 indicates a strong bias.
The issue is almost certainly with r.nextInt(nextIntValue);. Here you are requesting a random integer between 0 and 5. I cannot understand specifically why 18 is the break point but the chances a sequence of random positive integers less than a small number to be all even must reduce as the limit reduces.
I note that increasing that value from 6 to 100 still does not find length-18 even sequences. Perhaps the algorithm behind the scenes somehow influences the statistics.
Seems like the random generator doesn't allow 18 consecutive even numbers, when your maxRandom is even, starting at 6.
I changed the code a bit to demonstrate how the 18th random is always odd:
class NextIntWeirdness {
public static void main(String[] args) {
int maxRandom = 6;
Random r = new Random();
for (int i = 0; i < 100; i++) {
int evenNumbers = 17;
int evenResults;
do {
evenResults = 0;
for (int j = 0; j < evenNumbers; j++) {
int num = r.nextInt(maxRandom);
if (num % 2 != 0) {
break;
} else {
evenResults++;
}
}
} while (evenResults < evenNumbers);
System.out.println(r.nextInt(maxRandom));
}
}
}
I'm trying to write a simple method in Java that return the reverse of a number (in the mathematical way, not string-wise). I want to take care of boundary conditions since a number whose reverse is out of int range would give me a wrong answer. Even to throw exceptions, I'm not getting clearcut logic. I've tries this code.
private static int reverseNumber(int number) {
int remainder = 0, sum = 0; // One could use comma separated declaration for primitives and
// immutable objects, but not for Classes or mutable objects because
// then, they will allrefer to the same element.
boolean isNegative = number < 0 ? true : false;
if (isNegative)
number = Math.abs(number); // doesn't work for Int.MIN_VALUE
// http://stackoverflow.com/questions/5444611/math-abs-returns-wrong-value-for-integer-min-value
System.out.println(number);
while (number > 0) {
remainder = number % 10;
sum = sum * 10 + remainder;
/* Never works, because int won't throw error for outside int limit, it just wraps around */
if (sum > Integer.MAX_VALUE || sum < Integer.MIN_VALUE) {
throw new RuntimeException("Over or under the limit");
}
/* end */
/* This doesn't work always either.
* For eg. let's take a hypothetical 5 bit machine.
* If we want to reverse 19, 91 will be the sum and it is (in a 5 bit machine), 27, valid again!
*/
if (sum < 0) {
throw new RuntimeException("Over or under the limit");
}
number /= 10;
}
return isNegative ? -sum : sum;
}
Your approach of dividing by 10, transfering the reminder to the current result * 10 is the way to go.
The only thing you are doing wrong is the check for the "boundary violation", because
sum > Integer.MAX_VALUE || sum < Integer.MIN_VALUE
can ofc. NEVER be true - Otherwhise MIN and MAX wouldn't have any meaning.
So, think mathematical :-)
sum = sum * 10 + remainder;
should not exceed Integer.MAX_VALUE, i.e.
(!)
Integer.MAX_VALUE >= sum * 10 + remainder;
or transformed:
(!)
(Integer.MAX_VALUE - remainder) / 10 >= sum
So, you can use the following check BEFORE multiplying by 10 and adding the remainder:
while (number > 0) {
remainder = number % 10;
if (!(sum <= ((Integer.MAX_VALUE -remainder) / 10))) {
//next *10 + remainder will exceed the boundaries of Integer.
throw new RuntimeException("Over or under the limit");
}
sum = sum * 10 + remainder;
number /= 10;
}
simplified (DeMorgan) the condition would be
if (sum > ((Integer.MAX_VALUE -remainder) / 10))
which makes perfect sence - because its exactly the reversed calculation of what your next step will be - and if sum is already GREATER than this calculation - you will exceed Integer.MAX_VALUE with the next step.
Untested, but that should pretty much solve it.
I discovered the hard way that this method seems to fail miserably when you feed it a power of 2. Given two Random objects of different seeds, it seems that the first integer they return when asked to return an integer between 0 (inclusive) and and a power of two (exclusive) is always the same; the seeds don't matter. For example:
public static void main(String[] args) {
Random mRandom;
for (int i = 0; i < 10; i++) {
mRandom = new Random(i);
System.out.println(mRandom.nextInt((int) Math.pow(2, 4)));
}
}
Console:
11
11
11
11
11
11
11
11
11
11
I chose 2^4 arbitrarily, but it seems to work for any power of two. What's going on? Furthermore, how can I avoid this?
This problem occurs due to 2 reasons.
Same seed for Random class.
At nextInt(int n), if n is power of 2
1. Same seed for Random class.
Because, you have initiated new Random instance with new seed value which has influence on the nextInt value generation. According to Java docs of Random(long seed).
Creates a new random number generator using a single long seed. The seed is the initial value
of the internal state of the
pseudorandom number generator which is maintained by method next(int).
The invocation new Random(seed) is equivalent to:
Random rnd = new Random();
rnd.setSeed(seed);
If you try to generate random value, without new seed than it will generate real random value, even though new instance of Random class.
for (int i = 0; i < 10; i++) {
mRandom = new Random(); // Without seed
System.out.println(mRandom.nextInt((int) Math.pow(2, 4)));
}
Output: 2 1 12 4 3 9 9 8 2 9
2. At nextInt(int n), if n is power of 2
Besides this, Random#nextInt has effect of power of 2. If n is a power of 2 it will return (int)((n * (long)next(31)) >> 31) which will always same for same n. According to nextInt Algorithm,
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
You could also use Math.random and Math.pow together for more simplicity if you wanted.
for (int i = 0; i < 10; i++) {
int pows = (int) Math.pow(2, 4);
int random = (int)(Math.random()*pows);
System.out.println(""+random);
}