This question already has answers here:
How to generate a random BigInteger value in Java?
(8 answers)
Closed 8 years ago.
I need to get a random BigInteger that is bigger than 2^511 and lower than 2^512.
byte[] bytes = new byte[64]; // 512 bits
new Random().nextBytes(bytes);
bytes[0] |= 0x80; // set the most significant bit
return new BigInteger(1, bytes);
From the doc :
BigInteger(int numBits, Random rnd)
Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.
So something like that should work :
BigInteger number = new BigInteger(512, new Random()); //Give you a number between 0 and 2^512 - 1
number = number.setBit(0); //Set the first bit so number is between 2^511 and 2^512 - 1
This solution creates at first a BigInteger with value 2^511 and afterwards adds an value between 0 and 2^511 - 1:
StringBuilder builder = new StringBuilder("1");
for (int bit = 0; bit < 511; bit++) builder.append("0");
BigInteger value = new BigInteger(builder.toString(), 2).add(new BigInteger(511, new Random()));
You could try that
public static void main(String[] args) {
int min = 511;
double rand = Math.random(); //between 0 and 1
double exp = min + rand; //between 511 et 512
Double result = Math.pow(2, exp);
System.out.println("result = ["+result+"]");
}
It is maybe not optimised, but its works. With the double result, you can obtain a integer.
Related
I am trying to sum up all the numbers between 2 given numbers excluding the boundary.. E.g. addNumbers("5", "8") should return 13 since 6+7=13. This is the function I currently have.
public static BigInteger addNumbers(String from, String to) {
BigInteger total = new BigInteger("0");
BigInteger startingBoundary = new BigInteger(from);
BigInteger finishingBoundary = new BigInteger(to);
if (startingBoundary.compareTo(finishingBoundary) < 0) {
startingBoundary = new BigInteger(from);
finishingBoundary = new BigInteger(to);
} else {
finishingBoundary = new BigInteger(from);
startingBoundary = new BigInteger(to);
}
while (startingBoundary.compareTo(finishingBoundary) != 0 ) {
System.out.println("Starting boundary:" + startingBoundary.intValue());
System.out.println("Finishing boundary: " + finishingBoundary.intValue());
total.add(startingBoundary);
System.out.println("total: "+total.intValue());
startingBoundary.add(new BigInteger("1"));
}
return total;
}
The problem is that the while condition seems to be running infinitely despite me changing the value of it. Also when printing out the total object in each loop, it always prints out 0. I know I initialised it to 0 but i was expecting it to change as I am adding to it..
Note that the use of BigInteger implies that the numbers, and thus also the difference between the two numbers, might be huge. Looping from lower to upper boundary might take ages, literally. Instead, you could use a variant of the closed form sum(1..N) = (N*(N+1))/2. Use it to sum the number from 1 to upper and from 1 to lower, then combine the two to get your desired result.
BigInteger lower = new BigInteger("5");
BigInteger upper = new BigInteger("8");
BigInteger one = BigInteger.ONE, two = BigInteger.TWO;
BigInteger oneToUpper = upper.multiply(upper.add(one)).divide(two);
BigInteger oneToLower = lower.multiply(lower.add(one)).divide(two);
BigInteger lowertoUpperInc = oneToUpper.subtract(oneToLower).add(lower);
System.out.println(lowertoUpperInc); // 5 + 6 + 7 + 8 = 26
BigInteger lowertoUpperExc = oneToUpper.subtract(oneToLower).subtract(upper);
System.out.println(lowertoUpperExc); // 6 + 7 = 13
(Note that your loop also seems to return 18 for this example, which seems to be 5+6+7 and thus not what you really wanted.)
Other than your loop, this will also work for truly BigInteger, e.g. the sums (inclusive and exclusive) for lower = 123456789123456789 and upper = 987654321987654321 are 480109740480109740075445815075445815 and 480109740480109738964334703964334705 respectively.
As already mentioned in another answer: Calls like
total.add(startingBoundary);
do not have any observable effect. The add method does not modify the total object. Instead, it returns a new BigInteger object. The reason for that is, more generally, that BigInteger is immutable. This means that the value of a BigInteger object cannot be changed after it has been created. For the reasons, have a look at Why BigInteger in java is designed to be immutable?
Changing the line to
total = total.add(startingBoundary);
will solve this (similarly, for the other lines - for a fixed implementation, see the example below).
A side note: Instead of new BigInteger("0") and new BigInteger("1"), you should usually use BigInteger.ZERO and BigInteger.ONE. There is no reason to create new objects for these frequently used values.
A possible improvement, though:
Unless the assignment explicitly says that this has to be solved with a loop, there is a far more efficient and elegant solution for this. You can use the Gauß'sche Summenformel (sorry, no English version of that one), which basically states that
The sum of the natural numbers from 1 to n is equal to (n*(n+1))/2
So you can compute these sums directly, for the limits of your range, and then just return the difference between the two.
The following contains a fixed version of your original code, and the alternative implementation, together with a (very basic) "microbenchmark":
import java.math.BigInteger;
import java.util.Locale;
public class SumFromRange
{
public static void main(String[] args)
{
simpleExample();
simpleBenchmark();
}
private static void simpleExample()
{
System.out.println(addNumbers("5", "8"));
System.out.println(addNumbersFast("5", "8"));
System.out.println(addNumbers("15", "78"));
System.out.println(addNumbersFast("15", "78"));
}
private static void simpleBenchmark()
{
int blackHole = 0;
for (long min = 10000; min <= 20000; min += 10000)
{
for (long max = 10000000; max <= 20000000; max += 10000000)
{
String from = String.valueOf(min);
String to = String.valueOf(max);
long before = 0;
long after = 0;
before = System.nanoTime();
BigInteger slow = addNumbers(from, to);
after = System.nanoTime();
blackHole += slow.hashCode();
System.out.printf("Compute %10d to %10d slow took %8.3f ms\n",
min, max, (after - before) / 1e6);
before = System.nanoTime();
BigInteger fast = addNumbersFast(from, to);
after = System.nanoTime();
blackHole += fast.hashCode();
System.out.printf(Locale.ENGLISH,
"Compute %10d to %10d fast took %8.3f ms\n", min, max,
(after - before) / 1e6);
}
}
System.out.println("blackHole " + blackHole);
}
public static BigInteger addNumbers(String from, String to)
{
BigInteger total = BigInteger.ZERO;
BigInteger startingBoundary = new BigInteger(from);
BigInteger finishingBoundary = new BigInteger(to);
if (startingBoundary.compareTo(finishingBoundary) < 0)
{
startingBoundary = new BigInteger(from);
finishingBoundary = new BigInteger(to);
}
else
{
finishingBoundary = new BigInteger(from);
startingBoundary = new BigInteger(to);
}
startingBoundary = startingBoundary.add(BigInteger.ONE);
while (startingBoundary.compareTo(finishingBoundary) != 0)
{
total = total.add(startingBoundary);
startingBoundary = startingBoundary.add(BigInteger.ONE);
}
return total;
}
public static BigInteger addNumbersFast(String from, String to)
{
BigInteger f = new BigInteger(from);
BigInteger t = new BigInteger(to);
BigInteger sf = computeSum(f);
BigInteger st = computeSum(t.subtract(BigInteger.ONE));
return st.subtract(sf);
}
// Compute the sum of 1...n
public static BigInteger computeSum(BigInteger n)
{
BigInteger n1 = n.add(BigInteger.ONE);
return n.multiply(n1).divide(BigInteger.valueOf(2));
}
}
The benchmark results for larger values are obvious:
Compute 10000 to 10000000 slow took 635,506 ms
Compute 10000 to 10000000 fast took 0.089 ms
Compute 10000 to 20000000 slow took 1016,381 ms
Compute 10000 to 20000000 fast took 0.037 ms
Compute 20000 to 10000000 slow took 477,258 ms
Compute 20000 to 10000000 fast took 0.038 ms
Compute 20000 to 20000000 slow took 987,400 ms
Compute 20000 to 20000000 fast took 0.040 ms
These aren't even in the same league...
Use
total = total.add(startingBoundary);
and
startingBoundary = startingBoundary.add(new BigInteger("1"));
Because add does not add to the first operand, but returns the sum.
Also, before starting the loop, do
startingBoundary = startingBoundary.add(new BigInteger("1"));
to satisfy your condition that the starting boundary has to be excluded.
As defensive coding, don't use equals to zero, but use
startingBoundary.compareTo(finishingBoundary) < 0
This question already has answers here:
How do I generate random integers within a specific range in Java?
(72 answers)
Closed 6 years ago.
Trying to figure this out for a while, need a random number that is either -1, 0 or 1. Any help would be great.
Random random = ThreadLocalRandom.current();
int randomNumber = random.nextInt(3) - 1;
Will do the work
If you use Java < 8 version then old approach will be great for you:
You can use java.util.Random class and its method nextInt(int bound). This method generates a random integer from 0 (inclusive) to bound (exclusive). If you want some specific range then you will need to perform some simple math operations:
Cut the range: max - min
If you want to include upper bound value then will add 1: nextInt((max - min) + 1) (optional step)
Shift the generated number to the value of lower bound: nextInt((max - min) + 1) + min
Result:
Random r = new Random();
int randomNumber = r.nextInt((max - min) + 1) + min;
If you use Java >= 8 version, then there will be easier approach for you:
Now java.util.Random class provides other methods according to Stream api like:
public IntStream ints(int randomNumberOrigin, int randomNumberBound)
public IntStream ints(long streamSize, int randomNumberOrigin, int randomNumberBound)
Now you can generate a random integer from origin (inclusive) to bound (exclusive) like that:
Random r = new Random();
r.ints(min, max).findFirst().getAsInt();
If you want to include upper bound into generating process then:
r.ints(min, (max + 1)).findFirst().getAsInt();
To prevent producing unlimited stream:
r.ints(min, (max + 1)).limit(1).findFirst().getAsInt();
or
r.ints(1, min, (max + 1)).findFirst().getAsInt();
answer 1
long l = System.currentTimeMillis();
int randomNumber = (int) (l % 3) - 1;
answer 2
int randomNumber = (int) (Math.random() * 3) - 1;
answer 3
Random random = new Random();
int randomNumber = random.nextInt(3) - 1;
Look at this one
Random r = new Random();
int n = r.nextInt((1 - -1) + 1) + -1;
System.out.println(n);
it will generate random between the range you want. output will be 1 or 0 or -1.
You can use int arrays with Random class. Store your values in an integer array, and generate random number for the index of the array.
Sample Code:
final int[] arr = new int[] { -1, 0, 1 };
Random number = new Random();
int n = number.nextInt(arr.length);
System.out.println(arr[n]); //arr[n] will give you random number
This question already has answers here:
How do I generate random integers within a specific range in Java?
(72 answers)
Closed 6 years ago.
I ran into this problem today and I'm sure there is an elegant solution I am not thinking of.
Let's say I want to generate a random integer(or long) in Java with a specified number of digits, where this number of digits can change.
I.e. pass in a number of digits into a method, and return a random number with the specified number of digits
Ex.) N = 3, generate a random number between 100-999; N = 4, generate a random number between 1000-9999
private long generateRandomNumber(int n){
/*Generate a random number with n number of digits*/
}
My attempt so far (this works, but it seems messy)
private long generateRandomNumber(int n){
String randomNumString = "";
Random r = new Random();
//Generate the first digit from 1-9
randomNumString += (r.nextInt(9) + 1);
//Generate the remaining digits between 0-9
for(int x = 1; x < n; x++){
randomNumString += r.nextInt(9);
}
//Parse and return
return Long.parseLong(randomNumString);
}
Is there a better/more efficient solution than this?
*There are lots of solutions for generating random numbers in a specified range, I was more curious on the best way to generate random numbers given a set number of digits, as well as making the solution robust enough to handle any number of digits.
I did not want to have to pass in a min and max, but rather just the number of digits needed
private long generateRandomNumber(int n) {
long min = (long) Math.pow(10, n - 1);
return ThreadLocalRandom.current().nextLong(min, min * 10);
}
nextLong produces random numbers between lower bound inclusive and upper bound exclusive so calling it with parameters (1_000, 10_000) for example results in numbers 1000 to 9999.
Old Random did not get those nice new features unfortunately. But there is basically no reason to continue to use it anyways.
public static int randomInt(int digits) {
int minimum = (int) Math.pow(10, digits - 1); // minimum value with 2 digits is 10 (10^1)
int maximum = (int) Math.pow(10, digits) - 1; // maximum value with 2 digits is 99 (10^2 - 1)
Random random = new Random();
return minimum + random.nextInt((maximum - minimum) + 1);
}
You can simply disregard the numbers that are not in the required range. That way your modified pseudo random number generator guarantees that it generates a number in the given range uniformly at random:
public class RandomOfDigits {
public static void main(String[] args) {
int nd = Integer.parseInt(args[0]);
int loIn = (int) Math.pow(10, nd-1);
int hiEx = (int) Math.pow(10, nd);
Random r = new Random();
int x;
do {
x = r.nextInt(hiEx);
} while (x < loIn);
System.out.println(x);
}
}
Here is the way I would naturally write a method like this:
private long generateRandomNumber(int n){
double tenToN = Math.pow(10, n),
tenToNMinus1 = Math.pow(10, n-1);
long randNum = (long) (Math.random() * (tenToN - tenToNMinus1) + tenToNMinus1);
return randNum;
}
This question already has answers here:
How do I generate random integers within a specific range in Java?
(72 answers)
Closed 9 years ago.
I am trying to create a random phone number with a range. The format being (xxx)-xxx-xxx and the area code not starting with 0,8, or 9 and the next set of three being in a range from 100-742 and then the last set of 4 can be any digit. How would i create the first two parts? Any help would be appreciated. Thanks!
import java.util.*;
import java.text.*;
public class PhoneNumber{
public static void main(String[] arg){
Random ranNum = new Random();
//int areaCode = 0;
//int secSet = 0;
//int lastSet = 0;
DecimalFormat areaCode = new DecimalFormat("(000)");
DecimalFormat secSet = new DecimalFormat("-000");
DecimalFormat lastSet = new DecimalFormat("-0000");
//DecimalFormat phoneNumber = new DecimalFormat("(###)-###-####");
int i = 0;
//areaCode = (ranNum.nextInt()); //cant start with 0,8,9
//secSet = (ranNum.nextInt()); // not greater than 742 and less than 100
//lastSet = (ranNum.nextInt(999)) + 1; // can be any digits
i = ranNum.nextInt();
System.out.print(areaCode.format(i));
i = ranNum.nextInt();
System.out.print(secSet.format(i));
i = ranNum.nextInt();
System.out.print(lastSet.format(i));
}
}
well, basically, you need to generate numbers in two ranges
[1; 7]
[100; 742]
To have random integer in range [m; n] you could write:
updated (remove Math.random())
int numberInRange = m + new Random().nextInt(n - m + 1);
HTH
1,2,3,4,5,6,7
makes 7 different values
ranNum.nextInt(7)+1; //So 1 is your lowest number and 7 is the number of different solutions
nexInt will range between 0 and intPassed exclusive,
So ranNum.nextInt(7) will run between 0 and 6, + 1 makes 1 .. 7
This will range between 1 and 7
You can take the same principal for the second range
You can try the next:
int sec = java.util.concurrent.ThreadLocalRandom.current().nextInt(100, 743);
And so on with the other parts of the phone number.
This method returns a pseudorandom, uniformly distributed value between the given least value (inclusive) and bound (exclusive).
Just make a random number greater than 99 and less than 800, then the next would be about the same way.
Random rand = new Random();
// add 1 to make it inclusive
max min
int firstRandomSet = rand.nextInt((799 - 100) + 1) + 100;
//none starts with 0,8, or 9
int secondRandomSet = rand.nextInt((742 - 100) + 1) + 100;
//produces anything from 100-742
to get the numbers 0001 - 9999 you'll have to be creative.
int maxValues= 9999;
int thirdRandomSet = rand.nextInt(maxValues);
System.out.printf("%04d\n", thirdRandomSet);
I need to generate arbitrarily large random integers in the range 0 (inclusive) to n (exclusive). My initial thought was to call nextDouble and multiply by n, but once n gets to be larger than 253, the results would no longer be uniformly distributed.
BigInteger has the following constructor available:
public BigInteger(int numBits, Random rnd)
Constructs a randomly generated BigInteger, uniformly distributed over the range 0 to (2numBits - 1), inclusive.
How can this be used to get a random value in the range 0 - n, where n is not a power of 2?
Use a loop:
BigInteger randomNumber;
do {
randomNumber = new BigInteger(upperLimit.bitLength(), randomSource);
} while (randomNumber.compareTo(upperLimit) >= 0);
on average, this will require less than two iterations, and the selection will be uniform.
Edit: If your RNG is expensive, you can limit the number of iterations the following way:
int nlen = upperLimit.bitLength();
BigInteger nm1 = upperLimit.subtract(BigInteger.ONE);
BigInteger randomNumber, temp;
do {
temp = new BigInteger(nlen + 100, randomSource);
randomNumber = temp.mod(upperLimit);
} while (s.subtract(randomNumber).add(nm1).bitLength() >= nlen + 100);
// result is in 'randomNumber'
With this version, it is highly improbable that the loop is taken more than once (less than one chance in 2^100, i.e. much less than the probability that the host machine spontaneously catches fire in the next following second). On the other hand, the mod() operation is computationally expensive, so this version is probably slower than the previous, unless the randomSource instance is exceptionally slow.
The following method uses the BigInteger(int numBits, Random rnd) constructor and rejects the result if it's bigger than the specified n.
public BigInteger nextRandomBigInteger(BigInteger n) {
Random rand = new Random();
BigInteger result = new BigInteger(n.bitLength(), rand);
while( result.compareTo(n) >= 0 ) {
result = new BigInteger(n.bitLength(), rand);
}
return result;
}
The drawback to this is that the constructor is called an unspecified number of times, but in the worst case (n is just slightly greater than a power of 2) the expected number of calls to the constructor should be only about 2 times.
The simplest approach (by quite a long way) would be to use the specified constructor to generate a random number with the right number of bits (floor(log2 n) + 1), and then throw it away if it's greater than n. In the worst possible case (e.g. a number in the range [0, 2n + 1) you'll throw away just under half the values you create, on average.
Why not constructing a random BigInteger, then building a BigDecimal from it ?
There is a constructor in BigDecimal : public BigDecimal(BigInteger unscaledVal, int scale) that seems relevant here, no ? Give it a random BigInteger and a random scale int, and you'll have a random BigDecimal. No ?
Here is how I do it in a class called Generic_BigInteger available via:
Andy Turner's Generic Source Code Web Page
/**
* There are methods to get large random numbers. Indeed, there is a
* constructor for BigDecimal that allows for this, but only for uniform
* distributions over a binary power range.
* #param a_Random
* #param upperLimit
* #return a random integer as a BigInteger between 0 and upperLimit
* inclusive
*/
public static BigInteger getRandom(
Generic_Number a_Generic_Number,
BigInteger upperLimit) {
// Special cases
if (upperLimit.compareTo(BigInteger.ZERO) == 0) {
return BigInteger.ZERO;
}
String upperLimit_String = upperLimit.toString();
int upperLimitStringLength = upperLimit_String.length();
Random[] random = a_Generic_Number.get_RandomArrayMinLength(
upperLimitStringLength);
if (upperLimit.compareTo(BigInteger.ONE) == 0) {
if (random[0].nextBoolean()) {
return BigInteger.ONE;
} else {
return BigInteger.ZERO;
}
}
int startIndex = 0;
int endIndex = 1;
String result_String = "";
int digit;
int upperLimitDigit;
int i;
// Take care not to assign any digit that will result in a number larger
// upperLimit
for (i = 0; i < upperLimitStringLength; i ++){
upperLimitDigit = new Integer(
upperLimit_String.substring(startIndex,endIndex));
startIndex ++;
endIndex ++;
digit = random[i].nextInt(upperLimitDigit + 1);
if (digit != upperLimitDigit){
break;
}
result_String += digit;
}
// Once something smaller than upperLimit guaranteed, assign any digit
// between zero and nine inclusive
for (i = i + 1; i < upperLimitStringLength; i ++) {
digit = random[i].nextInt(10);
result_String += digit;
}
// Tidy values starting with zero(s)
while (result_String.startsWith("0")) {
if (result_String.length() > 1) {
result_String = result_String.substring(1);
} else {
break;
}
}
BigInteger result = new BigInteger(result_String);
return result;
}
For those who are still asking this question and are looking for a way to generate arbitrarily large random BigIntegers within a positive integer range, this is what I came up with. This random generator works without trying bunch of numbers until one fits the range. Instead it will generate a random number directly that will fit the given range.
private static BigInteger RandomBigInteger(BigInteger rangeStart, BigInteger rangeEnd){
Random rand = new Random();
int scale = rangeEnd.toString().length();
String generated = "";
for(int i = 0; i < rangeEnd.toString().length(); i++){
generated += rand.nextInt(10);
}
BigDecimal inputRangeStart = new BigDecimal("0").setScale(scale, RoundingMode.FLOOR);
BigDecimal inputRangeEnd = new BigDecimal(String.format("%0" + (rangeEnd.toString().length()) + "d", 0).replace('0', '9')).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeStart = new BigDecimal(rangeStart).setScale(scale, RoundingMode.FLOOR);
BigDecimal outputRangeEnd = new BigDecimal(rangeEnd).add(new BigDecimal("1")).setScale(scale, RoundingMode.FLOOR); //Adds one to the output range to correct rounding
//Calculates: (generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
BigDecimal bd1 = new BigDecimal(new BigInteger(generated)).setScale(scale, RoundingMode.FLOOR).subtract(inputRangeStart);
BigDecimal bd2 = inputRangeEnd.subtract(inputRangeStart);
BigDecimal bd3 = bd1.divide(bd2, RoundingMode.FLOOR);
BigDecimal bd4 = outputRangeEnd.subtract(outputRangeStart);
BigDecimal bd5 = bd3.multiply(bd4);
BigDecimal bd6 = bd5.add(outputRangeStart);
BigInteger returnInteger = bd6.setScale(0, RoundingMode.FLOOR).toBigInteger();
returnInteger = (returnInteger.compareTo(rangeEnd) > 0 ? rangeEnd : returnInteger); //Converts number to the end of output range if it's over it. This is to correct rounding.
return returnInteger;
}
How does it work?
First it generates a String with random numbers with the same length as the maximum range. For example: with given range of 10-1000 it will generate some number between 0000 and 9999 as a String.
Then it creates BigDecimals to represent the maximum possible value (9999 in previous example) and minimum value (0) and converts the range parameter BigIntegers to BigDecimals. Also in this step to the given range maximum value is added 1 in order to correct rounding errors in the next step.
Then using this formula the generated random number is mapped to the given range:
(generated - inputRangeStart) / (inputRangeEnd - inputRangeStart) * (outputRangeEnd - outputRangeStart) + outputRangeStart
After that it will do a last check whether or not the mapped number fits the given range and sets it to the given range maximum if it doesn't. This is done in order to correct rounding errors.
Just use modular reduction
new BigInteger(n.bitLength(), new SecureRandom()).mod(n)
Compile this F# code into a DLL and you can also reference it in your C# / VB.NET programs
type BigIntegerRandom() =
static let internalRandom = new Random()
/// Returns a BigInteger random number of the specified number of bytes.
static member RandomBigInteger(numBytes:int, rand:Random) =
let r = if rand=null then internalRandom else rand
let bytes : byte[] = Array.zeroCreate (numBytes+1)
r.NextBytes(bytes)
bytes.[numBytes] <- 0uy
bigint bytes
/// Returns a BigInteger random number from 0 (inclusive) to max (exclusive).
static member RandomBigInteger(max:bigint, rand:Random) =
let rec getNumBytesInRange num bytes = if max < num then bytes else getNumBytesInRange (num * 256I) bytes+1
let bytesNeeded = getNumBytesInRange 256I 1
BigIntegerRandom.RandomBigInteger(bytesNeeded, rand) % max
/// Returns a BigInteger random number from min (inclusive) to max (exclusive).
static member RandomBigInteger(min:bigint, max:bigint, rand:Random) =
BigIntegerRandom.RandomBigInteger(max - min, rand) + min