2011-02-04 26 views
5

Bu soru: How to generate a random BigInteger BigIntegers için Random.nextInt (int n) ile aynı semantiği elde etmenin bir yolunu açıklar.Java'da rasgele bir BigDecimal nasıl oluşturabilirim?

Aynı şeyi BigDecimal ve Random.nextDouble() için de yapmak isterim.

Yukarıdaki soruya verilen bir yanıt, rastgele bir BigInteger oluşturulmasını ve ardından rasgele bir ölçekle BigDouble oluşturulmasını önerir. Çok hızlı bir deney, bunu çok kötü bir fikir olarak gösterir :)

Bu yöntemin kullanılması, tamsayı için tamsayıların n-log10(R) gibi bir şeyle ölçeklendirilmesini gerektirmesidir. Burada n, gereken sayısal basamak sayısıdır. çıktı ve R rastgele BigInteger'dir. Bu sayede doğru sayıda hanenin bulunmasına izin verilmelidir, böylece (örneğin) 1 -> 10^- 64 ve 10 -> 64 -> 1.

Ölçekleme değerinin, sonuç düşmesi için doğru seçilmesi gerekir. aralığında [0,1].

Daha önce bunu yapan var mı ve sonuçların doğru dağıtılıp dağıtılmadığını biliyor mu? Bunu başarmanın daha iyi bir yolu var mı?

DÜZENLEME: Ölçeğin argümanını anlamamı düzeltmek için @biziclop'a teşekkürler. Yukarıdaki gerekli değildir, sabit bir ölçek faktörü istenen etkiye sahiptir. daha sonra başvurmak, benim (görünüşte çalışan kod) için

geçerli:

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; 
} 

cevap

3

Sadece ne istediğini bilseydim ... kesinlikle çok kolay. [0, 1] aralıklarında eşit dağıtılmış bir sayı ve hassas N ondalık basamakları, 10 * N'den küçük bir üniforma BigInteger üretir ve 10 * N.

+0

Yanlış olan orijinal cevabın "rastgele ölçek" kısmıydı. Bu yöntem iyi olmalı. – DJClayworth

+0

Tek bir BigInteger, 10^N'den daha az satın alarak [0, 10^m] ve bunları birleştiren çok sayıda tamsayı oluşturabilirsiniz. –

+0

Doğru, ama bu sorunun ilk cümlesiyle bağlantılı güzel bir cevabı olan karşılık gelen bir soru var. Teklifiniz de işe yarayabilir, özellikle m = 9 ile random.nextInt() kullanılabilir. – maaartinus

1
Burada bariz eksik olabilir

ama nasıl fraksiyonel diğer tamsayı parçası olmak, bir tane iki rastgele BigInteger s oluşturma ve yaklaşık ? Açıkçası, "kesirli" bigint'in aralığı, izin vermek istediğiniz hassasiyetle belirlenir, bu da sabitleme işleminden uzaklaşamaz. Güncelleştirme: Bu yalnızca bir rastgele bigint ile çalışmak için daha basitleştirilebilir. 0 ile n arasında bir ondalık kesinlik ile (k sabit ise) rastgele bir sayı istiyorsanız, 0 ile n * 10^k arasında rastgele bir sayı üretirsiniz ve 10^k ile bölünür.

+0

Bunu yapmanın sonucu, düzgün bir şekilde dağıtılmaz. Bunu denedim ve sonuç fraksiyonel kısım boyunca eşit olarak dağıtıldı, bu da sonuçlarda 10^-27'nin 0,01 ile 0,1 arasında bir sayı gibi görünmesi anlamına geliyor. 10^-27 26 olmalıdır veya o kadar büyüklük dereceleri 0.1-0.01 –

+0

@Mike Houston aralığındaki bir sayıdan daha az görünme olasılığı o zaman apaçık görünüyorum, çünkü hala anlamadım.Üniform olarak dağıtılmasını mı istiyorsun, istemiyor musun? – biziclop

+0

@Mike Houston Nope, hala anlamıyor. En n basamaklı uzunlukta eşit dağıtılmış bir değişken alırsanız ve 10^n'a bölerseniz, eşit olarak dağılır. – biziclop

2

Rastgele bir BigInteger Andy Turner's answer about generating a random BigInteger oluşturma hakkında bir yazı yaptım. Bunu rastgele bir BigDecimal oluşturmak için doğrudan kullanmıyorum. Esasen kaygım, her rakamı bir sayı olarak üretmek için bağımsız Rastgele örneklerini kullanmaktır. Fark ettiğim bir sorun, Random ile bir satırda aldığınız sadece çok sayıda ve belirli bir sayı var. Ayrıca nesil, üretilen değerlerin eşit bir dağılımını sürdürmeye çalışır. Benim çözümüm, bir dizi veya Rastgele örneklerin bir koleksiyonunu depolamak ve bunları çağırmakla ilgili bir şeye bağlıdır. Bunun iyi bir yol olduğunu düşünüyorum ve bunu bulmaya çalışıyorum, bu yüzden bu yaklaşımın herhangi bir işaretçisi veya eleştirisi varsa ilgileniyorum.

/** 
* 
* @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

"Random ile sadece bir satırda aldığınız belirli bir sayının çok fazla değeri vardır" ile ne demek istediğini anlamıyorum. Rastgele için Java kaynağına göre, "Bir sonraki genel sözleşme, bir int değeri döndürdüğü ve argüman bitlerinin 1 ile 32 (kapsayıcı) arasında olması durumunda, geri dönen değerin çok düşük sıralı bitleri olacaktır. bağımsız olarak seçilmiş bit değerleri, her biri 0 veya 1 olacak şekilde eşittir. " Bu, üst üste kaç tane özdeş değere sahip olmanızın bir sınırı olmadığını, tahmin edeceğiniz gibi gittikçe artan bir ihtimal olmadığını ima ediyor gibi görünüyor. –