Tạo bất kỳ số nguyên ngẫu nhiên


17

Chương trình / chức năng của bạn nên

  • xuất chính xác một số nguyên
  • xuất bất kỳ số nguyên nào có xác suất dương
  • xuất ra một số nguyên lớn hơn 1.000.000 hoặc nhỏ hơn -1.000.000 với ít nhất với xác suất 50%.

Ví dụ đầu ra (tất cả phải có thể):

59875669123
12
-42
-4640055890
0
2014
12
24
-7190464664658648640055894646646586486400558904644646646586486400558904646649001

Làm rõ:

  • Một dấu ngắt dòng được cho phép.
  • Số không hàng đầu không được phép.
  • -0 được cho phép.

Mã ngắn nhất sẽ thắng.


2
@Optimizer tại sao bạn giả sử xác suất đồng phục? Câu hỏi không nêu rõ. Trên thực tế, có vẻ như rõ ràng từ thời điểm đó rằng phân phối không nhất thiết phải miễn là ít nhất 50% trong số đó nằm ngoài [-1 triệu, 1 triệu].
hobbs

10
Một giải pháp tạo ra " phân phối đồng đều trên tất cả các số nguyên" là không thể. Có vô số số nguyên, vì vậy mỗi số nguyên riêng lẻ sẽ xuất hiện với xác suất bằng 0. (Hoặc: Xuất ra một số hữu hạn có nghĩa là bạn đang bỏ qua vô số số khác!) Mọi giải pháp sẽ phải làm biến dạng các giá trị cao hơn để đạt được P (tổng ) = 1.
joeytwiddle

2
@Ypnypn RAM của máy tính cũng không phải là giới hạn. Bạn không phải lưu trữ một phần đầu ra của bạn ở bất cứ đâu.
jimmy23013

4
@GiantTree - way too long to fit in an integer- Điều này chỉ đúng nếu bạn cho rằng điều đó integercó nghĩa là intkiểu dữ liệu trên vòm 32/64 bit, đây không nhất thiết là một giả định hợp lệ. "Integer" bắt đầu như một thuật ngữ toán học , không có ràng buộc kích thước.
Tên giả

5
Bất cứ ai sử dụng trình tạo số ngẫu nhiên giả để đưa ra quyết định về đầu ra sẽ loại trừ gần như tất cả các số nguyên và đặt giới hạn trên cho kích thước của các số nguyên có thể được tạo ra (giả sử rằng PRNG có khoảng thời gian hữu hạn). Điều này có thể được bỏ qua trong câu trả lời hoặc một câu trả lời hợp lệ yêu cầu một trình tạo số ngẫu nhiên thực sự?
trichoplax

Câu trả lời:


12

CJam, 16 14 13 byte

0{Kmr(+esmr}g

Điều này sẽ chạy trong một thời gian rất dài, bởi vì nó sử dụng dấu thời gian hiện tại (theo thứ tự 10 12 ) để xác định xem vòng lặp có nên chấm dứt hay không. Tôi đang sử dụng điều này như là bài nộp, vì nó ngắn nhất, nhưng có hai lựa chọn thay thế 14 byte, có giá trị riêng:

0{esmr(+esmr}g

Điều này không bị giới hạn bởi thời gian của PRNG, vì phạm vi của tất cả các số ngẫu nhiên phụ thuộc vào dấu thời gian hiện tại. Do đó, điều này sẽ có thể tạo ra bất kỳ số nào, mặc dù xác suất cho số âm, hoặc thậm chí số dương nhỏ biến mất nhỏ.

Dưới đây là một phiên bản tương đương sử dụng 3e5thay vì dấu thời gian. Và 20cho phạm vi đầu tiên (dưới dạng đệ trình 13 byte). Nó nhanh hơn nhiều và cũng tuân thủ tất cả các quy tắc. Đây là trường hợp giới hạn để có xác suất 50% cho các số vượt quá 1.000.000 trong khi vẫn giữ thời gian chạy hợp lý và kích thước mã nhỏ. Giải thích và biện minh toán học đề cập đến phiên bản này:

0{Kmr(+3e5mr}g

Điều này thường mất một vài giây để chạy. Bạn có thể thay thế 5bằng một 2để làm cho nó chạy nhanh hơn. Nhưng sau đó, yêu cầu về xác suất 50% sẽ chỉ được đáp ứng cho 1.000 thay vì 1.000.000.

Tôi đang bắt đầu từ 0. Sau đó, tôi đã có một vòng lặp, mà tôi đã thoát ra với xác suất 1 / (3 * 10 5 ). Trong vòng lặp đó, tôi thêm một số nguyên ngẫu nhiên từ -1 đến 18 (đã bao gồm) vào tổng số đang chạy của tôi. Có một xác suất hữu hạn (mặc dù nhỏ) rằng mỗi số nguyên sẽ là đầu ra, với số nguyên dương có nhiều khả năng hơn số nguyên âm (tôi không nghĩ bạn sẽ thấy số nguyên âm trong đời mình). Thoát ra với xác suất nhỏ như vậy và tăng phần lớn thời gian (và thêm nhiều hơn trừ) đảm bảo rằng chúng ta thường sẽ vượt quá 1.000.000.

0              "Push a 0.";
 {          }g "Do while...";
  Kmr          "Get a random integer in 0..19.";
     (         "Decrement to give -1..18.";
      +        "Add.";
       3e5mr   "Get a random integer in 0..299,999. Aborts if this is 0.";

Một số biện minh toán học:

  • Trong mỗi bước, chúng tôi thêm trung bình 8,5.
  • Để đạt được 1.000.000, chúng tôi cần 117.647 bước này.
  • Xác suất mà chúng tôi sẽ thực hiện ít hơn số bước này là

    sum(n=0..117,646) (299,999/300,000)^n * 1/300,000
    

    mà đánh giá 0.324402. Do đó, trong khoảng hai phần ba trường hợp, chúng tôi sẽ thực hiện thêm 117.647 bước và dễ dàng mỗi 1.000.000.

  • (Lưu ý rằng đây không phải là xác suất chính xác, bởi vì sẽ có một số biến động về mức trung bình 8,5, nhưng để đạt được 50%, chúng ta cần vượt xa 117.646 đến khoảng 210.000 bước.)
  • Nếu nghi ngờ, chúng ta có thể dễ dàng thổi tung mẫu số của xác suất chấm dứt, lên đến 9e9mà không cần thêm bất kỳ byte nào (nhưng nhiều năm thời gian chạy).

... hay 11 byte?

Cuối cùng, có một phiên bản 11 byte, cũng không bị giới hạn bởi thời gian của PRNG, nhưng nó sẽ hết bộ nhớ mỗi lần. Nó chỉ tạo một số ngẫu nhiên (dựa trên dấu thời gian) mỗi lần lặp và sử dụng cả hai để tăng và kết thúc. Kết quả từ mỗi lần lặp vẫn còn trên ngăn xếp và chỉ được tóm tắt ở cuối. Cảm ơn Dennis vì ý tưởng này:

{esmr(}h]:+

Tôi đã thêm một nhận xét cho câu hỏi để xem liệu các quy tắc có yêu cầu trình tạo số ngẫu nhiên thực sự hay không, nhưng tôi đoán bạn sẽ đánh giá cao ngành sư phạm. Là nguồn ngẫu nhiên của bạn ở đây giả ngẫu nhiên? Điều đó sẽ hạn chế kích thước của tập hợp các đầu ra có thể trong hầu hết thời gian PRNG của bạn, phải không?
trichoplax

(+1 bất kể sự thanh lịch đơn giản)
trichoplax

Có tôi đoán tất cả cho đến nay. Tôi tò mò muốn xem liệu ai đó đăng câu trả lời mà không có vấn đề đó ...
trichoplax

Tôi thấy OP đã tuyên bố rằng bạn có thể giả sử trình tạo số ngẫu nhiên của mình là trình tạo số ngẫu nhiên thực sự dù có hay không - vì vậy điều này hiện đang dư thừa ... :)
trichoplax

Tổng của Kmrtrong một khoảng thời gian vẫn có khả năng luôn là một số dương lớn lớn hơn thời kỳ đó. Và nó không thể tạo ra mọi con số có thể trong trường hợp đó.
jimmy23013

11

Java, 133 149

void f(){String s=x(2)<1?"-":"";for(s+=x(9)+1;x(50)>0;s+=x(10));System.out.print(x(9)<1?0:s);}int x(int i){return new java.util.Random().nextInt(i);}

Ví dụ đầu ra

-8288612864831065123773
0
660850844164689214
-92190983694570102879284616600593698307556468079819964903404819
3264

Bị đánh cắp

void f() {
    String s = x(2)<1 ? "-" : "";       // start with optional negative sign
    s+=x(9)+1;                          // add a random non-zero digit
    for(; x(50)>0; )                    // with a 98% probability...
        s+=x(10)                        // append a random digit
    System.out.print(x(9)<1 ? 0 : s);   // 10% chance of printing 0 instead
}

int x(int i) {
    return new java.util.Random().nextInt(i);
}

Câu trả lời cũ (trước khi thay đổi quy tắc)

void f(){if(Math.random()<.5)System.out.print('-');do System.out.print(new java.util.Random().nextInt(10));while(Math.random()>.02);}

Cả hai bạn đều đúng nhưng câu hỏi cho biết xác suất phải có ít nhất 50% không nằm trong phạm vi +/- 1.000.000
GiantTree

@Optimizer Làm lại.
Ypnypn

Nếu bạn sử dụng chữ nhị phân, bạn không phải in -.
TheNumberOne

4

Toán học - 47

Round@RandomVariate@NormalDistribution[0,15*^5]

Về cơ bản chỉ cần tạo số ngẫu nhiên bằng cách sử dụng phân phối bình thường với phương sai bằng 1500000. Điều này sẽ tạo ra một số nguyên trong khoảng từ -10 ^ 6 đến 10 ^ 6 với xác suất 49,5015%.


"Điều này sẽ tạo ra một số nguyên trong khoảng từ -10 ^ 6 đến 10 ^ 6 với xác suất 50,4985%." - điều đó không đủ. Bạn đã đọc sai thông số kỹ thuật? Có lẽ bạn muốn sử dụng 10 ^ 7 làm phương sai?
John Dvorak

@JanDvorak Xác suất sai, xin lỗi. Bây giờ là đúng.
swish

Liệu việc thực hiện điều này trong Mathematica có thực sự bao gồm tất cả các số nguyên? Tôi không có quyền truy cập vào nguồn nhưng tôi đoán là không ...
trichoplax

@githubphagocyte Nó sẽ phụ thuộc vào độ chính xác hiện tại.
swish

4
Ý tôi là, chỉ định bất kỳ độ chính xác cụ thể nào sẽ loại trừ những con số lớn hơn thế. Cách duy nhất nó có thể hoạt động là nếu bạn có thể chỉ định độ chính xác không giới hạn.
trichoplax

4

Con trăn 2 75 69 byte

from random import*;s=0;j=randrange
while j(12):s=s*9+j(-8,9)
print s

Việc kiểm tra xem vòng lặp while ở giữa có thể tạo ra tất cả các số nguyên (mặc dù thiên về 0) không quan trọng. "12" được chọn sao cho có khoảng một nửa số vượt quá ± 10 6 .


Giải pháp cũ hơn:

Python 2, 44 byte

Dựa trên giải pháp Mathicala .

from random import*;print int(gauss(0,8**7))

Không thực sự hoạt động vì Python floatchỉ có độ chính xác hữu hạn.


Điều này sẽ không thể tạo ra tất cả các số nguyên, bởi vì trình tạo số giả ngẫu nhiên có số lượng trạng thái nội bộ hữu hạn. Theo tài liệu Python sử dụng Mersenne Twister, do đó trạng thái khá lớn. Nhưng nó không phải là vô hạn, vì vậy nó chỉ có thể tạo ra một tập hợp con hữu hạn của tất cả các số nguyên.
starblue

@starblue: Từ OP: "Bạn có thể giả sử rằng trình tạo số ngẫu nhiên của ngôn ngữ của bạn là trình tạo số ngẫu nhiên thực sự ngay cả khi không phải như vậy."
kennytm

3

Ruby, 70

f=->{m=10**6
r=rand -m..m
r<1?(r>-5e5??-:'')+r.to_s+f[][/\d+/]:r.to_s}

Để tạo ra số lượng rất lớn có thể, tôi sẽ trả lại số dưới dạng Stringtừ lambda. Nếu điều đó không được phép, hãy đếm thêm 8 ký tự (choputs f[] ) để biến nó thành một chương trình thay vì một chức năng.

Giải trình

Tạo một số giữa -1,000,0001,000,000. Nếu số là 1hoặc cao hơn, số được trả về là a String.

Nếu số thấp hơn 1, hàm được gọi đệ quy để trả về số ngoài phạm vi số. Để đảm bảo số âm cũng có thể được tạo, a -được đặt trước tiền tố Stringnếu số ban đầu lớn hơn -500,000.

Tôi hy vọng tôi hiểu đúng thách thức!


3

R, 38

library(Rmpfr)
round(rnorm(1,2e6,1e6))

Rút ra từ phân phối Gaussian với trung bình 2.000.000, được chọn ngẫu nhiên và độ lệch chuẩn 1.000.000, do đó, khoảng 2/3 số lần rút sẽ nằm trong phạm vi 1.000.000 và 3.000.000. Phân phối không bị ràng buộc vì vậy về lý thuyết điều này có thể tạo ra bất kỳ số nguyên nào. Gói Rmpfr thay thế các phao đôi được xây dựng của R với độ chính xác tùy ý.


Vâng tôi nhận ra tôi đã đọc sai thông số kỹ thuật. Và tôi tưởng tượng nó có những hạn chế tương tự về độ chính xác của máy với
Mathicala

Hmm trong trường hợp đó tôi không chắc chắn. Tôi sẽ phải xem xét nó; hãy xem xét câu trả lời này "tạm dừng" ngay bây giờ
Shadowtalker

@ MartinBüttner đã sửa tôi nghĩ
Shadowtalker

Hấp dẫn. Tôi không nghĩ rằng bạn cần toàn bộ sample(c(1,-1),1)suy nghĩ mặc dù. Chỉ cần tập trung tại 1e6 là đủ ..
Martin Ender

@ MartinBüttner oh không cần 50% ở cả hai đầu? Điều đó không rõ ràng
Shadowtalker

2

Perl, 53 ký tự

print"-"if rand>.5;do{print int rand 10}while rand>.1

Tôi chắc chắn không thấy bất kỳ lý do nào để làm việc với số nguyên khi in một :)

Có xác suất bằng nhau khi in một số có hoặc không có dấu "-" hàng đầu.

In số 1 chữ số 10% thời gian, số có 2 chữ số 9% thời gian, số có 3 chữ số 8,1% thời gian, số có 4 chữ số 7,29% thời gian, số có 5 chữ số 6,56% thời gian, số có 6 chữ số 5,9% thời gian, v.v ... Bất kỳ độ dài nào cũng có thể, với xác suất giảm. Các số từ một đến năm chữ số chiếm khoảng 41,5% trường hợp đầu ra và số 1.000.000 (hoặc -1.000.000) chỉ 6 phần triệu của một phần trăm, do đó, số đầu ra sẽ nằm ngoài phạm vi -1.000.000 đến 1.000.000 khoảng 54.6 % thời gian

Cả "0" và "-0" đều là đầu ra có thể, mà tôi hy vọng không phải là vấn đề.


Điều này không in "số" như -00000000167? Đó không thực sự là một số nguyên.
isaacg

1
@isaacg Tôi không thấy lý do tại sao đó không phải là số nguyên.
Tối ưu hóa

2
@Optimizer Đó là, nhưng OP rõ ràng đã cấm dẫn 0.
Martin Ender

Bạn có thể tạo một chữ số hàng đầu ngẫu nhiên khác không trước vòng lặp, từ -9 đến +9. print int(rand(20)-10)||1. Tôi cần một cách để tạo 0 như một đầu ra, mặc dù. Có thể | | chết 0, nếu rác thải sau 0 được cho phép. Khác cần một cách ngắn để in số không và thoát mà không cần đầu ra thêm nếu int(rand(20)-10)==0.
Peter Cordes

@PeterCordes đồng ý, đó là một cách tiếp cận hợp lý nhưng tôi không cảm thấy muốn viết nó và tôi không nghĩ rằng nó sẽ có tính cạnh tranh lâu dài. Cảm thấy tự do để gửi nó vào riêng :) bạn
Hobbs

2

Perl, 114 Chars

use Math::BigInt;sub r{$x=Math::BigInt->new(0);while(rand(99)!=0){$x->badd(rand(2**99)-2**98);}print($x->bstr());}

Phá vỡ:

use Math::BigInt;               -- include BigIntegers
  sub r{                        -- Define subroutine "r"
    $x=Math::BigInt->new(0);    -- Create BigInteger $x with initial value "0"
      while(rand(99)!=0){       -- Loop around until rand(99) equals "0" (may be a long time)
        $x->badd(               -- Add a value to that BigInt
          rand(2**99)-2**98);   -- Generate a random number between -2^98 and +2^98-1
        }print($x->bstr());}    -- print the value of the BigInt

Xác suất nhận được giá trị từ -1.000.000 đến 1.000.000 đang có xu hướng về 0 NHƯNG điều đó là có thể.

Lưu ý: Chương trình con này có thể chạy trong một thời gian dài và lỗi với "Hết bộ nhớ!" lỗi nhưng về mặt kỹ thuật tạo ra bất kỳ số nguyên nào như được nêu trong câu hỏi.

Perl, 25

sub r{rand(2**99)-2**98;}

Tạo một số nguyên ngẫu nhiên trong phạm vi +/- 2 ^ 99.

Phá vỡ

sub r{                    -- Define subroutine "r"
     rand(2**99)          -- Generate a random integer between 0 and 2^99
                -2**98;}  -- Subtract 2^98 to get negative values as well

Đã thử nghiệm với 1 triệu mẫu:

~5 are inside the range of +/-1.000.000
~999.995 are outside that range
= a probability of ~99,99% of generating an integer outside that range.
Compare that number to the probability of 2.000.000 in 2^99: It is approx. the same.

Điều này đáp ứng tất cả các quy tắc:

  • 1 số nguyên
  • bất kỳ số nguyên nào cũng có thể
  • ít nhất 50% (trong trường hợp của tôi 99,99%) của tất cả các số nguyên được tạo nằm ngoài phạm vi +/- 1.000.000.

Điều này hoạt động bởi vì trình tạo số ngẫu nhiên cơ bản xác định xác suất bằng nhau cho mỗi bit được tạo, do đó cũng thực hiện điều đó trên các số nguyên được tạo.
Mỗi số nguyên có xác suất 1/2 ^ 99 được tạo.

Biên tập:

Tôi đã phải tăng số mũ để số nguyên lớn hơn được tạo ra. Tôi đã chọn 99 vì nó giữ mã càng ngắn càng tốt.


Chúng tôi không đồng ý rằng không nên có bất kỳ giới hạn trên / dưới? Chẳng hạn, số nguyên 2 ^ 31 + 1 có 0 xác suất, phá vỡ quy tắc 2
Trình tối ưu hóa

@Optimizer đối với tôi một số nguyên được định nghĩa như trong nhiều ngôn ngữ lập trình: một số trong giới hạn của -2^31+2^31-1( 32 bit ). Bạn có thể dễ dàng tăng số mũ nếu bạn muốn tạo số nguyên lớn hơn nhưng có thể thất bại tùy thuộc vào việc triển khai Perl.
GiantTree

Tôi chỉ thấy rằng số nguyên lớn đến mức nực cười cũng phải được tạo ra. Tôi sẽ chỉnh sửa mã của tôi một cách nhanh chóng.
GiantTree

@ MartinBüttner Tôi đã cố gắng hết sức để đáp ứng thông số kỹ thuật của câu hỏi. Tôi chỉ không thể (ít nhất là không có sự giúp đỡ) để tạo ra các số nguyên lớn vô hạn. Số nguyên lớn nhất của Perl là khoảng 1.7e308 là giới hạn tôi không thể kiểm soát.
GiantTree

@ MartinBüttner Cả hai đều có thể nhưng vd. chuỗi sẽ tràn sau 2gb dữ liệu làm cho nó hữu hạn trở lại. Thật khó để nói rằng một con số sẽ vô cùng lớn nếu có vấn đề với bộ nhớ. Tôi sẽ sớm đưa ra một cách tiếp cận khác bằng cách sử dụng BigInts. Ngoài ra, số nguyên không tràn vào 1.7e308, nó chỉ được chuyển đổi thành infite ( 1.#INFchính xác)
GiantTree

2

C #, 126 107 byte

string F(){var a=new System.Random();var b=a.Next(-1E6,1E6+1)+"";while(a.Next(1)>0)b+=a.Next(10);return b;}

Ung dung:

string F()
{
    System.Random rand = new System.Random();
    string rtn = rand.Next(-1E6, 1E6 + 1) + "";
    while (rand.Next(1) > 0)
         rtn += a.Next(10);
    return rtn;
}

Cơ hội để tạo ra một số n chữ số là 1/2 ^ (n-10), lớn hơn 0 cho tất cả n dương và 1/2 cho n = 11.Cũng tạo ra các số 0 đứng đầu, dường như không được phép trong câu hỏi ban đầu hoặc bất kỳ nhận xét nào của nó.


Khi sử dụng using System;, bạn không cần System.Randomhai lần, nhưng chỉ Random, phải không?
Charlie

@Charlie Đây là một chức năng, vì vậy tôi không thể sử dụng các usingcâu lệnh. Nó sẽ chỉ tiết kiệm 1 char dù sao đi nữa.
LegionMammal978

1
Bạn có thể lưu 1 char bằng cách xóa khoảng trống tại -1E6, 1E6+1.
Chương trìnhFOX

2

Perl, 62 byte

print $n=int rand(20)-10;while($n&&rand>.1){print int rand 10}

Tôi đã có cùng ý tưởng với @Hobbs, về việc tạo ra một chữ số tại một thời điểm, nhưng mã của anh ta không đáp ứng được yêu cầu không có số 0 đứng đầu. Tạo chữ số đầu tiên thay vì chỉ dấu đã giải quyết điều đó. Và trừ khi có một cách ngắn hơn để thoát nếu chúng tôi in số 0 hoặc cách ngắn hơn để tạo từ -9 đến 9, thì điều này sẽ làm điều đó cho kích thước.

Trong một vòng lặp shell: while perl -e '...'; do echo;done |less

Tôi nghĩ rằng đây là một trong những cách ngắn nhất không yêu cầu RAM vô hạn để đáp ứng vấn đề. Như một phần thưởng, đầu ra không thiên vị mạnh mẽ đối với bất cứ điều gì và thời gian chạy rất nhanh.

Tôi đã thử sử dụng bitwise và để lưu một ký tự trong điều kiện while, nhưng tôi nghĩ rằng điều này kết thúc là đúng thường xuyên hơn, vì vậy vòng lặp kết thúc sớm hơn. Sẽ cần nhiều ký tự hơn để điều chỉnh những thứ khác để chống lại điều đó, để duy trì xác suất tạo abs (đầu ra)> 1M.


Thật tuyệt, bạn đã vắt kiệt một số điều mà tôi sẽ không nghĩ tới :)
hobbs 28/12/14

1

Javascript (73)

Giải pháp này sử dụng rằng bạn có thể xây dựng một số với cơ sở n bằng cách nhân số trước đó với n và thêm một chữ số trong cơ sở n . Chúng tôi có một bổ sung ..?..:..trong đó để có thể tạo tất cả các số nguyên âm. Các mã sau đây nên được kiểm tra trong bảng điều khiển trình duyệt.

b=Math.round;c=Math.random;x=0;while(b(c()*99)){x*=b(c())?2:-2;x+=b(c())}

Xác suất để có được một số nguyên> = 2^1(hoặc <= -(2^1)) bằng với khả năng vòng lặp được chạy 2 lần. Cơ hội của điều đó xảy ra là (98/99)^2. Do đó, cơ hội nhận được một số lớn hơn 2^20(hoặc <= -(2^20)) là (98/99)^21 = 0.808hoặc 81%. Đây chỉ là lý thuyết và cho rằng Math.random thực sự ngẫu nhiên. Nó rõ ràng là không.


Đoạn mã kiểm tra mã này. Cũng trong một thời trang dễ đọc hơn.


1
OP hiện đã xác nhận rằng bạn có thể cho rằng PRNG của bạn thực sự ngẫu nhiên, ngay cả khi không.
trichoplax

1

GolfScript, 20 byte

0{)8.?rand}do.2&(*4/

Vâng, cái này cũng chậm.

So với các ngôn ngữ như CJam và Pyth, GolfScript phải chịu một từ khóa tạo số ngẫu nhiên dài dòng ( rand). Để vượt qua khuyết tật này, tôi cần tìm cách sử dụng nó chỉ một lần.

Mã này hoạt động bằng cách liên tục chọn một số ngẫu nhiên trong khoảng từ 0 đến 8 8 1 = 16.777.215, và tăng một bộ đếm cho đến khi số ngẫu nhiên xảy ra là 0. Giá trị bộ đếm kết quả có phân phối hình học với trung bình khoảng -1 / log 2 (1 - 1/8 8 ) 11.629.080, do đó, nó đáp ứng bài kiểm tra "hơn 1.000.000 ít nhất 50% thời gian".

Than ôi, số ngẫu nhiên do đó tạo ra luôn luôn tích cực. Vì vậy, phần bổ sung .2&(*4/là cần thiết để cho nó trở thành âm hoặc bằng không. Nó hoạt động bằng cách trích xuất bit thấp thứ hai của số (do đó là 0 hoặc 2), giảm dần để làm cho nó -1 hoặc 1, nhân nó với số ban đầu và chia kết quả cho 4 (để loại bỏ hai bit thấp nhất, hiện tương quan với dấu và cũng cho phép kết quả trở thành 0). Ngay cả sau khi chia cho 4, giá trị tuyệt đối của số ngẫu nhiên vẫn có trung vị là -1 / log 2 (1 - 1/8 8 ) / 4 2.907.270, vì vậy nó vẫn vượt qua bài kiểm tra 50%.


1

JavaScript, 81 byte

Mã này đáp ứng tất cả các quy tắc:

  • Xuất bất kỳ số nguyên nào có xác suất dương
  • Số nguyên đầu ra ngoài phạm vi +/- 1000000 với xác suất ít nhất 50%
  • Không dẫn đầu 0về sản lượng

Như một phần thưởng, thuật toán chạy với độ phức tạp thời gian là O (log 10 n) nên nó trả về số nguyên gần như ngay lập tức.

for(s="",r=Math.random;r()>.1;s+=10*r()|0);r(s=s.replace(/^0*/,"")||0)<.5?"-"+s:s

Điều này giả định một môi trường REPL. Hãy thử chạy đoạn mã trên trong bảng điều khiển của trình duyệt hoặc sử dụng đoạn mã ngăn xếp bên dưới:

D.onclick = function() {
  for(s="", r=Math.random;r()>.1; s+=10*r()|0);
  P.innerHTML += (r(s=s.replace(/^0*/,"") || 0) <.5 ?"-" + s : s) + "<br>"
}
<button id=D>Generate a random number</button><pre id=P></pre>

Thuật toán :

  • Tiếp tục nối các chữ số ngẫu nhiên vào chuỗi scho đến khi a Math.random() > 0.1.
  • Dựa trên Math.random() > 0.5, làm cho số âm (bằng cách thêm chuỗi svào -).

Thuật toán này không có phân phối đồng đều trên tất cả các số nguyên. Các số nguyên có số chữ số cao hơn ít có xác suất hơn các số nguyên thấp hơn. Trong mỗi lần lặp cho vòng lặp, có 10% cơ hội tôi sẽ dừng lại ở chữ số hiện tại. Tôi chỉ cần đảm bảo rằng tôi dừng lại sau 6 chữ số hơn 50% thời gian.

Phương trình này của @nutki giải thích giá trị tối đa của tỷ lệ phần trăm dừng dựa trên điều kiện trên:

1 - 50%^(1/6) ≈ 0.11

Do đó, 0,1 cũng nằm trong phạm vi để đáp ứng cả ba quy tắc của câu hỏi.


Có một vài điều làm tôi bối rối về câu trả lời này. Bạn có cho rằng Math.random () tạo ra một phân phối thống nhất các số ngẫu nhiên, bởi vì thông số kỹ thuật nói rằng nó phụ thuộc vào việc triển khai. Giả sử rằng đó là phân phối đồng đều, P (Math.random ()> 0,1) = 0,9 nên có khả năng rất lớn là nó sẽ chấm dứt giữa mỗi lần lặp. Việc triển khai thuật toán của bạn chạy trên Firefox 34.0 Ubuntu cho tôi xác suất ~ 0,47 (<0,5) mỗi lần tôi kiểm tra nó: jsfiddle.net/WK_of_Angmar/dh8gq4pb
Wk_of_Angmar

Ngoài ra, làm thế nào bạn quản lý để tính độ phức tạp thời gian cho một thuật toán mà không có đầu vào?
Wk_of_Angmar

1

TI-BASIC, 14 byte

1-2int(2rand:randNorm(AnsE6,9

Tương tự như câu trả lời R của @ ssdecontrol, điều này rút ra từ phân phối Gaussian với trung bình -1.000.000 hoặc 1.000.000, được chọn ngẫu nhiên và độ lệch chuẩn 9. Phân phối không bị ràng buộc để theo lý thuyết, điều này có thể tạo ra bất kỳ số nguyên nào.

Giải thích :

1-2int(2rand     - get a random integer 0 or 1, then multiply by 2 and subtract 1
:                - this gives the number 1 or -1 (with equal probability) to Ans
randNorm(AnsE6,9 - displays Gaussian distribution with mean (Ans * 1,000,000) and std. dev. 9

Nhưng nó có thể tạo ra "2" hoặc "-2" không?
kennytm


1
OK đọc mã sai (suy nghĩ :có nghĩa là "in" do cách giải thích được trình bày). Nhưng nó có thể tạo ra số hơn 20 chữ số không?
kennytm

Bất kỳ số nguyên dài tùy ý có thể là một đầu ra? Điều này không bị giới hạn bởi phạm vi randNorm?
Tối ưu hóa

"Phân phối không bị ràng buộc nên về lý thuyết, điều này có thể tạo ra bất kỳ số nguyên nào." Không có phạm vi.
Timtech

1

Bash, 66

LANG=C sed -r '/^-?(0|[1-9][0-9]*)$/q;s/.*/5000000/;q'</dev/random

Nó hầu như luôn in 5000000. Nhưng nếu tìm thấy một số hợp lệ /dev/random, nó sẽ in số đó thay thế.

Và cái này nhanh hơn:

LANG=C sed -r '/^-?(0|[1-9][0-9]*)$/q;s/.*/5000000/;q'</dev/urandom

1
@Optimizer Nó được cho là chậm. Đó là bởi vì nó là một nguồn ngẫu nhiên thực sự. Nhưng bạn có thể kiểm tra nó với /dev/urandomít ngẫu nhiên hơn.
jimmy23013

@Optimizer Làm thế nào mà lấy đầu vào thủ công? Nó đang đọc một tập tin, nhưng tất cả mọi thứ là một tập tin.
Nit

@Optimizer Tôi chỉ đơn giản là không hiểu điểm bạn sẽ làm.
Nit

đọc từ /dev/urandomtrong một kịch bản shell về cơ bản giống như gọi rand()bằng các ngôn ngữ khác. Mặc dù nếu bạn thực sự sử dụng bash, không phải POSIX sh, bạn có thể nhận được các số ngẫu nhiên từ đó echo $RANDOM. wiki.ubfox.com/DashAsBinSh cung cấp hexdump /dev/urandomtương đương với mức tối thiểu POSIX /bin/dash.
Peter Cordes

1

C ++, 95 byte

void f(){int d=-18,s=-1;while(s<9){d=(rand()%19+d+9)%10;cout<<d;s=9-rand()%10*min(d*d+s+1,1);}}

Mở rộng:

void f() {
    int d=-18,s=-1;
    while(s<9) {
        d=(rand()%19+d+9)%10;
        cout<<d;
        s=9-rand()%10*min(d*d+s+1,1);
    }
}

Giải trình:

Hàm tiếp tục in các chữ số ngẫu nhiên liên tiếp cho đến khi một công tắc có giá trị ngẫu nhiên lấy giá trị bắt buộc để dừng chức năng. d là biến giữ giá trị của chữ số tiếp theo được in. s là biến chuyển đổi lấy các giá trị nguyên ngẫu nhiên trong khoảng [0, 9], nếu s == 9 thì không có thêm chữ số nào được in và chức năng kết thúc.

Các biến d và s được khởi tạo để xử lý đặc biệt cho chữ số đầu tiên (lấy nó từ khoảng [-9, 9] và nếu chữ số đầu tiên bằng 0 thì hàm phải kết thúc để tránh các số 0 đứng đầu). Giá trị của d có thể được chỉ định là d = rand ()% 10 nhưng sau đó chữ số đầu tiên không thể âm. d được chỉ định thay vì d = (rand ()% 19 + d + 9)% 10 và được khởi tạo ở -18 nên giá trị đầu tiên của d sẽ nằm trong khoảng từ [-9, 9] và các giá trị tiếp theo sẽ luôn nằm trong khoảng từ [0 , 9].

Biến s nằm trong phạm vi ngẫu nhiên từ [0, 9] và nếu s bằng 9, hàm kết thúc, do đó, sau khi in chữ số đầu tiên, chữ số tiếp theo sẽ được in với xác suất 90% (giả sử rand () là thực sự ngẫu nhiên và để đáp ứng điều kiện thứ ba). s có thể dễ dàng được gán là s = ​​rand ()% 10, tuy nhiên, có một ngoại lệ, nếu chữ số đầu tiên bằng 0, hàm phải kết thúc. Để xử lý ngoại lệ đó, s đã được chỉ định là s = ​​9-rand ()% 10 * min (d * d + s + 1,1) và được khởi tạo là -1. Nếu chữ số đầu tiên bằng 0, min sẽ trả về 0 và s sẽ bằng 9-0 = 9. Việc gán biến của s sẽ luôn nằm trong khoảng từ [0, 9], vì vậy ngoại lệ chỉ có thể xảy ra ở chữ số đầu tiên.

Đặc điểm (giả sử rand () là thực sự ngẫu nhiên)

  • Số nguyên được in chữ số theo chữ số, với xác suất cố định là 90% in một chữ số khác sau khi in chữ số cuối cùng.

  • 0 là số nguyên có cơ hội được in cao nhất, với xác suất khoảng 5,2%.

  • Xác suất in một số nguyên trong khoảng [-10 ^ 6, 10 ^ 6] là khoảng 44% (phép tính không được viết ở đây).

  • Số nguyên dương và âm được in với cùng một xác suất (~ 47,4%).

  • Không phải tất cả các chữ số được in với cùng một xác suất. Ví dụ: ở giữa in số nguyên, nếu chữ số cuối cùng là 5, chữ số 3 sẽ có cơ hội được in tiếp theo thấp hơn một chút. Nói chung, nếu chữ số cuối cùng là d, chữ số (d + 18)% 10 sẽ có cơ hội được in tiếp theo thấp hơn một chút.

Kết quả đầu ra (10 lần thực hiện)

-548856139437
7358950092214
507
912709491283845942316784
-68
-6
-87614261
0
-5139524
7

Process returned 0 (0x0)   execution time : 0.928 s
Press any key to continue.

1

Bash, 42 byte

printf "%d\n" 0x$(xxd -p -l5 /dev/random)
/ dev / Random trên OSX chỉ là các byte ngẫu nhiên và xxd -p -l5chuyển đổi 5 ký tự ascii thành hex và printfbiến nó thành định dạng thập phân.


0

Bình thường , 11 byte

WOyG~ZtOT)Z

Lưu ý: chương trình này có thể sẽ gặp sự cố với lỗi bộ nhớ trên bất kỳ máy tính thực nào. Để kiểm tra nó, hãy thử thay thế Gbằng một chuỗi ngắn hơn, chẳng hạn như trong mã này, tạo ra các số trung bình khoảng 28000:

pyth -c 'WOy"abcdefghijklm"~ZtOUT)Z'

Mã này lặp, thêm một số ngẫu nhiên từ -1 đến 8 đến Z, với xác suất 2 ^ -26 thoát khỏi vòng lặp trên mỗi lần lặp lại. Xác suất 2 ^ -26 đạt được bằng cách chọn một phần tử ngẫu nhiên ( O) của tập hợp tất cả các tập hợp con ( y) của bảng chữ cái (G ).

Chi tiết kỹ thuật & biện minh:

Xác suất 2 ^ -26 có nguồn gốc từ hai sự kiện:, ykhi được gọi trên các chuỗi, là hàm thiết lập sức mạnh, một cấu trúc danh sách tất cả các tập hợp con của đầu vào. Vì đầu vào, Gdài 26 ký tự, bộ sức mạnh này, yGcó 2 ^ 26 mục. OyGchọn một yếu tố ngẫu nhiên từ 2 ^ 26 mục đó. Chính xác một trong những mục đó, chuỗi trống, sẽ đánh giá là sai khi được chuyển đếnW , vòng lặp while. Do đó, có xác suất 2 ^ -26 thoát khỏi vòng lặp mỗi lần.

Trong bất kỳ số chu kỳ vòng lặp K cố định nào, xác suất nhận được số K * 3.5 + m và nhận K * 3.5 - m là bằng nhau, bởi vì mỗi chuỗi bổ sung đạt được tổng số có thể được đảo ngược, -1 -> 8, 0 -> 7, v.v., để đạt được cái khác. Ngoài ra, các số gần với K * 3.5 rõ ràng có nhiều khả năng hơn các số ở xa hơn. Do đó, nếu K> 2000000 / 3.5 = 571428.5 thì xác suất nhận được số trên 1000000 lớn hơn 75%, bởi vì một số kết quả trên số đó có thể được đưa vào tương ứng một-một với tất cả các kết quả bên dưới số và phần trên dưới một nửa, có thể được đưa vào tương ứng một-một với những người dưới 1000000. Xác suất nhận được ít nhất 571429 vòng là (1-2 ^ -26) ^ 571429, không ít hơn (1-2 ^ -26 * 571429), số lần dự kiến ​​rời khỏi vòng lặp trong 571429 lần thử đầu tiên, là 99,1%. Do đó, trên 99,1% thử nghiệm trở lên, có 75% hoặc nhiều hơn cơ hội nhận được ít nhất 1000000, do đó, có nhiều hơn 50% cơ hội nhận được hơn 1000000.

Mã này dựa trên hành vi Onơi một lỗi vô tình được giới thiệu 3 ngày trước và đã được sửa chữa ngày hôm nay. Nó sẽ hoạt động trên mọi phiên bản của Pyth 3 từ trước ngày 22 tháng 12 hoặc sau ngày hôm nay. Các mã sau đây là tương đương và luôn luôn hoạt động:

WOyG~ZtOUT)Z

Điều gì đã xảy ra với trình biên dịch trực tuyến?
Tối ưu hóa

@Optimizer Các vấn đề với trang web, tôi sẽ làm việc với nó.
isaacg

À .. tuyệt. Muốn làm việc với bản dịch thứ Py của câu trả lời CJam của tôi ngày hôm qua và thấy rằng nó mang lại 404.
Trình tối ưu hóa

0

Java, 113 byte

void g(){String a=Math.random()>0?"10":"01";for(;Math.random()>0;)a+=(int)(Math.random()*2);System.out.print(a);}

Chương trình này in một số nhị phân cho luồng đầu ra tiêu chuẩn. Bạn có thể phải chờ một thời gian vì xác suất số đó kết thúc số (hoặc số dương) là xấp xỉ 0. Ý tưởng rằng giá trị tuyệt đối của một số được tạo ra là dưới 1 triệu là thú vị, nhưng vẫn có thể.

Ung dung:

void g(){
    String a=Math.random()>0?"10":"01";             //Make sure there are no trailing zeroes.
    for(;Math.random()>0;)a+=(int)(Math.random()*2);//Add digits
    System.out.print(a);                            //Print
}

Đầu ra mẫu: Sẽ đăng khi một số được thực hiện.


0

Java (JDK) , 140 127 byte

()->{int i;var o=System.out;for(o.print(i=(int)(19*Math.random())-10);i!=0&Math.random()<.9;)o.print((int)(11*Math.random()));}

-13 bytes bằng cách lẻn logic hơn vào tiêu đề vòng lặp - nhờ @ceilingcat

Hãy thử trực tuyến!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.