Set accuracy of random numbers in java? - java

I was wondering if I am able to set the accuracy of the random double numbers that I generate.
Random generator = new Random();
double randomIndex = generator.nextDouble()*10000;
That produces the random numbers within 10000.
How am I able to set the accuracy to 4?

A couple of things. First, you mean "precision", not "accuracy". Second, you need to clarify why you want to do this, because a correct answer will depend on it.
If all you want to do is display the numbers with that precision, it is a formatting issue. You can use, e.g. System.out.printf("%.4f", value) or String.format().
If you are trying to to generate numbers with that precision, you could approximate by doing something like (rounding left out for simplicity):
double value = (int)(generateor.nextDouble() * 10000.0) / 10000.0;
Or if you want your range to be 0-10000 instead of 0-1:
double value = (int)(generateor.nextDouble() * 100000000.0) / 10000.0;
Due to the way floating-point numbers are stored, that will not be exact, but perhaps it is close enough for your purposes. If you need exact, you would want to store as integers, e.g.:
int value = (int)(generator.nextDouble() * 10000.0);
Then you can operate on that internally, and display as:
System.out.printf("%.4f", value / 10000.0);
Adjust multiplication factor above if you meant you wanted your range to be 0-10000.
If you are merely trying to generate a number in [0, 10000), you can use Random.nextInt(int) with a range specified, or simply cast the value to an int as above (optionally rounding).

Random generator = new Random();
double randomIndex = generator.nextDouble()*10000;
randomIndex=Math.floor(randomIndex * 10000) / 10000;//this is the trick

If you want 4 digits after the decimal mark you can simply do the following:
Random generator = new Random();
double randomIndex = Math.floor(generator.nextDouble()*10000 * 10000) /10000;

Random generator = new Random();
double randomIndex = Double.parseDouble(new DecimalFormat("##.####")
.format(generator.nextDouble() * 10000));

Simply
double result = generator.nextLong() / 10000.0;
Note, hoewever, that you can never be sure that the number has exactly 4 decimals, whenever you hit a number that is not representable in a double.
Anyway, the requirement is silly, because a double simply does not have decimal positions. Hence, to request 4 of them makes no sense.

Related

Best way to generate unique Random number in Java

I have to generate unique serial numbers for users consisting of 12 to 13 digits. I want to use random number generator in Java giving the system. Time in milliseconds as a seed to it. Please let me know about the best practice for doing so. What I did was like this
Random serialNo = new Random(System.currentTimeMillis());
System.out.println("serial number is "+serialNo);
Output came out as: serial number is java.util.Random#13d8cc98
For a bit better algorithm pick SecureRandom.
You passed a seed to the random constructor. This will pick a fixed sequence with that number. A hacker knowing the approximate time of calling, might restrict the number of attempts. So another measure is not using the constructor and nextLong at the same spot.
SecureRandom random = new SecureRandom​();
long n = random.nextLong();
A symmetric bit operation might help:
n ^= System.currentMillis();
However there is a unique number generation, the UUID, a unique 128 bits number, two longs. If you xor them (^) the number no longer is that unique, but might still be better having mentioned the circumstantial usage of random numbers.
UUID id = UUID.randomUUID();
long n = id.getLeastSignificantBits() ^ id.getMostSignificantBits();
Create a random number generator using the current time as seed (as you did)
long seed = System.currentTimeMillis();
Random rng = new Random​(seed);
Now, to get a number, you have to use the generator, rng is NOT a number.
long number = rng.nextLong();
According to the documentation, this will give you a pseudorandom number with 281.474.976.710.656 different possible values.
Now, to get a number with a maximum of 13 digits:
long number = rng.nextLong() % 10000000000000;
And to get a number with exactly 13 digits:
long number = (rng.nextLong() % 9000000000000) + 1000000000000;
First, import the Random class:
import java.util.Random;
Then create an instance of this class, with the current milliseconds as its seed:
Random rng = new Random(System.currentTimeMillis());
This line would generate an integer that can have up to 13 digits:
long result = rng.nextLong() % 10000000000000;
This line would generate an integer that always have 13 digits:
long result = rng.nextLong() % 9000000000000 + 1000000000000;
There are three ways to generate Random numbers in java
java.util.Random class
We can generate random numbers of types integers, float, double, long, booleans using this class.
Example :
//Random rand = new Random();
// rand_int1 = rand.nextInt(1000)
Math.random method : Can Generate Random Numbers of double type.
random(), this method returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Example :
Math.random());
//Gives output 0.15089348615777683
ThreadLocalRandom class
This class is introduced in java 1.7 to generate random numbers of type integers, doubles, booleans etc
Example :
//int random_int1 = ThreadLocalRandom.current().nextInt();
// Print random integers
//System.out.println("Random Integers: " + random_int1);

How do you generate a random decimal with decimals above 0 in Java?

I need to generate a random decimal from 0.85 to 1. I saw on other questions a lot of different methods, but all of them count on the beginning number to be 0. How do I do this?
Well, Math.random() will generate a number from 0 to 1, so Math.random()/100 will generate a number from 0 to 0.01, so Math.random()/100*15 will generate a number from 0 to 0.15, so Math.random()/100*15 + 0.85 will generate a number from 0.85 to 1
Another way to think of it:
double min = 0.85;
double max = 1.0;
double value = Math.random() * (max - min) + min;
If you want numbers between 0.85 and 1, inclusive, use SplittableRandom and its nextDouble(double origin, double bound) method, or use ThreadLocalRandom and its nextDouble(double origin, double bound) method.
Since the upper bound is exclusive in those methods, you need to bump up the double value by the smallest amount possible, which you can do by calling Math.nextUp(double d).
// Use one of these:
SplittableRandom rnd = new SplittableRandom();
ThreadLocalRandom rnd = ThreadLocalRandom.current();
// Then generate random values like this:
double value = rnd.nextDouble(0.85, Math.nextUp(1d));
For the purpose of providing an alternative, if random has type Random then a single double in the range .85 (inclusive) to 1 (exclusive) would be:
random.doubles(0.85, 1.00).findFirst().getAsDouble();
This is more useful if you wish to generate several values within the range.
Note that an advantage of Random over Math.random is that you can provide a seed which is useful for testing.

Randomly generating floats spanning the whole spectrum of valid floats

As part of random testing, I'm looking to generate random floats spanning the whole spectrum of valid floats (but excluding +/- infinity and NaN). I want very, very large numbers and minuscule numbers, both positive and negative.
Here's what I'm doing:
Random r = new Random();
float random_value = (r.nextFloat() - 0.5f) * Float.MAX_VALUE;
This seems like it should in theory work, but it only generates very large values. (ie. in the range of 1037 – 1038, positive and negative)
Any suggestions?
Your code should create uniformly distributed float values, that is, a uniform distribution in a purely mathematical sense. However, most of these values will be in the 1037-1038 range, simply because there are more mathematical values in that range than in the lower, everyday value range. In the real domain, there are 10 times as many values in the range 1037-1038 as 1036-1037, 10 times as many values in the range 1036-1037 as 1035-1036, and so on, so it's no surprise that just about all of them are of extremely large magnitude.
What I think you want is a completely random float value, with a range only in the valid float domain. Because a float is specified by an exponent and a mantissa, the limiting factor as to how many values are available in a given range is limited by the precision, not how many mathematical values are available. Specifically, there are precisely the same number of float values between a and b as there are between 2 * a and 2 * b, provided all values are within the float domain.
There is a one-to-one correspondence between all possible int values and all possible float values (including infinities and NaN), because both primitive types are represented by 32 bits.
Choose a random int value, across all possible int values, positive, 0, and negative, and convert the bit representation of the int to the corresponding bit representation of the float you want. You'll have to choose a random long and downcast to int. If you randomly get an infinity or an NaN, try again.
Random rnd = new Random();
float randomFloat = 0.0f;
do {
// downcast will cover negative int value range.
int randomInt = (int) rnd.nextLong(1L << 32);
float randomFloat = Float.intBitsToFloat(randomInt);
// Discard infinities and NaNs.
} while (randomFloat == Float.NEGATIVE_INFINITY ||
randomFloat == Float.POSITIVE_INFINITY ||
Float.isNaN(randomFloat));
You can get an uniform distribution by generating your floats using bits instead of arithmetic.
This could be an option:
public static float randomFloat() {
// Generate a random integer. These are uniform over the 32 bit words
Random r = new Random();
int intBits = r.nextInt();
// Make a float from the integer's bits
float f = Float.intBitsToFloat(intBits);
// Handle non-numeric cases
if (Float.isInfinite(f) || Float.isNaN(f)) {
// Only happens ~ 1/250 times
return randomFloat();
} else {
return f;
}
}
You are probably hitting precision issues. Try doing the multiplication at double precision and then casting down to a float afterwards.
i.e.
float random_value = (float)((r.nextDouble() - 0.5) * Float.MAX_VALUE);
Firstly you want to generate a random float between -1 and 1. To do this:
Random r = new Random();
float random_value = r.nextFloat() * 2 - 1
and then scale that:
Random r = new Random();
float random_value = (r.nextFloat() * 2 - 1) * Float.MAX_VALUE

Generate random double from random long

in Java I have a random generator that generates random number from -2^63 to 2^63 and that is NOT the java.util.Random.
I need to generate random double in (0,1), this is what I've done so far:
return (seed/(double)(9223372036854775807L))/2+0.5;//seed is a random long
Is this right? Are there any numerical problem (underflow?)?
Could be better/faster?
Thank you.
I would use Math.scalb as the most efficient and ensures there is no funny behaviour due to rounding or representation error
double d = Math.scalb(seed >>> 1, -63);
You can only use 53 bits in a double so some will be discarded.
If you run
long seed = Long.MAX_VALUE;
System.out.println(Math.scalb(seed >>> 1, -63));
prints
0.5
With a seed of 0 you get 0.0
With a seed of -1 you get 1.0
I would prefer to see just a single division.
0.5+(seed/1.84467440737096E+19);
That said, you are going to run up against issues with floating point accuracy since you have 64 random integer bits which you then try to squeeze into 53 bits of double precision. You may be better off making a dedicated generator for floating point values, but I could not say for sure since I don't know your motivation.
The fastest way would probably just be to set the first three bits in your long to 0 and then use those bits to make a double.:
double rand = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
This works by forcing the sign to positive, and exponent to be less than 0, which will cause the mantissa to be shifted right at least once. It gives an even distribution assuming all the ints in the long are completely random. Here is a full Java program that uses Random to generate random longs, and then this method to convert them to double's between 0 and 1:
import java.util.Random;
class Main{
public static void main(String[] args){
Random rand = new Random();
long seed = rand.nextLong();
double x = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
System.out.println(x);
}
}
This is the output of 10 executions:
1.1211565592484309E-247
8.84224349357039E-242
6.956043405745214E-271
3.747746366809532E-232
9.302628573486166E-158
1.1440116527034282E-166
1.2574577719255876E-198
5.104999671234867E-269
3.360619724894072E-213
1.5654452507283312E-220
Edit
This gives a uniform distribution of all possible doubles between 0 and 1. Since there are many more small doubles you will likely never see a number close to 1. You can fix this by generating a new exponent based on the bits of the existing one, but you need a loop to do it, so it probably isn't the fastest method after factoring this in:
long exponent = 0;
for(int i = 52; (seed >>> i & 1) > 0; i++) exponent++;
double x = Double.longBitsToDouble(seed & 0x000FFFFFFFFFFFFFL | ((1022 - exponent) << 52));
0.4773960377161338
0.929045618651037
0.7183096209363845
0.33962049395497845
0.45568660174922454
0.11670190555677815
0.09371618427480996
0.8192870898479095
0.9365016017283178
0.11311614413193898
Not exactly. I think that easier way is to do the following:
new Random(seed).nextDouble()
Unless I'm misreading your need to have a random double from 0 to 1, Java's built in Math.random does just that. So you could avoid all the conversion you are currently doing.

Getting a random number between 0 and 0.06 in Java?

How do you get random Double values between 0.0 and 0.06 in Java?
nextDouble() returns a random floating-point number uniformly distributed between 0 and 1. Simply scale the result as follows:
Random generator = new Random();
double number = generator.nextDouble() * .06;
See this documentation for more examples of Random.
This will give you a random double in the interval [0,0.06):
double r = Math.random()*0.06;
To avoid the inexactness of floating point values you can use a double/integer calculation which is more accurate (at least on x86/x64 platforms)
double d = Math.random() * 6 / 100;
you need to have a look at the Random class
Based on this java doc (though watch the boundary condition):
new Random().nextDouble() * 0.06

Categories