Chọn một số ngẫu nhiên trong khoảng từ 0 đến n bằng cách sử dụng nguồn ngẫu nhiên không đổi


26

Bài tập

Cho một số nguyên dương nnhỏ hơn 2^30chỉ định làm đầu vào theo bất kỳ cách nào bạn chọn, mã của bạn sẽ xuất ra một số nguyên ngẫu nhiên giữa 0n, bao gồm. Số lượng bạn tạo nên được chọn thống nhất ngẫu nhiên . Đó là mỗi giá trị từ 0để nphải xảy ra với xác suất như nhau (xem Nội quy và Hãy cẩn thận).

Quy tắc và hãy cẩn thận

Mã của bạn có thể giả định rằng bất kỳ trình tạo số ngẫu nhiên nào được tích hợp vào ngôn ngữ hoặc thư viện tiêu chuẩn của bạn tuyên bố là ngẫu nhiên thống nhất trên thực tế là thống nhất. Đó là bạn không phải lo lắng về chất lượng của nguồn ngẫu nhiên bạn đang sử dụng. Tuy nhiên,

  • Bạn phải thiết lập rằng nếu nguồn ngẫu nhiên bạn đang sử dụng là đồng nhất thì mã của bạn sẽ đưa ra một số nguyên ngẫu nhiên thống nhất từ 0đến n.
  • Bất kỳ đối số khi gọi một hàm ngẫu nhiên tích hợp hoặc thư viện phải là hằng số. Đó là chúng phải hoàn toàn độc lập với giá trị đầu vào.
  • Mã của bạn có thể chấm dứt với xác suất 1 thay vì được đảm bảo chấm dứt.

Ghi chú

  • randInt(0,n) không hợp lệ vì nó lấy đầu vào làm đối số cho hàm dựng sẵn hoặc hàm thư viện.
  • rand()%nsẽ không đưa ra một số ngẫu nhiên thống nhất nói chung. Như một ví dụ được đưa ra bởi betseg, nếu intmax == 15n = 10, sau đó bạn sẽ có nhiều khả năng nhận được 0-5hơn 6-10.
  • floor(randomfloat()*(n+1)) nói chung cũng sẽ không đưa ra một số ngẫu nhiên thống nhất do số hữu hạn của các giá trị dấu phẩy động khác nhau có thể có từ 0 đến 1.

Làm thế nào bạn sẽ xác nhận rằng đầu ra là ngẫu nhiên thống nhất? Có thể một ngôn ngữ / thư viện nhất định sẽ tạo ra các số ngẫu nhiên thống nhất, nhưng thao tác có thể dẫn đến đầu ra không đồng nhất. (ví dụ: rng()cung cấp 0- 100, nếu n = 75và chức năng là rng()%75, thì 0-25 sẽ phổ biến hơn ...)
Baldrickk

1
@Baldrickk Bằng sự khôn ngoan của đám đông :) Chúng tôi chỉ có thể đọc mã và suy nghĩ về nó.

Kết luận buồn khi đặt câu hỏi lý thuyết xác suất đơn giản nhất có thể: tính ngẫu nhiên và xác suất được hiểu rất kém. :( (Và đọc các quy tắc là khó, rõ ràng.)
Martin Ender

Điều này xuất hiện trong tâm trí: Số ngẫu nhiên
BgrWorker

Tại sao bạn chấp nhận câu trả lời x86 khi có ba câu ngắn hơn?
Dennis

Câu trả lời:


25

Máy x86 có rdrandhướng dẫn, 10 byte

BITS 64

_try_again:

 rdrand eax
jnc _try_again

 cmp eax, edi
ja _try_again

 ret

mã máy

0FC7F0 73FB 39F8 77F7 C3

Đầu vào là trong thanh ghi rdivà đầu ra trong rax.
Điều này tôn trọng SYS V AMD64 ABI để mã thực hiện hiệu quả chức năng C

unsigned int foo(unsigned int max); 

với số nguyên 32 bit.

Hướng dẫn rdrandđược mô tả bởi Intel

RDRANDtrả về các số ngẫu nhiên được cung cấp bởi DRBG, bộ tạo bit ngẫu nhiên xác định, an toàn về mặt mật mã. DRBG được thiết kế để đáp ứng tiêu chuẩn NIST SP 800-90A .

Đối phó với CSRNG, dù sao thì việc phân phối là thống nhất, dù sao, trích dẫn NIST SP 800-90A:

Một số ngẫu nhiên là một thể hiện của một biến ngẫu nhiên không thiên vị, nghĩa là đầu ra được tạo ra bởi một quá trình ngẫu nhiên phân phối đồng đều .


Thủ tục tạo ra một số ngẫu nhiên và nếu nó không hoàn toàn lớn hơn đầu vào thì nó được trả về.
Nếu không, quá trình được nhắc lại.

eaxlà 32 bit, rdrandtrả về một số trong khoảng từ 0 đến 2 32 -1, do đó, với mọi n trong [0, 2 32 -1], số lần lặp dự kiến ​​là 2 32 / (n + 1) được xác định cho tất cả n trong [0, 2 30 ).


Rực rỡ cấp thấp. Cảm ơn bạn.

Để làm gì jnc?
l4m2

@ l4m2 rdrandđặt CFiif dữ liệu trả về là hợp lệ. Dữ liệu có thể không hợp lệ vì có quá nhiều yêu cầu làm cạn kiệt entropy pool. Xem mục nhập thủ công cho ndrandnày .
Margaret Bloom

20

Thạch , 7 6 byte

⁴!!X%‘

Cảm ơn @Jonathan ALLan vì đã chơi golf 1 byte!

Không thể chạy trên TIO vì (16!)! là một con số khổng lồ .

Làm thế nào nó hoạt động

⁴!!X%‘  Main link. Argument: n

⁴       Set the return value to 16.
 !!     Compute (16!)!.
   X    Pseudo-randomly choose an integer between 1 and (16!)!.
        Since (16!)! is evenly divisible by any k ≤ 2**30, it is evenly divisible
        by n+1.
    %‘  Take the result modulo n+1.

Đây là một phiên bản cố định của câu trả lời bị xóa của tôi, cùng một ý tưởng. Mặc dù tôi đã có một số mũ không cần thiết.
orlp

Xin lỗi, tôi đã không nhìn vào nó trước khi đăng.
Dennis

Ồ nó không thành vấn đề, dù sao tôi cũng không định sửa nó. Tôi quá khó chịu với Jelly để thực sự chơi xung quanh nó.
orlp

1
"Thưa ông, tôi không biết tại sao bạn lại nổi điên. Thuật toán là thời gian không đổi. Đó là một điều tốt, phải không? Tại sao an ninh và nhân sự ở ngoài cửa?"
corsiKa

1
Đã đồng ý. Bit của một sự khác biệt giữa một số 8 chữ số và một số chữ số 417 triệu: p
Jonathan Allan

11

Toán học, 29 byte

Dựa trên câu trả lời của Dennis's Jelly .

RandomInteger[2*^9!-1]~Mod~#&

Tôi không khuyên bạn nên thực sự chạy cái này. 2e9!là một con số khá lớn ...

Nó hóa ra là ngắn nhất để tạo ra một số lượng lớn chia hết cho tất cả các đầu vào có thể và ánh xạ kết quả đến phạm vi cần thiết với một modulo đơn giản.

Lấy mẫu từ chối, 34 byte

Cách tiếp cận cũ của tôi dẫn đến mã có phần thú vị hơn:

13!//.x_/;x>#:>RandomInteger[13!]&

Lấy mẫu từ chối cơ bản. Chúng tôi khởi tạo đầu ra là 13! (lớn hơn đầu vào tối đa 2 30 ) và sau đó liên tục thay thế nó bằng một số nguyên ngẫu nhiên trong khoảng từ 0 đến 13! miễn là giá trị lớn hơn đầu vào.


1
Bạn có nghĩa là "nhỏ hơn hoặc bằng đầu vào"?

1
@Lembik Không. Chúng tôi muốn tạo lại giá trị miễn là nó không rơi vào phạm vi mong muốn.
Martin Ender

Ồ tôi hiểu rồi. Vì một số lý do, tôi nghĩ rằng chúng tôi đã liên tục lấy mẫu từ phạm vi mong muốn. Cảm ơn.

1
Nhắc tôi để thêm giới hạn thời gian vào lần tới :)

9

Brachylog , 9 byte

≥.∧13ḟṙ|↰

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

Điều này sử dụng 13!như trong câu trả lời của Martin Ender ( 13ḟnhỏ hơn một byte 2^₃₀).

được triển khai bằng cách sử dụng random_between/3, khi đào nguồn của nó, sử dụng random_float/0liên kết với random/1thuật toán Mersenne Twister phù hợp với mục đích của chúng tôi.

Giải trình

≥.           Input ≥ Output
  ∧          And
   13ḟṙ      Output = rand(0, 13!)
       |     Else
        ↰    Call recursively with the same input

7

Prolog (SWI) , 38 byte

X*Y:-Z is 2^31,random(0,Z,Y),Y=<X;X*Y.

Hoạt động bằng cách lấy mẫu từ chối.

Tạo một số ngẫu nhiên trong khoảng từ 0 đến 2 ^ 31-1 = 2147483647 cho đến khi tìm thấy một số nhỏ hơn hoặc bằng với đầu vào.

Tôi cảm thấy như thể tôi có thể sử dụng một vết cắt thay vì cái khác, nhưng tôi không thể thấy làm thế nào.


1
Bạn có thể tránh người khác sử dụng repeat, nhưng cuối cùng lại dài hơn 3 byte Tôi không chắc có cách nào ngắn hơn để có điểm lựa chọn vô hạn hơn lặp lại không.
Gây tử vong

@Firthize: Vâng, tôi cũng đã thử lặp lại. Tôi có một ký ức về việc sử dụng một cái gì đó như ,!.để buộc quay lại, nhưng tôi nhớ nó sai hoặc nó không áp dụng được cho giải pháp này.
Emigna

7

Mê cung , 63 byte

 ?
 #00}__""*_
 ;    #"  _
{-{=  } "><)
!{ : ;"({ +
@  }}:  >`#

(Cảm ơn @MartinEnder đã giúp đỡ với một số môn golf nặng ở đây.)

Mê cung là một ngôn ngữ 2D và nguồn ngẫu nhiên duy nhất của nó là trong một tình huống như sau:

   x
  "<)
 " "
 " "

Giả sử con trỏ lệnh nằm trên xvà di chuyển xuống dưới. Nó tiếp tục hạ cánh trên <đó, nếu đỉnh của ngăn xếp là 0 (luôn luôn như vậy trong chương trình thực tế ở trên) sẽ dịch chuyển hàng hiện tại còn lại 1:

   "
 "<)
 " "
 " "

Con trỏ lệnh bây giờ <đang di chuyển xuống dưới. Tại một ngã ba, Labyrinth quay đầu dựa trên đỉnh của ngăn xếp - âm là rẽ trái, dương là rẽ phải và không di chuyển về phía trước. Nếu đỉnh của ngăn xếp vẫn bằng không tại thời điểm này, chúng ta không thể tiến lên hoặc lùi lại vì không có đường đi, vì vậy Labyrinth sẽ ngẫu nhiên giữa rẽ trái hoặc rẽ phải với xác suất bằng nhau.

Về cơ bản những gì chương trình trên thực hiện là sử dụng tính năng ngẫu nhiên để tạo các số 100 bit (100 được chỉ định #00ở đây) và tiếp tục lặp cho đến khi tạo ra một số <= n.

Để thử nghiệm, có thể sẽ giúp sử dụng #0"thay cho các số 10 bit, với "đường dẫn không có op. Hãy thử trực tuyến!

Giải thích sơ bộ:

 ?            <--- ? is input and starting point
 #0"}__""*_   <--- * here: first run is *0, after that is *2 to double
 ;    #"  _
{-{=  } "><)  <--- Randomness section, +0 or +1 depending on path.
!{ : ;"({ +        After <, the >s reset the row for the next inner loop.
@  }}:  >`#

 ^    ^
 |    |
 |    The " junction in this column checks whether the
 |    100-bit number has been generated, and if not then
 |    continue by turning right into }.
 |
 Minus sign junction here checks whether the generated number <= n.
 If so, head into the output area (! is output as num, @ is terminate).
 Otherwise, head up and do the outer loop all over again.

7

Python, 61 byte

from random import*
lambda n,x=2.**30:int(randrange(x)*-~n/x)

Chỉnh sửa: Cập nhật để tránh hình thức bị cấm

Edit2: Đã lưu 2 byte, cảm ơn @ Jonathan ALLan

Edit3: Trả 2 byte cho một giải pháp đầy đủ chức năng - cảm ơn lần nữa @Jonathan ALLan

Edit4: Đã xóa f=, lưu 2 byte

Chỉnh sửa5: Đã lưu thêm 1 byte nhờ @ Jonathan ALLan

Chỉnh sửa 6: Đã lưu thêm 2 byte nhờ @ Jonathan ALLan

Đến bây giờ, git đổ lỗi sẽ chỉ vào tôi vì những điều tồi tệ, và JonathanAllan cho những thứ giúp ích.

Edit7: Khi trời mưa, nó đổ - 2 byte khác

Edit8: Và thêm 2 byte


1
Điều này sẽ không bao giờ xuất ra n, nhưng bạn có thể lưu hai byte khi bạn sửa nó bằng cách sử dụng from random import*và loại bỏ r..
Jonathan Allan

1
Có, bạn có thể sử dụng "toán tử nòng nọc" để tránh các dấu ngoặc đơn cần thiết khác, ...*(-~n*1.0/2**30))thay vì...*((n+1)*1.0/2**30))
Jonathan Allan

1
Có thật không? Ngọt! Bạn có ác cảm lâu nay với số 70 không? Cảm ơn rất nhiều vì sự giúp đỡ của bạn
iwaseatenbyagrue

1
Trong thực tế randrangedường như chấp nhận một float, vì vậy lambda n,x=2.**30:int(randrange(x)*-~n/x)tiết kiệm bốn [chỉnh sửa ...] bốn!
Jonathan Allan

1
^ hai cái khác trong đó với dấu ngoặc đơn loại bỏ. Chỉ cần đi để hiển thị nhân của bạn là con đường để đi!
Jonathan Allan

6

Python 2 , 61 byte

from random import*
lambda n:map(randrange,range(1,2**31))[n]

Giả ngẫu nhiên chọn các số nguyên trong khoảng từ 0 đến k cho tất cả các giá trị của k trong khoảng từ 0 đến 2 31 - 2 , sau đó lấy số nguyên tương ứng với k = n .


5

Mẻ, 64 byte

@set/ar=%random%*32768+%random%
@if %r% gtr %1 %0 %1
@echo %r%

%random%chỉ cho 15 bit ngẫu nhiên, vì vậy tôi phải kết hợp hai số ngẫu nhiên. Vòng lặp cho đến khi giá trị ngẫu nhiên nằm trong phạm vi mong muốn, vì vậy chậm cho mức thấp n; 98 byte cho phiên bản nhanh hơn:

@set/a"n=%1+1,m=~(3<<30)/n*n,r=%random%*32768+%random%
@if %r% geq %m% %0 %1
@cmd/cset/a%r%%%%n%

Mã có thể chậm nhưng câu trả lời của bạn rất nhanh!

3
@Lembik Tôi đã có câu trả lời sẵn sàng trong câu hỏi đã bị xóa của bạn ...
Neil

Điều này có lặp lại số mong muốn trước không, và sau đó tất cả các số khác chuyển thành lớn hơn n?
Erik the Outgolfer

@EriktheOutgolfer Không; trừ khi bạn sử dụng call, việc gọi một tập lệnh bó sẽ chấm dứt tập lệnh hiện tại.
Neil

5

MATL , 12 byte

Cảm ơn @AdmBorkBork@Suever đã cho tôi biết cách tắt bộ đệm TIO.

`30WYrqG>}2M

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

Điều này sử dụng một phương pháp từ chối : tạo một số nguyên ngẫu nhiên từ 0đến 2^30-1và lặp lại trong khi nó vượt quá đầu vào n. Điều này được đảm bảo để chấm dứt với xác suất 1, nhưng số lần lặp trung bình là 2^30/n, và do đó phải mất rất lâu để nnhỏ hơn đáng kể so với 2^30.

`         % Do...while
  30W     %   Push 2^30
  Yr      %   Random integer from 1 to 2^30
  q       %   Subtract 1
  G>      %   Does it exceed the input? If so: next iteration. Else: exit
}         % Finally (execute right before exiting the loop)
  2M      %   Push the last generated integer
          % End (implicit). Display (implicit)

4

JavaScript (ES6), 55 54 byte

f=(n,m=1)=>m>n?(x=Math.random()*m|0)>n?f(n):x:f(n,m*2)

Tạo các số nguyên trong phạm vi [0 ... 2 k - 1] , trong đó k là số nguyên nhỏ nhất sao cho 2 k lớn hơn n . Lặp lại cho đến khi kết quả rơi vào [0 ... n] .

Tại sao?

Điều này dựa trên các giả định sau:

  • Trong nội bộ, các giá trị số nguyên giả ngẫu nhiên được tạo bởi công cụ JS để cung cấp Math.random()đồng nhất trong bất kỳ khoảng thời gian nào [0 ... 2 k -1] (với k <32 ).

  • Sau khi được nhân với công suất chính xác là 2, các giá trị float của IEEE 754 được trả về Math.random()vẫn đồng nhất trong các khoảng thời gian như vậy.

Nếu bất cứ ai có thể xác nhận hoặc bác bỏ những giả thuyết này, xin vui lòng cho tôi biết trong các ý kiến.

Bản giới thiệu

Tạo 1 triệu giá trị trong [0 ... 2] và hiển thị số liệu thống kê kết quả.


Math.floor (Math.random () * (n + 1)) tạo ra kết quả phân phối không kém cho tôi, vì vậy sẽ rất tuyệt nếu thấy có bất kỳ N <2 ^ 30 thực tế nào, sẽ tạo ra bất kỳ sự bất thường phân phối nào ở tất cả.
zeppelin

1
@zeppelin bạn cần có quá nhiều lần chạy thử để xác định bất kỳ sự bất thường nào vì một số float ngẫu nhiên trong phạm vi đó sẽ có một trong 2 ^ 53 giá trị sẽ được phân phối đồng đều nhất có thể trong 2 ^ 30 kết quả. Vì vậy, ngay cả đối với số lượng lớn trong phạm vi, lỗi sẽ là 1 trong 2 ^ 23, điều đó có nghĩa là bạn cần một số lượng thử nghiệm vô lý. Có lẽ bạn sẽ muốn một số đơn đặt hàng lớn hơn số lượng mẫu ban đầu (2 ^ 53). Tuy nhiên, nó không thể thống nhất hoàn toàn nếu số nhân không chia đều số lượng mẫu, đó là lý do Arnauld sử dụng sức mạnh của hai.
Martin Ender

4

Bash (+ coreutils), 44 byte

/ dev / urandom dựa trên giải pháp

od -w4 -vtu4</d*/ur*|awk '($0=$2)<='$1|sed q

Sẽ đọc các số nguyên 32 bit không dấu từ /dev/urandomvà lọc chúng ra awkcho đến khi tìm thấy một số trong một phạm vi nhất định, sau đó sed qsẽ hủy bỏ đường ống.


Hoan hô cho bash :)

4

Haskell, 70 byte

import System.Random
g n=head.filter(<=n).randomRs(0,2^30)<$>getStdGen

Không phải là một thuật toán rất hiệu quả nhưng nó hoạt động. Nó tạo ra một danh sách vô hạn các số nguyên (hoặc số float nếu cần, do hệ thống loại của Haskell) giới hạn bởi [0,2 ^ 30] và lấy số nguyên đầu tiên nhỏ hơn hoặc bằng n. Đối với n nhỏ này có thể mất một thời gian dài. Các số ngẫu nhiên phải được phân phối đồng đều, như được chỉ định trong tài liệu cho RandomR, vì vậy tất cả các số trong khoảng [0,2 ^ 30] phải có cùng xác suất (1 / (2 ^ 30 + 1)) do đó tất cả các số trong [ 0, n] có cùng xác suất.

Phiên bản thay thế:

import System.Random
g n=head.filter(<=n).map abs.randoms<$>getStdGen

Phiên bản này là khủng khiếp nhưng nó tiết kiệm toàn bộ byte. randomssử dụng một phạm vi tùy ý được xác định bởi loại để tạo một danh sách số vô hạn. Điều này có thể bao gồm các tiêu cực vì vậy chúng ta cần ánh xạ nó absđể buộc chúng dương (hoặc bằng không). Điều này là cực kỳ chậm đối với bất kỳ giá trị nào của n không lớn một cách vô lý. EDIT : Sau đó tôi nhận ra rằng phiên bản này không được phân phối đồng đều vì xác suất nhận được 0 tệ hơn các số khác do sử dụng abs. Để tạo ra một số số, mtrình tạo có thể tạo ra mhoặc -mtrong trường hợp 0 ​​chỉ có 0 chính nó sẽ hoạt động, do đó xác suất của nó là một nửa số khác.


Hoan hô cho Haskell (quá)!

4

Thạch , 9 byte

⁴!Ẋ’>Ðḟ⁸Ṫ

Hãy thử trực tuyến! - mã ở trên sẽ không chạy trên TIO vì phạm vi kích thước 16! phải được xây dựng trước (không đề cập đến thực tế là sau đó chúng cần được xáo trộn và sau đó được lọc!), vì vậy đây là điều tương tự ở quy mô nhỏ hơn nhiều, lặp lại 30 lần cho đầu vào 3 với giới hạn 10.

Làm sao?

⁴!Ẋ’>Ðḟ⁸Ṫ - Main link: n
⁴         - 16
 !        - factorial: 20922789888000
  Ẋ       - shuffle random: builds a list of the integers 1 through to 16! inclusive and
          - returns a random permutation via Python's random.shuffle (pretty resource hungry)
   ’      - decrement (vectorises - a whole pass of this huge list!)
     Ðḟ   - filter out if: (yep, yet another pass of this huge list!)
    >     -     greater than
       ⁸  -     left argument, n
        Ṫ - tail: return the rightmost remaining entry.

Lưu ý: sẽ hiệu quả hơn một nghìn lần cho cùng một số byte nếu ȷ⁵làm điều mà người ta mong đợi một cách ngây thơ và trả lại mười cho mười, nhưng đó không phải là trường hợp vì nó không được đánh giá là mười theo nghĩa đen được sử dụng theo số chữ ȷ...nhưng thay vào đó là hai chữ riêng biệt được phân tích cú pháp, ȷvới số mũ mặc định là ba nghìn, và cho mười.


Huh, đó là 9 ký tự, nhưng 22 byte
Kristoffer Sall-Storgaard

@ KristofferSall-Storgaard Mỗi ký tự là một trong 256 byte trong trang mã của Jelly , tôi đã quên biến các byte từ thành một liên kết như tôi thường làm.
Jonathan Allan

1
năm, tôi đã tra cứu nó và phát hiện ra điều tương tự
Kristoffer Sall-Storgaard

4

JDK 9 trên jshell, 75 59 byte

n->(new Random()).ints(0,1<<30).dropWhile(x->x>n).findAny()

Sử dụng

((IntFunction)(n->(new Random()).ints(0,1<<30).dropWhile(x->x>n).findAny())).apply(<n>)
  • -16 byte: Cảm ơn Jakob!
  • Giả sử rằng chúng tôi coi jshell là một môi trường thời gian chạy hợp lệ.
  • jshell, như một môi trường thời gian chạy, không yêu cầu nhập rõ ràng cho các thư viện lõi và không yêu cầu dấu chấm phẩy.
  • Trả về một OptionalInt. Các quy tắc không chỉ định rằng loại trả về phải là nguyên thủy và tôi đang xem xét OptionalIntđể trở thành một đại diện hợp lệ cho kết quả.

1
Cảm ơn @ kevin-cruijssen đã truyền cảm hứng. Golf mã đầu tiên của tôi!
Pete Terlep

Việc đầu ra đóng hộp có được chấp nhận hay không khác với việc có Optionalđược chấp nhận hay không. Tôi sẽ xác nhận với người đăng nếu tôi là bạn. Ngoài ra, không cần phải tính toàn bộ bài tập; chỉ cần biểu thức lambda là đủ.
Jakob

1
Bạn có thể lưu 4 byte bằng cách xóa dấu ngoặc đơn xung quanh tham số lambda nnew Random().
Jakob

3

PHP, 30 byte

    while($argn<$n=rand());echo$n;

Chạy với echo <N> | php -Rn '<code>'.

chọn một số ngẫu nhiên trong khoảng từ 0 đến getrandmax()(2 ** 31-1 trên máy 64 bit của tôi);
lặp lại trong khi đó là lớn hơn đầu vào.

Việc này có thể mất một lúc ... AMD C-50 (1 GHz) của tôi cần trong khoảng từ 0,3 đến 130 giây N=15.

Một cách nhanh hơn cho trung bình N( 46 byte ):

for(;++$i<$x=1+$argn;)$n+=rand()%$x;echo$n%$x;

hoặc là

for(;++$i<$x=1+$argn;$n%=$x)$n+=rand();echo$n;

lấy N+1số nguyên ngẫu nhiên, tính tổng chúng và lấy modulo với N+1.
C-50 cần khoảng. 8 giây cho 1 triệu lượt chạy.

Một giải pháp không hợp lệ cho 19 byte :

echo rand(0,$argn);

3

PowerShell , 35 byte

for(;($a=Random 1gb)-gt"$args"){}$a

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

Một phương pháp lấy mẫu từ chối khác. Đây là một forvòng lặp vô hạn , đặt giá trị $alà một Randomsố nguyên nằm giữa 01gb( = 1073741824 = 2^30) và tiếp tục lặp miễn là số nguyên đó là -greater than đầu vào $args. Khi vòng lặp hoàn thành, chúng ta chỉ cần đặt $avào đường ống và đầu ra là ẩn.

Lưu ý: Điều này sẽ mất nhiều thời gian nếu đầu vào là một số nhỏ.


3

Python 2 , 72 69 byte

-3 byte nhờ xnor (ghi đè tích idhợp dưới dạng biến)

from random import*
n=input()
while id>n:id=randrange(2**30)
print id

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

randrange(2**30)tạo ra một số giả phân phối đồng đều (Mersenne Twister 2 19937-1 ) từ phạm vi [0,2 30 ) . Vì nđược đảm bảo dưới 2 30, điều này có thể được gọi lặp đi lặp lại cho đến khi nó không lớn hơn đầu vào. Sẽ mất một thời gian dài dự kiến ​​cho các giá trị rất thấp n, nhưng thường hoạt động trong vòng một phút ngay cả đối với các đầu vào thấp đến 50.


2
Bạn có thể khởi tạo r=''là "vô cùng". Hoặc, tốt hơn nữa, không khởi tạo rvà thay vào đó sử dụng idở mọi nơi r.
xnor


2

05AB1E , 11 byte

žIÝ.rDI›_Ϥ

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

Giải trình

žIÝ          # push the inclusive range [0 ... 2^31]
   .r        # get a random permutation (pythons random.shuffle)
     D       # duplicate this list
      I      # push input
       ›_Ï   # keep only elements from the list not greater than input
          ¤  # take the last one

Vì danh sách [0 ... 2147483648]quá lớn cho TIO, liên kết sử dụng 1.000.000thay thế.

Giải pháp thay thế (trung bình) nhanh hơn nhiều 11 byte

[žIÝ.RD¹›_#

Dùng thử trực tuyến

Giải trình

[             # start loop
 žIÝ          # push the inclusive range [0 ... 2^31]
    .R        # pick a random integer (pythons random.chiose)
      D       # duplicate
       ¹      # push input
        ›_#   # break if random number is not greater than input
              # implicitly output top of stack (the random number)

žJL.R%cho 6 trừ khi tôi thiếu một cái gì đó rất lớn. Đẩy 2 ^ 32, liệt kê từ 0 đến 2 ^ 32, chọn ngẫu nhiên. Đầu vào modulo. Sẽ hoàn toàn vít hiệu quả mà bạn có.
Bạch tuộc ma thuật Urn

@ carusocomputing. Bạn cần Icó 7 byte để có được các đối số cho mô đun theo đúng thứ tự (và có thể Ýthay vì L), nhưng nếu không thì đó chắc chắn là một giải pháp ngắn hơn. Tôi đã thấy Dennis làm điều đó trong câu trả lời Jelly của anh ấy, nhưng vì đây là ý tưởng đầu tiên của tôi nên tôi đã giữ nó. Vì cách tiếp cận này khác với cách này, bạn có thể đăng nó dưới dạng một câu trả lời riêng.
Emigna

DI‹Ïsẽ tránh vòng lặp.
Bạch tuộc ma thuật Urn

Ngoài ra, như vậy, điều này không được đảm bảo để chấm dứt; nếu tôi không nhầm, đầu vào của 0hầu như luôn luôn dẫn đến một vòng lặp gần như vô tận, khiến cho việc chấm dứt trở nên khó khăn. Mặc dù giải pháp không cho phép khả năng chấm dứt trong tất cả các tình huống nhưng nó không được đảm bảo do tính ngẫu nhiên.
Bạch tuộc ma thuật Urn

@carusocomputing: Đối với đầu vào rất nhỏ, trung bình phiên bản thứ hai sẽ mất một thời gian rất dài để hoàn thành có, nhưng sẽ có đủ thời gian.
Emigna

2

Python 2, 89 byte

l=range(2**31)
import random
random.shuffle(l)
n=input()
print filter(lambda x:x<=n,l)[0]

Giải trình

L=range(2**31)      # Create a list from 0 to 2^31 exclusive. Call it <L>.
import random       # Import the module <random>.
random.shuffle(L)   # Use 'shuffle' function from <random> module,
                    # to shuffle the list <L>.
n=input()           # Take the input -> <n>.

print
    filter(         # Create a new sequence,
    lambda x:x<=n   # where each element is less than or equal to <n>.
    ,L)             # from the list <L>.
    [0]             # Take the first element.

Điều này rất không hiệu quả, vì nó tạo ra 2 ^ 31 số nguyên, xáo trộn và lọc chúng.

Tôi thấy không có điểm nào trong việc chia sẻ liên kết TIO, nơi nó tạo ra các danh sách lớn như vậy, vì vậy đây là liên kết TIO cho n= 100.

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


2

Java 8, 84 83 80 71 62 byte

n->{int r;for(;(r=(int)(Math.random()*(1<<30)))>n;);return r;}

-1 byte nhờ @ OliverGrégoire .
-3 byte nhờ @Jakob .
-9 byte chuyển đổi Java 7 sang Java 8.
-9 byte bằng cách thay đổi java.util.Random().nextInt(1<<30)thành (int)(Math.random()*(1<<30)).

Giải trình:

Hãy thử nó ở đây.

n->{        // Method with integer parameter and integer return-type
  int r;    //  Result-integer
  for(;(r=(int)(Math.random()*(1<<30)))>n;);
            //  Loop as long as the random integer is larger than the input
            //  (the random integer is in the range of 0 - 1,073,741,824 (2^30))
  return r; //  Return the random integer that is within specified range
}           // End method

LƯU Ý: Rõ ràng có thể mất rất nhiều thời gian cho đầu vào nhỏ.

Ví dụ đầu ra:

407594936

2
@Aaron Tôi cũng đã đặt câu hỏi này nhưng hãy xem điểm đầu dòng thứ hai: "Bất kỳ đối số nào khi gọi hàm ngẫu nhiên tích hợp hoặc thư viện phải là hằng số. Đó là chúng phải hoàn toàn độc lập với giá trị đầu vào." Đây là lý do max int được sử dụng.
Chọc

1
2^30= 1073741824. Bạn thích sử dụng -1>>>1(= 2147483647). Nhưng điều này tồn tại: 1<<30chính xác là bằng 2^30; và ngắn hơn 1 byte.
Olivier Grégoire

1
Thế còn int c(int n){int r;for(;(r=new java.util.Random().nextInt(1<<30))>n;);return r;}?
Jakob

@Jakob Cảm ơn. Tôi thậm chí đã rút ngắn nó thêm 18 byte bằng cách sử dụng Java 8 thay vì 7 và sử dụng Math.random()thay vì java.util.Random().nextInt.
Kevin Cruijssen

2

Python 3, 51 byte

Đây là một giải pháp python với một nguồn ngẫu nhiên không chính thống.

print(list(set(map(str,range(int(input())+1))))[0])

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

Vì vậy, để phá vỡ điều này.

int(input())+1

Lấy số đầu vào, và thêm 1vào nó.

set(range(...))

Tạo tập hợp {0, 1, 2, 3, 4, ... n}cho tất cả các kết quả có thể.

print(list(...)[0])

Lấy tập hợp, chuyển đổi nó thành danh sách và lấy mục đầu tiên.

Điều này hoạt động vì trong Python 3, thứ tự set()được thiết lập bởi PYTHONHASHSEED ( không thể lấy được nhưng được thiết lập khi thực thi tập lệnh).

Phải thừa nhận rằng, tôi đoán rằng đây là phân phối đồng đều, vì hash()giá trị được gán ngẫu nhiên và tôi đang xem xét chọn ngẫu nhiên giá trị với một giá trị cụ thể hash(), thay vì chỉ trả lại hash(input())chính nó.

Nếu bất cứ ai biết liệu đây là một phân phối thống nhất, hoặc làm thế nào tôi có thể kiểm tra điều đó, xin vui lòng bình luận.


1

C #, 57 byte

n=>{int x=n+1;while(x>n)x=new Random().Next();return x;};

Hàm ẩn danh trả về một số nguyên nằm trong khoảng từ 0 đến n.

Số đầu vào càng nhỏ, thời gian trả về giá trị ngẫu nhiên càng dài.

Chương trình đầy đủ:

using System;

class RandomNumber
{
    static void Main()
    {
        Func<int, int> f =
        n=>{int x=n+1;while(x>n)x=new Random().Next();return x;};

        // example
        Console.WriteLine(f(100000));
    }
}

2
"Bất kỳ đối số nào khi gọi hàm ngẫu nhiên tích hợp hoặc thư viện phải là hằng số. Đó là chúng phải hoàn toàn độc lập với giá trị đầu vào." Đối số Nextkhông tĩnh.
Yytsi

1

Bash + coreutils, 20 byte

Chơi gôn

seq 0 $ 1 | shuf | sed 1q

shuf - tạo hoán vị ngẫu nhiên

Shuf sẽ sử dụng đoạn mã sau : để tạo hoán vị:

permutation = randperm_new (randint_source, head_lines, n_lines);

mà kết thúc ở randint_genmax

/* Consume random data from *S to generate a random number in the range
0 .. GENMAX.  */

randint
randint_genmax (struct randint_source *s, randint genmax) 
{
      ...

      randread (source, buf, i);

      /* Increase RANDMAX by appending random bytes to RANDNUM and
         UCHAR_MAX to RANDMAX until RANDMAX is no less than
         GENMAX.  This may lose up to CHAR_BIT bits of information
         if shift_right (RANDINT_MAX) < GENMAX, but it is not
         worth the programming hassle of saving these bits since
         GENMAX is rarely that large in practice.  */
      ...
}

lần lượt sẽ đọc một vài byte dữ liệu ngẫu nhiên từ nguồn ngẫu nhiên cấp thấp:

/* Consume random data from *S to generate a random buffer BUF of size
   SIZE.  */

void
randread (struct randread_source *s, void *buf, size_t size)
{
  if (s->source)
    readsource (s, buf, size);
  else
    readisaac (&s->buf.isaac, buf, size);
}

tức là ở mức thấp, không có sự phụ thuộc trực tiếp giữa shufgiá trị đầu vào và dữ liệu được đọc từ nguồn ngẫu nhiên (ngoài việc tính toán dung lượng bộ đệm byte cần thiết).


6
Đây không phải là cung cấp đầu vào như là một đối số cho trình tạo số ngẫu nhiên của bạn?
Martin Ender

Ngay cả khi điều này không hợp lệ, xin vui lòng gửi một câu trả lời bash khác!

@MartinEnder tốt, không trực tiếp, nó chỉ sử dụng đầu vào để xác định giới hạn trên cho phạm vi số nguyên được tạo và jot will arrange for all the values in the range to appear in the output with an equal probability(đó có thể là đường biên, nhưng vẫn).
zeppelin

2
Nếu tôi đào đủ sâu vào bất kỳ trình tạo số ngẫu nhiên nào, tôi chắc chắn tôi sẽ tìm thấy một cuộc gọi vào RNG cấp thấp hơn mà không trực tiếp sử dụng đối số ban đầu. Điểm quan trọng của thách thức là có được phân phối đồng đều có kích thước tùy ý từ phân phối có kích thước cố định mà bạn vẫn không thực hiện.
Martin Ender

1

SmileBASIC, 38 byte

INPUT N@L
R=RND(1<<30)ON N<=R GOTO@L?R

Tạo các số ngẫu nhiên cho đến khi số đó nhỏ hơn số đầu vào.


1

Ruby, 23 15 23 32 29 byte

->n{1while n<q=rand(2**30);q}

Làm thế nào nó hoạt động:

  • 1while [...];thực hiện câu lệnh ít nhất một lần: 1trước khi whileđóng vai trò là người đứng đầu
  • Nhận một số ngẫu nhiên trong phạm vi 0..2 ^ 30-1 ( thấp hơn 2 ^ 30 , như được chỉ định)
  • Lặp lại nếu số cao hơn tham số đầu vào (Có thể mất chút thời gian khi n nhỏ)

1

Ồ, 26 byte

IΩ
D31º#╬D0[>?D-+∞;,

Giải trình:

IΩ                 ■Main wire
IΩ                 ■Call wire below

D31º#╬D0[>?D-+∞;,  ■"Real main" wire
D                  ■Duplicate input
 31º#╬D            ■Push random_int in [0..2^31] twice
       0[          ■Push input again
         >?    ;   ■If(random_int > input){
           D-+     ■  remove the random_int
              ∞    ■  recursion
               ;   ■}
                ,  ■Print random_int

Có một thông dịch viên cho ngôn ngữ này? Còn trang Code thì sao?
ATaco

@ATaco: Thông dịch viên , Mã trang: CP-437
Emigna

1

Đi, 63 61 byte

import."math/rand"
var n=0;func R(){q:=n;for;q<n+1;n=Int(){}}

Sử dụng nó như thế này:

func main() {
    n = 5000
    R()
    print(n)
}

Kiểm tra nó trực tiếp tại sân chơi đi


Theo mặc định của chúng tôi, không được phép nhập dữ liệu từ các biến được xác định trướcghi đầu ra vào các biến được xác định trước . Bạn có thể sử dụng con trỏ tới các biến toàn cục
Dennis

1

Golang, 84 78 71 byte

import."math/rand"
func R(n int)int{q:=n+1;for;q>=n;q=Int(){};return q}

Lấy mẫu từ chối đơn giản.

Lưu ý: vì hạt giống toán học / rand là hằng số 1, người gọi phải gieo hạt trừ khi muốn có kết quả không đổi.

Kiểm tra: https://play.golang.org/p/FBB4LKXo1r Không còn có thể kiểm tra trên thực tế trên hệ thống 64 bit, vì nó trả về tính ngẫu nhiên 64 bit và sử dụng kiểm tra từ chối.

package main

import "fmt"
import "time"

/* solution here *//* end solution */

func main() {
    Seed(time.Now().Unix())
    fmt.Println(R(1073741823))
}

1
nếu bạn sử dụng import."math/rand"thì Int31có sẵn trong không gian tên toàn cầu và bạn có thể lưu 4 byte, cũng intđược đảm bảo ít nhất là 32 bit, giúp bạn tiết kiệm thêm 6 byte
Kristoffer Sall-Storgaard

Sử dụng :=cú pháp cho 3 byte khác
Kristoffer Sall-Storgaard

Sử dụng int thay vì int32 không lưu bất kỳ byte nào vì chúng ta cần truyền kết quả của Int31 () - 3 * int + () = 11 byte so với 2 * int32 = 10 byte.
Đi xe đạp

1
Không cần phải truyền, có một Int()chức năng trong gói rand, ngoài ra, bạn có thể xóa khoảng trống sauimport
Kristoffer Sall-Storgaard
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.