2011-02-04 35 views
5

Câu hỏi này: How to generate a random BigInteger mô tả cách để đạt được cùng ngữ nghĩa như Random.nextInt (int n) cho BigIntegers.Làm cách nào để tạo một BigDecimal ngẫu nhiên trong Java?

Tôi muốn thực hiện tương tự cho BigDecimal và Random.nextDouble().

Một câu trả lời trong câu hỏi trên gợi ý tạo một BigInteger ngẫu nhiên và sau đó tạo một BigDouble từ nó với một tỷ lệ ngẫu nhiên. Một thử nghiệm rất nhanh cho thấy đây là một ý tưởng rất tồi :)

Trực giác của tôi là sử dụng phương pháp này sẽ yêu cầu số nguyên được chia tỷ lệ bằng một cái gì đó như n-log10(R), trong đó n là số chữ số chính xác được yêu cầu trong đầu ra và R là BigInteger ngẫu nhiên. Điều này sẽ cho phép số lượng chữ số chính xác được hiển thị sao cho (ví dụ) 1 -> 10^-64 và 10^64 -> 1.

Giá trị tỷ lệ cũng cần được chọn chính xác cho kết quả giảm trong phạm vi [0,1].

Có ai đã làm điều này trước đây và họ có biết kết quả được phân phối chính xác không? Có cách nào tốt hơn để đạt được điều này?

EDIT: Nhờ @biziclop để điều chỉnh hiểu biết của tôi về đối số quy mô. Ở trên là không cần thiết, một yếu tố quy mô không đổi có hiệu quả mong muốn.

Để tham khảo sau, tôi (hình như làm việc code) là:

private static BigDecimal newRandomBigDecimal(Random r, int precision) { 
    BigInteger n = BigInteger.TEN.pow(precision); 
    return new BigDecimal(newRandomBigInteger(n, r), precision); 
} 

private static BigInteger newRandomBigInteger(BigInteger n, Random rnd) { 
    BigInteger r; 
    do { 
     r = new BigInteger(n.bitLength(), rnd); 
    } while (r.compareTo(n) >= 0); 

    return r; 
} 

Trả lời

3

Chắc chắn rất dễ dàng ... nếu tôi chỉ biết bạn muốn gì. Đối với một số được phân bố đồng nhất trong phạm vi [0, 1) và chữ số thập phân N chính xác tạo ra một BigInteger đồng nhất nhỏ hơn 10 * N và chia tỷ lệ theo 10 * N.

+0

Đó là phần "tỷ lệ ngẫu nhiên" của câu trả lời ban đầu sai. Phương pháp này sẽ ổn thôi. – DJClayworth

+0

Bạn có thể tạo một BigInteger thống nhất nhỏ hơn 10^N mua tạo nhiều số nguyên [0, 10^m] và kết hợp chúng. –

+0

Phải, nhưng có một câu hỏi tương ứng với câu trả lời hay được liên kết trong câu đầu tiên của câu hỏi này. Đề xuất của bạn cũng có thể hoạt động tốt, đặc biệt là với m = 9 do đó random.nextInt() có thể được sử dụng. – maaartinus

1

tôi có thể thiếu rõ ràng ở đây nhưng làm thế nào về việc tạo ra hai ngẫu nhiên BigInteger s, một là phần số nguyên, và khác các phân đoạn ? Rõ ràng là phạm vi của bigint "phân số" sẽ được quyết định bởi độ chính xác bạn muốn cho phép, mà bạn không thể thoát khỏi việc ghim xuống.

Cập nhật: Điều này có thể được đơn giản hơn nữa để làm việc chỉ với một bigint ngẫu nhiên. Nếu bạn muốn một số ngẫu nhiên giữa 0 và n với độ chính xác thập phân k (trong đó k là hằng số), bạn chỉ cần tạo một số ngẫu nhiên từ 0 đến n * 10^k và chia cho 10^k.

+0

Kết quả của việc này không được phân phối đồng đều. Tôi đã thử điều này, và kết quả được phân bố đều trên phần phân đoạn, có nghĩa là 10^-27 cũng giống như một số giữa 0,01 và 0,1 xuất hiện trong kết quả. 10^-27 nên có 26 đơn đặt hàng trở nên ít có khả năng xuất hiện hơn một số trong phạm vi 0.1-0.01 –

+0

@Mike Houston Tôi bị thiếu rõ ràng sau đó, bởi vì tôi vẫn không hiểu.Bạn có muốn nó được phân phối đồng đều hay không? – biziclop

+0

@Mike Houston Nope, vẫn không hiểu. Nếu bạn lấy một biến phân bố đồng đều dài tối đa n chữ số và bạn chia nó thành 10^n, thì nó vẫn được phân bố đều. – biziclop

2

Tôi đã tạo một bài đăng về việc tạo một BigInteger ngẫu nhiên Andy Turner's answer about generating a random BigInteger. Tôi không sử dụng trực tiếp để tạo ra một BigDecimal ngẫu nhiên. Về cơ bản, mối quan tâm của tôi là sử dụng các cá thể ngẫu nhiên độc lập để tạo ra mỗi chữ số trong một số. Một vấn đề tôi nhận thấy là với Random chỉ có rất nhiều giá trị và số cụ thể mà bạn nhận được trong một hàng. Ngoài ra, thế hệ cố gắng duy trì một cái gì đó của một phân phối thậm chí các giá trị được tạo ra. Giải pháp của tôi phụ thuộc vào thứ gì đó lưu trữ một mảng hoặc tập hợp các trường hợp ngẫu nhiên và gọi những trường hợp này. Tôi nghĩ rằng đây là một cách tốt để đi về nó và tôi đang cố gắng để tìm hiểu, vì vậy quan tâm nếu có ai có bất kỳ con trỏ hoặc chỉ trích về cách tiếp cận này.

/** 
* 
* @param a_Random 
* @param decimalPlaces 
* @param lowerLimit 
* @param upperLimit 
* @return a pseudo randomly constructed BigDecimal in the range from 
* lowerLimit to upperLimit inclusive and that has up to decimalPlaces 
* number of decimal places 
*/ 
public static BigDecimal getRandom(
     Generic_Number a_Generic_Number, 
     int decimalPlaces, 
     BigDecimal lowerLimit, 
     BigDecimal upperLimit) { 
    BigDecimal result; 
    BigDecimal range = upperLimit.subtract(lowerLimit); 
    BigDecimal[] rangeDivideAndRemainder = 
      range.divideAndRemainder(BigDecimal.ONE); 
    BigInteger rangeInt = rangeDivideAndRemainder[0].toBigIntegerExact(); 
    BigInteger intComponent_BigInteger = Generic_BigInteger.getRandom(
      a_Generic_Number, 
      rangeInt); 
    BigDecimal intComponent_BigDecimal = 
      new BigDecimal(intComponent_BigInteger); 
    BigDecimal fractionalComponent; 
    if (intComponent_BigInteger.compareTo(rangeInt) == 0) { 
     BigInteger rangeRemainder = 
       rangeDivideAndRemainder[1].toBigIntegerExact(); 
     BigInteger fractionalComponent_BigInteger = 
       Generic_BigInteger.getRandom(a_Generic_Number, rangeRemainder); 
     String fractionalComponent_String = "0."; 
     fractionalComponent_String += fractionalComponent_BigInteger.toString(); 
     fractionalComponent = new BigDecimal(fractionalComponent_String); 
    } else { 
     fractionalComponent = getRandom(
       a_Generic_Number, decimalPlaces); 
    } 
    result = intComponent_BigDecimal.add(fractionalComponent); 
    result.add(lowerLimit); 
    return result; 
} 

/** 
* Provided for convenience. 
* @param a_Generic_BigDecimal 
* @param decimalPlaces 
* @return a random BigDecimal between 0 and 1 inclusive which can have up 
* to decimalPlaces number of decimal places 
*/ 
public static BigDecimal getRandom(
     Generic_Number a_Generic_Number, 
     int decimalPlaces) { 
    //Generic_BigDecimal a_Generic_BigDecimal = new Generic_BigDecimal(); 
    Random[] random = a_Generic_Number.get_RandomArrayMinLength(
      decimalPlaces); 
    //System.out.println("Got Random[] size " + random.length); 
    String value = "0."; 
    int digit; 
    int ten_int = 10; 
    for (int i = 0; i < decimalPlaces; i++) { 
     digit = random[i].nextInt(ten_int); 
     value += digit; 
    } 
    int length = value.length(); 
    // Tidy values ending with zero's 
    while (value.endsWith("0")) { 
     length--; 
     value = value.substring(0, length); 
    } 
    if (value.endsWith(".")) { 
     value = "0"; 
    } 
    BigDecimal result = new BigDecimal(value); 
    //result.stripTrailingZeros(); 
    return result; 
} 
+0

Tôi không hiểu ý bạn là gì "với ngẫu nhiên chỉ có quá nhiều giá trị [a] số cụ thể mà bạn nhận được trong một hàng". Theo nguồn Java cho Random, "Hợp đồng chung tiếp theo là nó trả về giá trị int và nếu bit đối số nằm trong khoảng từ 1 đến 32 (bao gồm), thì nhiều bit có thứ tự thấp của giá trị trả về sẽ là .. các giá trị bit được chọn độc lập, mỗi giá trị là ... đều có khả năng là 0 hoặc 1. " Điều này dường như hàm ý với tôi rằng không có giới hạn về số lượng các giá trị giống hệt nhau mà bạn nhận được trong một hàng, nó chỉ càng khó xảy ra, như bạn mong đợi. –

Các vấn đề liên quan