我需要生成[-0.5, 0.5]
范围内的随机实数,包括两个边界。
我发现了产生相似范围的各种方法,例如
-0.5 + Math.random()
但是上限始终是专有的,我也需要包含在内。 0.5
必须在范围内。
答案 0 :(得分:8)
一种实现此目的的方法是,将随机int
创建为-500至500,然后将其除以1000。
int max = 500;
int min = -500;
int randomInt = rand.nextInt((max - min) + 1) + min;
float randomNum = randomInt / 1000.00f;
System.out.println(randomNum);
您可以通过在整数边界和除数中添加和删除零来更改精度。 (例如:创建从-5到+5的整数,然后除以10以降低精度)
该解决方案的一个缺点是它不使用浮点/双精度数据类型提供的最大精度。
答案 1 :(得分:3)
您可以通过比期望的最大值大的最小值( epsilon )来调整上限。要找到ε,请从任意正值开始,并使其尽可能小:
double min = -0.5;
double max = 0.5;
double epsilon = 1;
while (max + epsilon / 2 > max) {
epsilon /= 2;
}
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, max + epsilon);
编辑:@DodgyCodeException建议的替代方法(结果与上述相同):
double min = -0.5;
double max = 0.5;
double maxPlusEpsilon = Double.longBitsToDouble(Double.doubleToLongBits(max) + 1L)
Random random = ThreadLocalRandom.current();
DoubleStream randomDoubles = random.doubles(min, maxPlusEpsilon);
答案 2 :(得分:3)
我还没有看到在IEEE-754 Double表示中使用位摆弄的任何答案,所以这是一个。
基于观察到下一个二进制指数的过渡与在二进制表示中添加1
相同(实际上这是设计使然):
Double.longBitsToDouble(0x3ff0000000000000L) // 1.0
Double.longBitsToDouble(0x3ffFFFFFFFFFFFFFL) // 1.9999999999999998
Double.longBitsToDouble(0x4000000000000000L) // 2.0
我想到了这个
long l = ThreadLocalRandom.current().nextLong(0x0010000000000001L);
double r = Double.longBitsToDouble(l + 0x3ff0000000000000L) - 1.5;
此技术仅适用于跨越二进制数(1、2、4、8、0.5、0.25等)的范围,但是对于那些范围,此方法可能是最有效和最准确的方法。本示例的跨度调整为1。对于不跨二进制范围的范围,您仍然可以使用此技术来获得不同的跨度。应用该技术获得[0,1]范围内的数字并将结果缩放到所需的跨度。精度损失可以忽略不计,并且所得的精度实际上与Random.nextDouble(double, double)
相同。
对于其他范围,执行以下代码以找到偏移量:
double span = 0.125;
if (!(span > 0.0) || (Double.doubleToLongBits(span) & 0x000FFFFFFFFFFFFFL) != 0)
throw new IllegalArgumentException("'span' is not a binary number: " + span);
if (span * 2 >= Double.MAX_VALUE)
throw new IllegalArgumentException("'span' is too large: " + span);
System.out.println("Offset: 0x" + Long.toHexString(Double.doubleToLongBits(span)));
当将此偏移量插入实际代码的第二行时,您将获得[span,2 * span]范围内的值。减去span
得到一个从0开始的值。
答案 3 :(得分:1)
给出答案如何回答,这是一个随时可用的功能:
public static double randomFloat(double minInclusive, double maxInclusive, double precision) {
int max = (int)(maxInclusive/precision);
int min = (int)(minInclusive/precision);
Random rand = new Random();
int randomInt = rand.nextInt((max - min) + 1) + min;
double randomNum = randomInt * precision;
return randomNum;
}
然后
System.out.print(randomFloat(-0.5, 0.5, 0.01));
答案 4 :(得分:1)
@OH GOD SPIDERS' answer给了我一个想法,可以将其发展为可以提供更高精确度的答案。当转换为nextLong()
时,double
给出的值在MIN_VALUE到MAX_VALUE之间,并且具有足够的精度。
double randomNum = (rand.nextLong() / 2.0) / Long.MAX_VALUE;
包含边界的证明:
assert (Long.MIN_VALUE/2.0)/Long.MAX_VALUE == -0.5;
assert (Long.MAX_VALUE/2.0)/Long.MAX_VALUE == 0.5;
答案 5 :(得分:0)
Random.nextDouble给出的值为[0,1]。因此,要将其映射到[-0.5,0.5]的范围,只需减去0.5。
您可以使用此代码获得所需的输出
double value = r.nextDouble() - 0.5;