Kịch bản ngẫu nhiên không thực sự ngẫu nhiên


106

Như một trò đùa nhỏ trong văn phòng, ai đó muốn một kịch bản chọn ngẫu nhiên một cái tên, và nói rằng người đó sẽ pha một ly đồ uống.

Hãy gọi mọi người là John, Jeff, Emma, ​​Steve và Julie.

Tôi nghĩ sẽ rất buồn cười khi tạo ra một kịch bản có vẻ ngẫu nhiên trong nháy mắt, nhưng thực sự luôn cho cùng một người với đầu ra (Tùy bạn là người bạn chọn).

Câu trả lời được bình chọn cao nhất sẽ thắng sau một tuần

Và người chiến thắng là....

Paul R với (hiện tại) 158 phiếu.

Câu trả lời ở đây rất hay, và nếu có ai có ý tưởng nào khác chưa được đăng, xin vui lòng thêm chúng, tôi thích đọc qua chúng.



6
@AstroCB một trong những mục yêu thích của tôi. Ngay phía sau bàn bợm.
Cruncher

50
Có vẻ như nó sẽ lén lút hơn nếu là ngẫu nhiên, ngoại trừ việc không bao giờ chọn một người.
Brendan Long

6
@AstroCB cái này cũng tuyệt vời: Dilbert.com/strips/comic/2001-10-25
gilbertohasnofb

3
Tôi đã đi qua trang đầu tiên: hầu hết các câu trả lời luôn chọn John, cao thứ 2 là Julie, Jeff hiếm khi được chọn và Steve bằng 1. Ngay cả Ray cũng được chọn bởi một người nhưng không ai chọn Emma. Đạo đức của câu chuyện: khi đứng trong một hàng để quyết định ngẫu nhiên ai sẽ mua đồ uống, hãy đặt tên cho mình là Emma.
Biến khổ sở

Câu trả lời:


171

C

Điều quan trọng là quyết định ai sẽ mua càng nhanh càng tốt, để không lãng phí thời gian uống quý giá - do đó C là lựa chọn rõ ràng để có được hiệu suất tối đa:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    const char *buyer;
    int n;

    srand(time(NULL)); // make sure we get a good random seed to make things fair !
    n = rand();
    switch (n % 5)
    {
        case 0: buyer = "John";
        case 1: buyer = "Jeff";
        case 2: buyer = "Emma";
        case 3: buyer = "Steve";
        case 4: buyer = "Julie";
    }
    printf("The person who is buying the drinks today is: %s !!!\n", buyer);
    return 0;
}

Giải trình:

Điều này sẽ hoạt động tốt nếu có break;sau mỗi trường hợp trong câu lệnh chuyển đổi. Tuy nhiên, mỗi trường hợp "rơi vào" trường hợp tiếp theo, vì vậy, cô nàng tội nghiệp luôn luôn mua đồ uống.


17
+1 cho hiệu suất - nhanh hơn nhiều so với lăn một cái chết vật lý! ;)
Jwosty

16
Tôi đang suy nghĩ về việc tối ưu hóa nó hơn nữa, có lẽ với SIMD hoặc GPGPU, chỉ để có được hiệu suất cao hơn một chút. ;-)
Paul R

7
Hoàn toàn thực tế sống áp dụng. Không ai có thể thậm chí đặt câu hỏi rằng đó là một tai nạn trong một chút.
iFreilicht

5
Có phải chỉ tôi hay cái này quá rõ ràng để phát hiện ra?
Alvin Wong

3
@AlvinWong Tôi không nhận thấy nó ngay lập tức. Sau đó, một lần nữa, tôi không sử dụng C thường xuyên hoặc bất kỳ ngôn ngữ nào khác xuất phát từ BCPL.
Rhymoid

164

PHP

Không thể để điều này đi, vì vậy đây là một cái khác:

$f = fopen('/dev/random','r');
$s = fread($f, 4);
fclose($f);

$names = ['John', 'Jeff', 'Emma', 'Steve', 'Julie'];

echo $names[$s % count($names)];

Điều này thực sự không được đảm bảo để sản xuất john, nhưng cơ hội là rất tốt. PHP sẽ vui vẻ lấy bất cứ thứ gì / dev / ngẫu nhiên để thấy rằng nó (có thể) không thể phân tích cú pháp và đưa ra số 0 rất hợp lý thay thế. Rốt cuộc, cảnh báo cho lập trình viên về một lỗi tiềm ẩn được coi là một tội lỗi chết người trong PHP.


25
Bạn phải yêu thích PHP - và thậm chí tốt hơn, đôi khi sẽ hiếm khi chọn người khác. Vì vậy, nếu bạn may mắn, ban đầu nó sẽ có vẻ hơi thiên vị
Falco

142
+1000 cho "... cảnh báo cho lập trình viên về một lỗi tiềm ẩn được coi là một tội lỗi chết người trong PHP."
jsedano


85

Haskell

Nó quá trong suốt nếu nó luôn trả về cùng tên, vì vậy hãy thử các cách sau

import Control.Monad
import System.Exit
import Control.Concurrent
import Control.Concurrent.MVar


data Person = John | Jeff | Emma | Steve | Julie deriving (Show, Enum)

next Julie = John
next p = succ p

rotate :: MVar Person -> IO ()
rotate mp = modifyMVar_ mp (return . next) >> rotate mp

main :: IO ()
main = do
    mp <- newMVar John
    forkIO $ rotate mp
    putStrLn "Shuffling"
    readMVar mp >>= print
    exitWith ExitSuccess

Bất cứ khi nào bạn muốn nó là ngẫu nhiên:

[~]$ runghc prog.hs
Shuffling
Steve

[~]$ runghc prog.hs
Shuffling
Julie

Và cho mục tiêu không may của bạn:

[~]$ runhugs prog.hs
Shuffling
John

[~]$ runhugs prog.hs
Shuffling
John

Những cái ôm chỉ thực hiện đa nhiệm hợp tác, vì vậy rotateluồng sẽ không bao giờ chạy


24
Đó là ma quỷ!
Daenyth

8
Cảm giác như chụp ảnh một con xúc xắc chưa ngừng di chuyển.
Vi.

1
@Vi. Đó là một sự tương tự tốt đẹp. May mắn thay, việc sử dụng MVars đảm bảo rằng hình ảnh sẽ không bị mờ. :)
monocell

@monocell Vâng, về mặt kỹ thuật, thậm chí một bức ảnh của một vật thể chuyển động có thể rõ ràng.
ghosts_in_the_code

75

Bash - sự đơn giản tối đa

Một ví dụ rất đơn giản - hãy tránh mọi vấn đề bằng cách thực hiện theo cách của sách giáo khoa. Đừng quên chọn máy phát điện từ đồng hồ hệ thống để có kết quả tốt!

#!/bin/bash

names=(John Jeff Emma Steve Julie)   # Create an array with the list of names
RANDOM=$SECONDS                      # Seed the random generator with seconds since epoch
number=$((RANDOM % 5))               # Pick a number from 0 to 4
echo ${names[number]}                # Pick a name

Điều này phụ thuộc vào người dùng không biết $SECONDSnội dung thực sự làm gì; nó trả về số giây kể từ khi shell hiện tại bắt đầu. Như trong kịch bản, cái vỏ luôn bắt đầu từ 0 giây trước, vì vậy máy phát điện luôn được gieo hạt 0và Julie luôn mua bia.

Thêm:

Cái này đứng lên để xem xét khá tốt; Nếu bạn nhập cùng mã trên dòng lệnh thay vì trong tập lệnh, nó sẽ cho kết quả ngẫu nhiên, vì $SECONDSsẽ trả về thời gian mà vỏ tương tác của người dùng đã chạy.


9
\ o / Có nghĩa là !!! Thực sự có nghĩa!!! $SECONDSftw! \ o /
yeti

Điều gì xảy ra nếu bạn sourcenày, thay vì chỉ thực hiện nó? Shebang vẫn sẽ kích hoạt một lớp vỏ mới hay cái gì đó?
jpmc26

1
@ jpmc26: nếu bạn thực hiện nó sourcethì nó hoàn toàn giống như khi bạn tự gõ các lệnh trên dòng lệnh; #! / bin / bash là một nhận xét vì vậy nó bị bỏ qua. Điều này đúng với bất kỳ kịch bản nào.
Bạo loạn

57

C #

using System;
using System.Linq;

namespace PCCG {
    class PCCG31836 {
        public static void Main() {
            var names = new string[]{ "John", "Jeff", "Emma", "Steve", "Julie" };
            var rng = new Random();
            names.OrderBy(name => rng.Next());
            Console.WriteLine(names[0]);
        }
    }
}

Điều này có thể không đánh lừa những người quen thuộc với API .Net, nhưng những người không biết nó có thể tin rằng OrderByđiều chỉnh đối tượng bạn gọi nó và đó là một lỗi đáng tin cậy đối với người mới sử dụng API.


1
Ngay cả khi OrderBy giả định sửa đổi đối tượng, cuộc gọi đó có thực sự sắp xếp danh sách ngẫu nhiên không? Là một người không quen thuộc với .NET, tôi đoán đầu tiên là vì rng.Next()chỉ được gọi một lần, nên mảng sẽ được sắp xếp theo hằng số, dẫn đến không có thay đổi (hoặc thay đổi chỉ phụ thuộc vào thuật toán sắp xếp).
Brilliand

1
@Brilliand Đối số được truyền cho OrderBy không phải là giá trị tĩnh, nó được thực thi mỗi khi một phần tử được sắp xếp và trong trường hợp này trả về các giá trị ngẫu nhiên mà không so sánh bất kỳ giá trị nào. Nó thực sự sẽ hoạt động chính xác nếu dòng lànames = names.OrderBy(name => rng.Next());
user3188175

1
Dấu =>hiệu cho thấy đây là biểu thức lambda C # (bao đóng).
Người tuyết

44

PowerShell

$names = @{0='John'; 1='Jeff'; 2='Emma'; 3='Steve'; 4='Julie'}
$id = random -maximum $names.Length
$names[$id]

Điều này sẽ luôn luôn đầu ra John.

$nameslà một System.Collections.Hashtablecái không có Lengthtài sản. Bắt đầu với PowerShell v3, Length(và cũng Countcó thể) được sử dụng làm tài sản trên bất kỳ đối tượng nào. Nếu một đối tượng không có thuộc tính, nó sẽ trả về 1khi đối tượng không rỗng, nếu không nó sẽ trả về 0. Vì vậy, trong câu trả lời của tôi, $names.Lengthđánh giá là 1 và random -maximum 1luôn trả về 0 vì mức tối đa là độc quyền.


42

Q

show rand `John`Jeff`Emma`Steve`Julie;
exit 0;

Q luôn khởi tạo hạt giống số ngẫu nhiên của nó với cùng một giá trị.


8
vì vậy về cơ bản nó không ngẫu nhiên chút nào
Sam Creamer

3
@SamCreamer Mục đích của câu hỏi là rất nhiều để làm cho đầu ra không ngẫu nhiên. Nhưng điều này có vẻ ngẫu nhiên nên nó chắc chắn phù hợp với dự luật
Cruncher

4
Xin lỗi, ý tôi là số ngẫu nhiên của Q không phải là ngẫu nhiên, câu hỏi này chắc chắn đáp ứng các tiêu chí. Không có nghĩa là đi qua theo cách đó!
Sam Creamer

Vâng, vì vậy bạn phải tìm cách riêng của mình để tạo một hạt giống ngẫu nhiên mỗi khi bạn muốn sử dụng rand? Âm thanh ... hữu ích.
DLeh

1
Có thể thiết lập hạt giống ngẫu nhiên theo cách thủ công rất dễ dàng ... bắt đầu trình thông dịch với -S 1234tùy chọn hoặc thực hiện \S 1234từ trình thông dịch
xiên

34

Perl

use strict;

my @people = qw/John Jeff Emma Steve Julie/;
my @index = int(rand() * 5);

print "Person @index is buying: $people[@index]\n";

In: Person X is buying: Jeff(trong đó X là từ 0-4)

Lạm dụng bối cảnh vô hướng một chút. @index = int(rand() * 5)đặt một số nguyên ngẫu nhiên từ 0 - 4 ở vị trí 0 của @indexdanh sách. Khi in mảng, nó in đúng số nguyên ngẫu nhiên trong @index, nhưng khi sử dụng làm chỉ số mảng trong $people[@index], @index sử dụng ngữ cảnh vô hướng, tạo cho nó giá trị của kích thước danh sách, nghĩa là 1.

Thật thú vị, @people[@index]làm cho nó chỉ mục đúng.

Điều thú vị @people[@index]là một lát băm trong Perl, do đó @indexđược đánh giá trong ngữ cảnh danh sách; trong trường hợp này, đó là một danh sách mục duy nhất và đó là lý do tại sao nó hoạt động chính xác


Vậy trong thuật ngữ C (++), có một sự chuyển đổi ngầm định từ danh sách sang vô hướng xảy ra bởi vì khi lập chỉ mục, một vô hướng được mong đợi?
iFreilicht

@iFreilicht Đúng. Trong Perl, các biểu thức có thể được đánh giá dưới dạng danh sách hoặc dưới dạng vô hướng, tùy thuộc vào nơi chúng xuất hiện. Kết quả là, cùng một biểu thức có thể có nghĩa là những thứ khác nhau, tùy thuộc vào ngữ cảnh. Một biến danh sách (nghĩa là một biến có @tiền tố), trong "bối cảnh danh sách", được hiểu là tất cả các phần tử của nó, nhưng trong "bối cảnh vô hướng", là một vô hướng bằng tổng số phần tử trong danh sách. Do đó, bên trong chuỗi, biến danh sách có ngữ cảnh danh sách và được nội suy, và chúng ta nhận được Person X is buying. Nhưng là một chỉ số mảng, nó có bối cảnh vô hướng và được hiểu là 1.
Allen G

3
Vấn đề với điều này là khi một lập trình viên Perl nhìn thấy my @index = ..., anh ta lập tức tự hỏi "WTF?!".
derobert

@derobert, tại sao bạn lại thắc mắc? Bạn thấy mã như vậy khá thường xuyên ... my @letters = 'a' .. 'z'; my @squares = map $_**2, 1..20; my @sorted = sort { lc $a cmp lc $b } @words;vv
Matthias

@Matthias vì dòng này là để chọn và lưu trữ một giá trị duy nhất và thay vì vô hướng, nó được lưu trữ trong một mảng.
derobert

23

Bản thảo

// Randomly pick a person on only one line!
var people = [('John', 'Jeff', 'Emma', 'Steve', 'Julie')];

console.log(people[new Date() % people.length | 0]);

luôn luôn chọn Julie.

Nó có dấu ngoặc trong dấu ngoặc vuông và toán tử dấu phẩy trả về giá trị của toán hạng bên phải của nó.
Nó cũng rất dễ bỏ lỡ. Tôi đã bỏ lỡ nó trước đây trong mã thực .


Điều này thật thú vị. Cuối cùng, một sử dụng cho điều hành khủng khiếp, khủng khiếp đó.
Keen

5
Dấu phẩy trong bối cảnh đó về mặt kỹ thuật là một toán tử, chứ không phải là dấu phân cách. ecma-i Intl.org/ecma-262/5.1/#sec-11,14 Và thật kinh khủng. Trừ khi bạn muốn mã của bạn khó đọc. Như bạn làm ở đây. Vì vậy, danh tiếng.
Keen

2
@Cory Có, tôi đồng ý - mặc dù tôi sử dụng nó cho Code Golf với các biểu thức chức năng (ví dụ (a,b)=>(a=b[0],b)). Tôi đã làm rõ câu trả lời của mình.
Bàn chải đánh răng

21

C #

using System;

namespace LetsTroll {
    class Program {
        static void Main() {
            var names = new string[]{ "John", "Jeff", "Emma", "Steve", "Julie" };
            var random = new Random(5).NextDouble();
            var id = (int)Math.Floor(random);
            Console.WriteLine(names[id]);
        }
    }
}

Bí quyết là, phương thức new Random().NextDouble()trả về gấp đôi từ 0 đến 1. Bằng cách áp dụng Math.Floor()giá trị này, nó sẽ luôn là 0.


24
Nó không chịu được cái nhìn nhanh của tôi. ;)
Martin Ender

1
@TimS. như thế à : P
Knerd

2
+1, Tốt hơn nhiều - Tôi biết những gì bạn thực sự đang làm, nhưng nó có thể đánh lừa một người không quá quen thuộc với API.
Tim S.

1
Tôi không biết về điều này. Nếu bạn định chỉ định một hạt giống, tại sao không sử dụng cách thức thích hợp để nhận một int "ngẫu nhiên":var random = new Random(5); var id = random.NextInt(5);
clcto

2
@clcto Theo tôi, bao gồm hai lần có nhiều khả năng khiến ai đó thực hiện gấp đôi, hỏi tại sao và xem vấn đề. Bao gồm nó một lần, và sau đó bao gồm cả mã không cần thiết sau đó, sẽ mang lại một chút chuyển hướng / ngầm. Tiền thưởng: nếu ai đó sửa một trong các lỗi, một lỗi khác tồn tại.
Tim S.

18

C #

var names = new string[] {"John", "Jeff", "Emma", "Steve", "Julie"};
var guidBasedSeed = BitConverter.ToInt32(new Guid().ToByteArray(), 0);
var prng = new Random(guidBasedSeed);
var rn = (int)prng.Next(0, names.Length);
Console.WriteLine(names[rn]);

Dấu:

Tạo hạt giống từ GUID. Các hướng dẫn có cơ hội va chạm 4 × 10−10. Siêu ngẫu nhiên.

Câu trả lời:

Ít nhất là khi bạn sử dụng Guid.NewGuid(), rất tiếc! (Cách lén lút làm hạt giống luôn 0). Cũng vô nghĩa (int) cho định hướng sai.


Một cách khác mà tôi có thể làm là làm cho nó bị AddRangerối Concatkhi thêm tên vào a List<string>. Tôi đã có một Hashset với IEqualityComparer lén lút, nhưng nó sẽ quá bất thường. Trong tín dụng của tôi không có nhiều câu trả lời dựa trên hạt giống (nếu có) khi tôi đăng bài này.
Nathan Cooper

Tôi đoán bạn cũng có ý tưởng giống như tôi, nhưng bạn đã nhanh hơn một chút và làm cho nó khó nhìn hơn một chút. +1!
tsavinho

7
Tạo hạt giống cho trình tạo số ngẫu nhiên là một mẹo rõ ràng, nhưng bạn đã ẩn nó một cách tuyệt vời ở đây. Công việc đáng yêu.
TRiG

18

bash / coreutils

Điều này được lấy gần như nguyên văn từ một kịch bản tôi đã viết cho một mục đích tương tự.

#!/bin/bash
# Sort names in random order and print the first
printf '%s\n' John Jeff Emma Steve Julie | sort -r | head -1

Thậm chí quên sử dụng chữ hoa chữ R là một lỗi tôi thỉnh thoảng mắc phải trong các kịch bản đời thực.


3
bạn có thể đưa ra một lời giải thích tốt hơn? Bài viết hiện tại của bạn thực sự ngắn và không hữu ích với người không thực sự quen thuộc với bash.
iFreilicht

6
-rchỉ định sắp xếp ngược (từ điển), vì vậy Steve sẽ luôn được chọn. Nó có thể được coi là một lỗi đánh máy vô tội -Rcho loại ngẫu nhiên
Max

3
Đó là một lời nhắc tốt không nên tin vào các bình luận, nhưng hãy đọc kỹ mã!
TecBrat

16

Hồng ngọc

names = ["John", "Jeff", "Emma", "Steve", "Julie"]

puts names.sort{|x| rand()}.first

Điều này sẽ hoạt động chính xác với sort_by, nhưng sortmong đợi một chức năng so sánh hoạt động như thế nào <=>. Kết quả của rand () sẽ luôn dương, do đó, nó sẽ luôn tạo ra kết quả tương đương với điều kiện sortthuật toán triển khai Ruby của bạn mang tính quyết định. Ruby 1.9.3 của tôi luôn xuất ra Julie.


12

Hồng ngọc

names = ["John", "Jeff", "Emma", "Steve", "Julie"]

puts names[rand() % 5]

rand() không có đối số tạo ra một số float ngẫu nhiên trong khoảng từ 0 đến 1. Vì vậy, modulo 5 không làm gì cả và khi cắt thành một mảng với một đối số float, Ruby chỉ làm tròn nó xuống, vì vậy điều này luôn trả về John.


11

Perl

ba srands sẽ làm cho nó gấp ba lần ngẫu nhiên!

#!perl
use feature 'say';

sub random_person {
    my ($aref_people) = @_;
    srand; srand; srand;
    return $aref_people->[$RANDOM % scalar @$aref_people];
}

my @people = qw/John Jeff Emma Steve Julie/;
my $person = random_person(\@people);

say "$person makes next round of drinks!";

giải trình

không có $ RANDOM trong perl, đó là một biến không xác định. mã sẽ luôn trả về phần tử đầu tiên từ danh sách - đồ uống trên John :)

biên tập:

Sau khi duyệt mã, một trong năm người đã quyết định sửa lỗi rõ ràng, tạo ra chương trình sau:

#!perl
use feature 'say';

sub random_person {
    my ($aref_people) = @_;
    return $aref_people->[rand $#$aref_people];
}

my @people = qw/John Jeff Emma Steve Julie/;
my $person = random_person(\@people);

say "$person buys next round of drinks!";

bạn có thể nói ai đã làm nó chỉ bằng cách nhìn vào mã?

giải trình:

trong Perl, $#arraytrả về chỉ mục của phần tử cuối cùng; vì các mảng là không dựa trên, nên được tham chiếu đến một mảng có năm phần tử, $#$aref_peoplesẽ được 4.
randtrả về một số ngẫu nhiên lớn hơn hoặc bằng 0 và nhỏ hơn tham số của nó, vì vậy nó sẽ không bao giờ quay trở lại 4, điều đó có nghĩa là Julie sẽ không bao giờ mua đồ uống :)


1
$RANDOMlà một tính năng thực sự trong bash, ksh và zsh (nhưng không phải trong perl).
hạt nhân

10

Con trăn

Mọi người đều biết rằng bạn không thể tin tưởng vào sự ngẫu nhiên trong một không gian mẫu nhỏ như vậy; để làm cho nó thực sự ngẫu nhiên, tôi đã từ bỏ phương pháp lỗi thời để chọn tên từ danh sách, và thay vào đó chương trình của tôi sẽ đánh vần một tên hoàn toàn ngẫu nhiên. Vì hầu hết các tên trong văn phòng có 4 chữ cái, chúng tôi sẽ giải quyết cho điều đó.

import random

def CHR (n):
    # Just easily convert a number between 0 and 25 into a corresponding letter
    return chr(n+ord('A'))

# Seed the RNG with a large prime number. And multiply it by 2 for good measure.
random.seed (86117*2)

# Now, let's see what COMPLETELY RANDOM name will be spelled out!
totallyRandomName = ''
for i in range(4) :
    totallyRandomName += CHR(int(random.random()*26))

print (totallyRandomName)

Đương nhiên, tôi đã làm một số công việc chuẩn bị để đảm bảo tôi chọn đúng hạt giống.


15
Việc tạo số ngẫu nhiên tạo ra với một hằng số là quá rõ ràng ..
Brendan Long

@BrendanLong Nó chắc chắn sẽ làm tăng lông mày. Mọi người sẽ muốn kiểm tra nó để đảm bảo ngẫu nhiên. Và khi không, đoán xem ai mua đồ uống.
JFA

10

C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
char *name[]={"John", "Jeff", "Emma", "Steeve", "Julie"};

int i;
int n=rand()%10000;
int r=3;

for (i=0; i<10000+n; i++) // random number of iteration
    {
    r=(r*r)%10000; // my own PRNG (square and mod)
    }

printf("%s", name[r%5] );
}

Xin lỗi, Jeff!

Sau vài lần lặp r == 1 mod 5, vì toán học. Đạo đức: không viết PRNG của riêng bạn nếu bạn không giỏi toán. :)


10

C ++ x11

#include <vector>
#include <iostream>

int main () {
  std::srand(time(NULL));
  std::vector<std::string> choice{("jen","moss","roy")};
  std::cout << choice[rand()%choice.size()] << std::endl;
}

Kích thước của vectơ thực sự là 1 do dấu ngoặc đơn được sử dụng trong danh sách khởi tạo. Toán tử dấu phẩy sẽ loại bỏ tất cả các tên và trả lại tên cuối cùng, do đó người mua luôn là Roy.


10

Scala

Tôi biết người dùng của tôi sẽ nghi ngờ, vì vậy tôi đã đưa ra một bằng chứng cho thấy sự ngẫu nhiên của tôi là thực sự công bằng!

object DrinkChooser {

  def main(args: Array[String]): Unit = {
    proveRandomness()
    val names = List("John","Jeff","Emma","Steve","Julie")
    val buyer = names(randomChoice(names.size))
    println(s"$buyer will buy the drinks this time!")
  }

  def proveRandomness(): Unit = {
    val trials = 10000
    val n = 4
    val choices = for (_ <- 1 to 10000) yield randomChoice(n)
    (choices groupBy(identity)).toList.sortBy(_._1) foreach { case (a, x) =>
      println(a + " chosen " + (x.size * 100.0 / trials) + "%")
    }
  }

  def randomChoice(n: Int): Int = {
    var x = 1
    for (i <- 1 to 1000) { // don't trust random, add in more randomness!
      x = (x * randomInt(1, n)) % (n + 1)
    }
    x
  }

  // random int between min and max inclusive
  def randomInt(min: Int, max: Int) = {
    new scala.util.Random().nextInt(max - min + 1) + min
  }

}

Một ví dụ chạy:

1 chosen 25.31%
2 chosen 24.46%
3 chosen 24.83%
4 chosen 25.4%
John will buy the drinks this time!

Trừ khi người khác cực kỳ may mắn, John sẽ luôn mua đồ uống.

"Bằng chứng" về tính ngẫu nhiên phụ thuộc vào thực tế rand(1, 4) * rand(1, 4) % 5vẫn được phân bổ đều giữa 1 và 4, bao gồm. Nhưng rand(1, 5) * rand(1, 5) % 6là thoái hóa. Có khả năng bạn nhận được 0, sau đó sẽ đưa ra kết quả cuối cùng 0 bất kể phần còn lại của "tính ngẫu nhiên".



9

JavaScript

Lần thử thứ hai, cái này khó hơn một chút:

var getRandomEntry = function(args){
    return args[Math.floor(Math.random() * arguments.length)]; 
}

alert(getRandomEntry(["peter","julie","samantha","eddie","mark"]));

Các argumentsbiến có thể truy cập tại địa phương cho các chức năng và là một mảng của tất cả các đối số được truyền vào hàm. Bằng cách sử dụng cách đặt tên đơn giản và chuyển một mảng vào chính hàm, bạn có thể giả mạo rằng chúng ta không lấy chiều dài của mảng, nhưng thực tế là độ dài của danh sách đối số (là 1). Điều này thậm chí có thể được thực hiện tốt hơn bằng cách sử dụng ký tự đặc biệt hoặc một loại phông chữ.


Đây không phải là khó nhất để phát hiện ra. Bất cứ ai đã xây dựng một hàm tùy ý Ntrong JavaScript đều biết về argumentsbiến này.
Conor O'Brien

8

C ++

Để công bằng, chúng ta nên chạy nhiều, nhiều thử nghiệm và chọn bất kỳ ai được chọn thường xuyên nhất.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <map>

static const char *names[] = { "John", "Jeff", "Emma", "Steve", "Julie" };

int main() {
    srand(time(NULL));
    std::map<int, int> counts;

    // run 2^31 trials to ensure we eliminate any biases in rand()
    for (int i = 0; i < (1<<31); i++) {
        counts[rand() % (sizeof(names)/sizeof(*names))]++;
    }

    // pick the winner by whomever has the most random votes
    int winner = 0;
    for (std::map<int, int>::const_iterator iter = counts.begin(); iter != counts.end(); ++iter) {
        if (iter->second > counts[winner]) {
            winner = iter->first;
        }
    }

    printf("%s\n", names[winner % (sizeof(names)/sizeof(*names))]);
}

Giá trị của 1<<31cái gì? Xin lỗi, John.


Câu trả lời cho câu hỏi spoiler của bạn là UB. Tôi không quyết định nếu điều đó làm tốt hơn hay tồi tệ hơn.
nwp

@nwp Chà, chắc chắn, nhưng nó giữ bất cứ nơi nào int là phần bù 32 bit 2, dường như là trường hợp ngay cả trên 64 bit (với gcc). Tôi chưa thử nghiệm trên Clang.
lông mịn

Không, nó không giữ bất cứ nơi nào mà int là 32 - nhưng bổ sung 2. Giá trị của 1 << 31 là không xác định. Mặc dù vậy, bạn thật may mắn, hành vi không xác định làm cho trình biên dịch chọn bất cứ thứ gì nó cảm thấy và vì nó được tạo ra để tăng tốc nên nó sẽ quyết định không làm gì cả, điều đó xảy ra là điều bạn muốn.
nwp

@nwp 1<<31 == 0x80000000không có vấn đề gì, theo định nghĩa của <<, và trên phần bù 32-bit 2, đó là INT_MIN. Bạn có thể nghĩ về 1<<32cái nào có thể hoặc không == 0? (Bởi vì trên x86, 1<<32thường được ước tính là 1 ...)
fluffy

@nwp Nó thực sự được xác định thực hiện. Bây giờ nếu chúng ta đang nói về C, thì nó sẽ không được xác định.
Stuart Olsen

7

T-SQL (2008+)

SELECT TOP 1 name
FROM
 (VALUES('John'),('Jeff'),('Emma'),('Steve'),('Julie')) tbl(name)
ORDER BY RAND()

Giải trình:

Trong MS SQL Server, RAND()chỉ đánh giá một lần cho mỗi lần thực hiện. Mỗi tên luôn được gán cùng một số, để lại thứ tự ban đầu. John là đầu tiên. Sucks cho John.

Đề xuất cải tiến:

T-SQL có thể tạo ra chất lượng khá, số ngẫu nhiên trên mỗi hàng với RAND(CHECKSUM(NEWID())).


Tôi nghĩ ĐẶT HÀNG THEO NEWID () sẽ đủ (không cần KIỂM TRA)
Jacob

7

Lua

buyer={'John', 'Jeff', 'Emma', 'Steve', 'Julie'}
   -- use clock to set random seed
math.randomseed(os.clock())
   -- pick a random number between 1 and 5
i=math.random(5)
io.write("Today's buyer is ",buyer[i],".\n")

os.clock()là cho mục đích thời gian, os.time()là những gì nên được sử dụng math.randomseedcho RNG tốt. Đáng buồn thay, Julie luôn mua (ít nhất là trên máy tính của tôi).


math.random()không có đối số cũng trả về một số trong phạm vi [0,1). -1 vì không bắt được điều đó.
mniip

@mniip: Thật sự cũng xứng đáng! Tôi đã sửa nó rồi.
Kyle Kanos

6

Thành ngữ C ++ 11

Khi có đồ uống, điều đặc biệt quan trọng là phải cập nhật các tiêu chuẩn và phong cách mã hóa mới nhất; đây là một ví dụ tuyệt vời về công cụ chọn tên C ++ 11 hiệu quả cao và tuân thủ thành ngữ.

Nó được gieo từ đồng hồ hệ thống và xuất ra hạt giống cùng với tên để xác minh mỗi lần.

#include <vector>
#include <chrono>
#include <random>
#include <iostream>

auto main()->int {
  std::vector<std::string> names;           // storage for the names
  names.reserve(5);                         // always reserve ahead, for top performance
  names.emplace_back("John");               // emplace instead of push to avoid copies
  names.emplace_back("Jeff");
  names.emplace_back("Emma");
  names.emplace_back("Steve");
  names.emplace_back("Julie");

  std::mt19937_64 engine;                   // make sure we use a high quality RNG engine
  auto seed((engine, std::chrono::system_clock::now().time_since_epoch().count()));  // seed from clock
  std::uniform_int_distribution<unsigned> dist(0, names.size() - 1);     // distribute linearly
  auto number(dist(engine));                // pick a number corresponding to a name
  std::string name(names.at(number));       // look up the name by number
  std::cout << "Seed: " << seed << ", name: " << name << std::endl;  // output the name & seed
  return EXIT_SUCCESS;                      // don't forget to exit politely
}

Hãy thử trực tiếp: http://ideone.com/KOet5H

Ok vì vậy đây thực sự là mã khá tốt; có rất nhiều cá trích đỏ để khiến bạn nhìn quá kỹ vào mã để nhận thấy điều hiển nhiên - rằng RNG không bao giờ thực sự được tạo hạt :) Trong trường hợp seednày chỉ là một số nguyên, và trong khi nó có vẻ như engineđược truyền dưới dạng tham số cho một chức năng gieo hạt, nó thực sự chỉ bị bỏ qua. Biến hạt giống thực sự được đặt từ đồng hồ, do đó, nó có thể là đầu ra ở cuối cùng với tên để thêm sự xúc phạm đến thương tích, nhưng vẫn sẽ luôn là Steve mua đồ uống.


1
Nó giết tôi rằng nó không sử dụng danh sách khởi tạo cho các tên. Ít nhất, bạn chắc chắn đã thành công trong việc cung cấp mã mà chỉ cảm thấy quá sức. Tôi không thể biết liệu đó là do "tuân thủ" hay tất cả các nhận xét về tiếng ồn: P
vmrob

6

JavaScript

console.log(["Jeff", "Emma", "Steve", "Julie"][Math.floor(Math.random(5))]);

Chà, xin lỗi, Math.randomkhông lấy tham số và sẽ luôn trả về một số từ [0, 1). Tuy nhiên, đây là một chức năng dao động hạnh phúc và không phàn nàn về các đối số!


5

Con trăn

names=["John", "Jeff", "Emma", "Steve", "Julie"]
import random # Import random module
random.seed(str(random)) # Choose strictly random seed
print(random.choice(names)) # Print random choice

str (ngẫu nhiên) cho một chuỗi không đổi; không phải là một giá trị ngẫu nhiên


6
Một lưu ý không liên quan: nếu bạn đang sử dụng Python 3.2 trở lên, đối số thứ hai random.seed()phải là 2(mặc định). Nếu bạn vượt qua version=1, hash()chuỗi sẽ được sử dụng làm hạt giống thay vì toàn bộ chuỗi và vì Python ngẫu nhiên các giá trị băm của chuỗi hạt bắt đầu từ 3.2, bạn sẽ nhận được một tên thực sự ngẫu nhiên.
Blacklight Shining

5

Perl

Emma không nên quên ví của mình! Chạy theo strictwarnings.

use strict;
use warnings;

# Use a hash to store names since they're more extendible

my %people;
$people{$_}++ for qw/John Jeff Emma Steve Julie/;

print +(@_=%people)[rand@_];  # 'cos (keys %people)[rand( keys %people )]
                              # is just too long-winded.

Giải thích tại đây .


Perl 5.18 đã thay đổi điều này một chút, bằng cách giới thiệu ngẫu nhiên khóa băm (để tránh các cuộc tấn công phức tạp va chạm băm).
Konrad Borowski

4

JavaScript

function getDrinksBuyer(){ 
    var people = ["Jeff", "Emma", "Steve", "Julie"];
    var rand = Math.random(0,4)|0;
    return people[rand];
}

Các |0kết quả trong 0 tất cả các thời gian nhưng có vẻ như nó đang làm một số làm tròn khác.


Tôi thích nó. Mặc dù tôi sẽ làm parseInt(Math.random(0, 4))và có thể thêm nhận xét như - Math.randomtrả lại gấp đôi, vì vậy hãy chuyển đổi nó thành số nguyên trước
Claudiu

5
Bí quyết thực sự là Math.randomkhông quan tâm đến các thông số ít ỏi của chúng tôi. Nó chọn số theo cách riêng của nó. đó |0là làm tròn chính xác kết quả không mong muốn, và do đó không phải là nguồn gốc của bất kỳ mánh khóe nào.
Keen

|0là rất rõ ràng đối với một số người (tất cả chúng ta rất có thể), nhưng tôi cá là có rất nhiều người không biết nó làm gì. Đó là nhóm tôi đang dựa vào lừa.
Matt

3
@Matt Ý tôi là |0, nếu bạn biết nó làm gì, có vẻ như nó đang làm tròn xuống, và nó đang làm tròn xuống, vì vậy nó không phải là một sự lừa dối. (Và nếu ai đó không biết |0phải làm gì , thì sẽ không sử dụng mã lừa đảo; bạn chỉ có thể nói với họ bất cứ điều gì bạn muốn họ tin.) Thay vào đó, hành vi bất ngờ trong câu trả lời của bạn dựa trên thực tế Math.random(0,4)giống hệt như chức năng Math.random(), bởi vì Math.randomkhông sử dụng tham số.
Keen

4

J

;(?.5) { 'John'; 'Jeff'; 'Emma'; 'Steve'; 'Julie'

Tội nghiệp Julie ... Chuyện phiếm: đây có thể là J sạch nhất tôi từng viết ...

Mã này thực sự chính xác, ngoại trừ một điều. ?.là đồng phục rng: ?.5sẽ luôn trả về 4. ?5sẽ đúng.

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.