前言
因为突发奇想要生成一批学生考试成绩的测试数据,所以就考虑到随机数的生成,但是发现java各种库(Math、Random、ThreadLocalRandom)自带的随机数生成,取值都是 [x,y) ,于是为了搞出double形式的 [x,y] 取值范围内随机数,诞生了这一篇文章。
(关于为什么这些库的随机数生成,取值范围都是[x, y),大家自行去研究,这里不作展开)
纵览CSDN、博客园、stackflow,我阅读了应该不下几十篇文章/问答,对于整型,也就是int类型、long类型的指定范围内随机数生成,大家都是信手拈来。
但是一旦到达double,这种还有小数部分的数字,就出现了各种欠缺。
像是使用取余数之类的手段,我始终觉得会如同一位外国友人所言——将会降低取值的密度。至于其他的一些手段,我也有试着验证过,有的是会使得取值的概率不一,有的甚至并不能取到闭区间的上限值。
总而言之,似乎在double类型的情况下,指定范围内取随机数,我并未找到一个很好的思路。
于是,我只能先提供出当下觉得相对而言比较认可的写法,希望可以抛砖引玉,得到更好的思路。
一、获取指定范围内的int随机数
/**
* 获取指定范围内的整型随机数
* @param min 最小值
* @param minReach 是否取到最小值
* @param max 最大值
* @param maxReach 是否取到最大值
* @return 符合要求的随机整型数字
*/
public static int getIntegerNumber(Integer min, boolean minReach, Integer max, boolean maxReach) {
int num;
Random rand = new Random();
if (minReach) {
// [min, max]
if (maxReach) {
// num = min + rand.nextInt(max - min + 1); // 方式一
num = ThreadLocalRandom.current().nextInt(min, max + 1); // 方式二
} else { // [min, max)
// num = min + rand.nextInt(max - min); // 方式一
num = ThreadLocalRandom.current().nextInt(min, max); // 方式二
}
} else {
// (min, max]
if (maxReach) {
num = max - rand.nextInt(max - min);
} else { // (min, max) = [min + 1, max)
num = min + 1 + rand.nextInt(max - min - 1);
}
}
return num;
}
注意:ThreadLocalRandom得JDK1.7后才支持
二、获取指定范围内的double随机数
/**
* 生成指定范围的随机double数字
* @param min 最小值
* @param minReach 最小值是否可以取到(true-可以)
* @param max 最大值
* @param maxReach 最大值是否可以取到(true-可以)
* @return 符合要求的随机数
*/
public static double genDoubleNumber(double min, boolean minReach, double max, boolean maxReach) {
double num;
if(minReach) {
// [min, max]
if(maxReach) {
// todo 虽然涉及循环,但是目前没有找到不降低取值密度的写法
// 使用取余数之类带整型的写法,基本都会降低取值密度
do {
// 该公式的取值范围是:[min, max + 0.001)
num = ThreadLocalRandom.current().nextDouble(min, max + 0.001);
} while(num > max); // 排除掉取值大于max的情况,剩下的就是符合要求的值了
} else { // [min, max)
// num = min + Math.random() * (max - min); // 方式一
num = ThreadLocalRandom.current().nextDouble(min, max); // 方式二
}
} else {
// (min, max]
if(maxReach) {
num = max - Math.random() * (max - min);
} else { // (min, max)
/**
* 解释:
* (max - 1 - Math.random() * (max - min - 1)) ∈ (min, max - 1]
* Math.random() ∈ [0, 1)
* 两者相加,可知最终结果取值范围就是 (min, max)
* 注意,不要尝试使用乘法结合律
*/
num = Math.random() + (max - 1 - Math.random() * (max - min - 1));
}
}
return num;
}
N、补充
本文使用代码基于我写的存放于github的公开代码(点击前往仓库),欢迎前去查看是否有遗漏或者bug或者复制下来检验
如果你正无聊,不妨浏览我的更多奇奇怪怪的笔记文章。
如果你觉得本文对你有所收获,请点赞、转发,让更多人看到这篇文章,谢谢!!!
如果你觉得有哪里不对,也欢迎在评论区留言指教!!!