代码之家  ›  专栏  ›  技术社区  ›  Chris Bunch

Java—数字四舍五入问题

  •  1
  • Chris Bunch  · 技术社区  · 17 年前

    我编写了一些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
    

    爪哇:

    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() 而不是 maxVal ,否则返回零。我也试着换了新的 Double 和 BigDecimal

    6 回复  |  直到 17 年前
        1
  •  3
  •   toolkit    17 年前

    您在调用时遇到截断错误 maxVal.intValue()

    顺便说一句:如果你使用 groovy

    示例代码:

    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
    
        2
  •  2
  •   Marc Hughes    17 年前

    我的Java已经过时了,但是intValue()不是变成了32位的int值吗?2^46太大了,放不进去。

        3
  •  2
  •   Pesto    17 年前

    两件事:

    1. 在这种情况下,你需要 BigInteger 以确保值不会溢出其数据类型。
    2. 在相关问题上,, maxVal.intValue() 返回2147483647,远低于它应该达到的大约7.03E13。
        4
  •  2
  •   brabster    17 年前

    调用intValue()时,双精度值将转换为int。

    Java的整数最大值:

    您的最大值:

    即使是long类型也不能保存足够大的值。我认为正如@toolkit所说,您需要java.math包中的biginger类。

        5
  •  1
  •   Sparr    17 年前

    697573698804632150000000000000000000000000000
    和
    697573698804632158498861826956272125244140625
    不是同一个数字。在Java中,由于有这么大的数字,而Ruby有任意精度的整数算法,所以会丢失精度。在Java中对如此大的数字应用算术运算将导致[pseudo-]不可预测的结果。

        6
  •  1
  •   BCunningham    17 年前

    问题是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;
        }
    }
    

    此版本属性返回您要查找的正确结果。