我编写了一些Java代码来生成伪随机数,但是我遇到了我认为正在解决的问题,要求它与Ruby中的相同代码相匹配。这就是我在Java中所拥有的:
public class randTest {
private final static Double A = Math.pow(5,13);
private final static Integer S = 314159265;
private final static Double minVal = Math.pow(2, -46);
private final static Double maxVal = Math.pow(2, 46);
private final static Double newMax = 10.0;
private static Double r(Integer k) {
Double powS = Math.pow(A, k) * S;
Double xk = powS % maxVal.intValue();
Double result = minVal * xk;
System.out.println("k = " + k + ", pows = " + powS + ", xk = " + xk + ", result = " + result);
return result;
}
}
在Ruby(我的工作参考实现)中也是如此:
A = 5 ** 13
S = 314159265
MIN_VAL = 2 ** -46
MAX_VAL = 2 ** 46
NEW_MAX = 10
def r(k) # was generate_random
powS = (A ** k) * S
xk = powS % MAX_VAL
result = MIN_VAL * xk
puts "k = #{k}, pows = #{powS}, xk = #{xk}, result = #{result}"
return result
end
由于某种原因,输出差异很大(但Ruby的一个是正确的)。这是我打电话给r(4):
爪哇:
k = 4, pows = 6.9757369880463215E44, xk = 1.512592341E9, result = 2.1495230001278287E-5
红宝石:
k = 4, pows = 697573698804632158498861826956272125244140625, xk = 55279057169489, result = 0.785562650228954
为什么powS
可以在xk
中正确计算,而不是maxVal.intValue()
?请注意,在Java版本上,我需要使用maxVal
而不是Double
,否则返回零。我也尝试用BigDecimal
替换{{1}} s也无济于事。
答案 0 :(得分:3)
当您致电maxVal.intValue()
看一下BigDecimal和BigInteger,就像你的ruby片段一样。
顺便说一句:如果你使用位于Java之上的groovy,那么它会立即使用BigDecimal。
示例代码:
public class Rounding {
private final static BigDecimal A = BigDecimal.valueOf(Math.pow(5, 13));
private final static int S = 314159265;
private final static BigDecimal minVal = BigDecimal.valueOf(Math
.pow(2, -46));
private final static BigDecimal maxVal = BigDecimal
.valueOf(Math.pow(2, 46));
private final static BigDecimal newMax = BigDecimal.valueOf(10);
public static void main(final String[] args) {
r(4);
}
private static void r(final int k) {
final BigDecimal powS = A.pow(k).multiply(BigDecimal.valueOf(S));
final BigDecimal xk = powS.remainder(new BigDecimal(maxVal
.toBigInteger()));
final BigDecimal result = minVal.multiply(xk);
System.out.println("k = " + k + ", pows = " + powS + ", xk = " + xk
+ ", result = " + result);
}
}
产地:
k = 4, pows = 697573698804632158498861826956272125244140625, xk = 55279057169489, result = 0.785562650228953900455100455956
答案 1 :(得分:2)
我的Java生锈了,但intValue()没有转到32位的int值? 2 ^ 46太大而不适合那里。
答案 2 :(得分:2)
当你调用intValue()时,double值将被强制转换为int。
Java的整数MAX_VALUE:
保持int的最大值的常量可以是2 ^ 31-1。
你的MAX_VAL:
2 ** 46
即使是长型也不能保持足够大的价值。我认为正如@toolkit所说,你需要java.math包中的BigInteger类。
答案 3 :(得分:2)
两件事:
maxVal.intValue()
返回2147483647,远远低于它应该的大约7.03E13。答案 4 :(得分:1)
697573698804632150000000000000000000000000000
和
697573698804632158498861826956272125244140625
数字不一样。通过拥有如此大的数字,你在Java中失去了精度,其中Ruby具有任意精度整数运算。将算术运算应用于Java中较大的数字将导致[伪]不可预测的结果。
答案 5 :(得分:1)
问题在于Double无法保留您尝试放入的值,因此它会被截断。
对于像这样的大值,你需要使用java.math.BigDecimal,这允许十进制值具有任意大的精度。
这是你使用BigDecimal重做Java样本:
public class RandTest {
private final static BigDecimal A = new BigDecimal(5).pow(13);
private final static BigDecimal S = new BigDecimal(314159265);
private final static BigDecimal minVal =
new BigDecimal(2).pow(-46, new MathContext(100));
private final static BigDecimal maxVal = new BigDecimal(2).pow(46);
private final static BigDecimal newMax = new BigDecimal(10.0);
private static BigDecimal r(Integer k) {
BigDecimal powS = A.pow(k).multiply(S);
BigDecimal xk = powS.remainder(maxVal);
BigDecimal result = minVal.multiply(xk);
System.out.println("k = " + k + ", pows = " + powS + ", xk = " + xk
+ ", result = " + result);
return result;
}
}
此版本属性返回您正在寻找的正确结果。