Kelas acak memiliki metode untuk menghasilkan int acak dalam rentang tertentu. Sebagai contoh:
Random r = new Random();
int x = r.nextInt(100);
Ini akan menghasilkan bilangan int lebih atau sama dengan 0 dan kurang dari 100. Saya ingin melakukan hal yang sama persis dengan bilangan panjang.
long y = magicRandomLongGenerator(100);
Kelas acak hanya memiliki nextLong (), tetapi tidak memungkinkan untuk menyetel rentang.
java
random
range
long-integer
Vilius Normantas
sumber
sumber
java.util.Random
hanya menggunakan distribusi 48 bit (lihat detail implementasi), jadi tidak akan memiliki distribusi normal.Jawaban:
Mulai dari Java 7 (atau Android API Level 21 = 5.0+) Anda bisa langsung menggunakan
ThreadLocalRandom.current().nextLong(n)
(untuk 0 ≤ x <n) danThreadLocalRandom.current().nextLong(m, n)
(untuk m ≤ x <n). Lihat jawaban @Alex untuk detailnya.Jika Anda terjebak dengan Java 6 (atau Android 4.x), Anda perlu menggunakan perpustakaan eksternal (misalnya
org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1)
, lihat jawaban @mawaldne ), atau menerapkan milik Anda sendirinextLong(n)
.Menurut https://docs.oracle.com/javase/1.5.0/docs/api/java/util/Random.html
nextInt
diimplementasikan sebagaipublic 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; }
Jadi kami dapat memodifikasi ini untuk melakukan
nextLong
:long nextLong(Random rng, long n) { // error checking and 2^x checking removed for simplicity. long bits, val; do { bits = (rng.nextLong() << 1) >>> 1; val = bits % n; } while (bits-val+(n-1) < 0L); return val; }
sumber
rng.nextLong() % n
akan memberikan nilai yang seragam (anggap semua bit baik). Anda dapat mengabaikan bagian itu jika Anda mau.m <= x <= n
, bagaimana Anda akan mengubah solusi Anda?m
dann
dapat diperoleh dengan nomor acak antara0
dann-m
, lalu tambahkanm
.ThreadLocalRandom
ThreadLocalRandom
memilikinextLong(long bound)
metode.long v = ThreadLocalRandom.current().nextLong(100);
Ini juga memiliki
nextLong(long origin, long bound)
jika Anda membutuhkan asal selain 0. Lulus asal (inklusif) dan terikat (eksklusif).long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive.
SplittableRandom
memilikinextLong
metode yang sama dan memungkinkan Anda untuk memilih benih jika Anda ingin urutan angka yang dapat direproduksi.sumber
Metode standar untuk menghasilkan angka (tanpa metode utilitas) dalam suatu rentang adalah dengan hanya menggunakan ganda dengan rentang:
long range = 1234567L; Random r = new Random() long number = (long)(r.nextDouble()*range);
akan memberi Anda jarak antara 0 (inklusif) dan rentang (eksklusif). Demikian pula jika Anda menginginkan angka antara x dan y:
long x = 1234567L; long y = 23456789L; Random r = new Random() long number = x+((long)(r.nextDouble()*(y-x)));
akan memberi Anda long dari 1234567 (inklusif) sampai 123456789 (eksklusif)
Catatan: centang tanda kurung, karena mentransmisikan ke panjang memiliki prioritas lebih tinggi daripada perkalian.
sumber
bound
harus kurang dari bilangan bulat terbesar yang dapat dienkode dalam double, 2 ^ 53.Metode di atas bekerja dengan baik. Jika Anda menggunakan apache commons (org.apache.commons.math.random) periksa RandomData. Ini memiliki metode: nextLong (panjang lebih rendah, panjang atas)
http://commons.apache.org/math/userguide/random.html
http://commons.apache.org/math/api-1.1/org/apache/commons/math/random/RandomData.html#nextLong(long,%20long)
sumber
Gunakan operator '%'
Dengan menggunakan operator '%', kami mengambil sisanya bila dibagi dengan nilai maksimum Anda. Ini menyisakan kita hanya dengan angka dari 0 (inklusif) hingga pembagi (eksklusif).
Sebagai contoh:
public long randLong(long min, long max) { return (new java.util.Random().nextLong() % (max - min)) + min; }
sumber
if (max == min)
if (nextLong() >= 0)
min = 0
danmax = 2 * (MAX_LONG / 3)
, maka Anda dua kali lebih mungkin untuk mendapatkan nilai daripada[0, MAX_LONG / 3]
jika Anda mendapatkannya[MAX_LONG / 3, 2 * (MAX_LONG / 3)]
.nextLong
mengembalikan nilai negatif, sisanya akan menjadi negatif, dan nilainya akan berada di luar rentang.Lebih jauh meningkatkan jawaban kennytm: Implementasi subclass yang mempertimbangkan implementasi aktual di Java 8 akan menjadi:
public class MyRandom extends Random { public long nextLong(long bound) { if (bound <= 0) { throw new IllegalArgumentException("bound must be positive"); } long r = nextLong() & Long.MAX_VALUE; long m = bound - 1L; if ((bound & m) == 0) { // i.e., bound is a power of 2 r = (bound * r) >> (Long.SIZE - 1); } else { for (long u = r; u - (r = u % bound) + m < 0L; u = nextLong() & Long.MAX_VALUE); } return r; } }
sumber
if ((bound & m) == 0) { r = (bound * r) >> (Long.SIZE - 1); }
Pertama, mudah untuk menunjukkan dengan pengujian unit bahwa ini tidak benar-benar menghasilkan angka dalam kisaran [0, terikat). Kedua, ini tidak perlu rumit:r = r & m
akan mencapai hasil yang diinginkan, dan pada dasarnya itulah yang dilakukan implementasi Java 8 saat ini. Mungkin saja implementasinya berbeda ketika jawaban ini ditulis, tetapi tidak mungkin apa yang ditampilkan.Jika Anda menginginkan pseudorandom terdistribusi seragam dalam kisaran [0,
m
), coba gunakan operator modulo dan metode nilai absolut yang digabungkan dengannextLong()
metode seperti yang terlihat di bawah ini:Di mana
rand
objek Random Anda.Operator modulo membagi dua angka dan mengeluarkan sisa angka tersebut. Sebagai contoh,
3 % 2
adalah1
karena sisa 3 dan 2 adalah 1.Karena
nextLong()
menghasilkan pseudorandom yang terdistribusi seragam dalam rentang [- (2 ^ 48), 2 ^ 48) (atau di suatu tempat dalam rentang itu), Anda perlu mengambil nilai absolutnya. Jika tidak, modulonextLong()
metode memiliki peluang 50% untuk mengembalikan nilai negatif, yang berada di luar rentang [0,m
).Apa yang awalnya Anda minta adalah pseudorandom yang didistribusikan secara seragam di kisaran [0,100). Kode berikut melakukannya:
Math.abs(rand.nextLong()) % 100;
sumber
Bagaimana dengan ini:
public static long nextLong(@NonNull Random r, long min, long max) { if (min > max) throw new IllegalArgumentException("min>max"); if (min == max) return min; long n = r.nextLong(); //abs (use instead of Math.abs, which might return min value) : n = n == Long.MIN_VALUE ? 0 : n < 0 ? -n : n; //limit to range: n = n % (max - min); return min + n; }
?
sumber
Metode di bawah ini akan mengembalikan Anda nilai antara 10000000000 hingga 9999999999
long min = 1000000000L long max = 9999999999L public static long getRandomNumber(long min, long max){ Random random = new Random(); return random.nextLong() % (max - min) + max; }
sumber
Dari Java 8 API
Mungkin lebih mudah untuk mengambil implementasi aktual dari dokumen API https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long- mereka menggunakannya untuk menghasilkan aliran rindu. Dan asal Anda bisa jadi "0" seperti di pertanyaan.
long nextLong(long origin, long bound) { long r = nextLong(); long n = bound - origin, m = n - 1; if ((n & m) == 0L) // power of two r = (r & m) + origin; else if (n > 0L) { // reject over-represented candidates for (long u = r >>> 1; // ensure nonnegative u + m - (r = u % n) < 0L; // rejection check u = nextLong() >>> 1) // retry ; r += origin; } else { // range not representable as long while (r < origin || r >= bound) r = nextLong(); } return r; }
sumber
Dari halaman di Random :
Jadi, jika Anda ingin mendapatkan
Long
, Anda tidak akan mendapatkan kisaran 64 bit penuh.Saya akan menyarankan bahwa jika Anda memiliki rentang yang mendekati pangkat 2, Anda membangun
Long
seperti dalam cuplikan itu, seperti ini:next(32) + ((long)nextInt(8) << 3)
untuk mendapatkan rentang 35 bit, misalnya.
sumber
Metode yang menggunakan
r.nextDouble()
harus menggunakan:long number = (long) (rand.nextDouble()*max); long number = x+(((long)r.nextDouble())*(y-x));
sumber
public static long randomLong(long min, long max) { try { Random random = new Random(); long result = min + (long) (random.nextDouble() * (max - min)); return result; } catch (Throwable t) {t.printStackTrace();} return 0L; }
sumber
Random
contoh di hoc, Anda tidak boleh menangkapThrowable
s atau pengecualian lain jika tidak diperlukan, Anda harus mencatat kesalahan dengan beberapa jenis kerangka kerja logging (yaitu SLF4J) daripada menggunakanprintStackTrace
.Jika Anda dapat menggunakan aliran java, Anda dapat mencoba yang berikut ini:
Random randomizeTimestamp = new Random(); Long min = ZonedDateTime.parse("2018-01-01T00:00:00.000Z").toInstant().toEpochMilli(); Long max = ZonedDateTime.parse("2019-01-01T00:00:00.000Z").toInstant().toEpochMilli(); randomizeTimestamp.longs(generatedEventListSize, min, max).forEach(timestamp -> { System.out.println(timestamp); });
Ini akan menghasilkan angka dalam rentang yang diberikan untuk waktu yang lama.
sumber
import java.util*; Random rnd = new Random (); long name = Math.abs(rnd.nextLong());
Ini seharusnya berhasil
sumber
// gunakan waktu sistem sebagai nilai benih untuk mendapatkan nomor acak yang baik
Random random = new Random(System.currentTimeMillis()); long x; do{ x=random.nextLong(); }while(x<0 && x > n);
// Ulangi sampai mendapatkan angka yang lebih besar atau sama dengan 0 dan lebih kecil dari n
sumber
n
1, atau katakan 2? Loop akan melakukan banyak iterasi.