JS สร้างบูลีนแบบสุ่ม


136

คำถามง่ายๆ แต่ฉันสนใจในความแตกต่างที่นี่

ฉันกำลังสร้างบูลีนแบบสุ่มโดยใช้วิธีการต่อไปนี้ที่ฉันคิดขึ้นเอง:

const rand = Boolean(Math.round(Math.random()));

เมื่อใดก็ตามที่random()ปรากฏขึ้นดูเหมือนว่าจะมีข้อผิดพลาดอยู่เสมอ - มันไม่ได้สุ่มอย่างแท้จริงมันถูกบุกรุกโดยบางสิ่งหรืออื่น ๆ ฯลฯ ดังนั้นฉันต้องการทราบ:

ก) วิธีการข้างต้นเป็นแนวทางปฏิบัติที่ดีที่สุดหรือไม่?

b) ฉันคิดมากเกินไปหรือเปล่า?

c) ฉันคิดอะไรไม่ออกหรือเปล่า?

d) มีวิธีที่ดีกว่า / เร็วกว่า / สง่างามที่ฉันไม่รู้หรือไม่?

(ค่อนข้างสนใจถ้า B และ C เป็นเอกสิทธิ์เฉพาะบุคคล)

ปรับปรุง

ถ้ามันสร้างความแตกต่างฉันใช้สิ่งนี้สำหรับการเคลื่อนไหวของตัวละคร AI


26
const rand = Math.random() < 0.5เทียบเท่าและง่ายกว่า
Hamms

3
คุณสามารถบรรลุได้เฉพาะการหลอกลวงเท่านั้นไม่ใช่การสุ่มอย่างแท้จริง
Oriol

ไม่มีอะไรสุ่มจริงๆเป้าหมายคือการเข้าใกล้การสุ่มให้มากที่สุด
Adam Buchanan Smith

และถ้าคุณมีโอกาส 50/50 math.randomควรมีมากมาย เพียงแค่ใช้มิลลิวินาทีสำหรับเมล็ดพันธุ์ของคุณ
Adam Buchanan Smith

ฉันคิดว่ามันค่อนข้างสุ่มเวลาเข้าชมเว็บไซต์: D ดังนั้นฉันจึงมีความคิดนี้ ...Boolean(+Date.now()%2)
Roko C. Buljan

คำตอบ:


341

ในทางเทคนิคโค้ดดูดี แต่ซับซ้อนเกินไปเล็กน้อย คุณสามารถเปรียบเทียบMath.random()การ0.5โดยตรงเป็นช่วงของMath.random()มี[0, 1)(ที่นี้หมายถึง 'ในช่วง 0-1 รวม 0 แต่ไม่ได้ 1') คุณสามารถแบ่งช่วงเข้าและ[0, 0.5)[0.5, 1)

var random_boolean = Math.random() >= 0.5;

// Example
console.log(Math.random() >= 0.1) // %90 probability of get "true"
console.log(Math.random() >= 0.4) // %60 probability of get "true"
console.log(Math.random() >= 0.5) // %50 probability of get "true"
console.log(Math.random() >= 0.8) // %20 probability of get "true"
console.log(Math.random() >= 0.9) // %10 probability of get "true"


3
ฉันชอบวิธีแก้ปัญหานี้เพราะช่วยให้คุณปรับเปลี่ยนความน่าจะเป็นของจริง / เท็จ
Evanion

ถ้าคุณเปลี่ยนตัวเลข 0.5 เป็น 0.9 สิ่งนี้จะเพิ่มความน่าจะเป็นเท็จหรือไม่และอย่างไร
Agent Zebra

ถ้าคุณเปลี่ยนจาก 0.5 เป็น 0.9 จากนั้นความน่าจะเป็นมีแนวโน้มที่จะเปลี่ยนแปลง ฉันคิดว่าคุณสามารถลองใช้การวนซ้ำแบบสุ่มจำนวนมากเช่นการวนซ้ำ 10,000 ครั้ง
Kelvin

สำหรับ JavaScript สมัยใหม่คุณควรใช้letเช่นlet randomBool = Math.random() >= 0.5;
Chris Halcrow

ทำไมไม่ใช้แค่<แทน>=? Math.random() < 0.5เป็นเอกสิทธิ์ของ 0.5 สำหรับครึ่งต่ำและไม่รวม 1 สำหรับครึ่งสูง - ดังนั้นจึงยังมีโอกาส 50% แถมยังสั้นกว่าอีกด้วย และในความคิดของฉันMath.random() < 0.1คือใช้งานง่ายมากขึ้นในการอ่านเป็น "โอกาส 10% ของความจริง" Math.random() >= 0.9มากกว่า ฉันเดาว่ามันค่อนข้างจู้จี้จุกจิก คำตอบที่ดี
Aaron Plocharczyk


13

คุณสามารถใช้crypto.getRandomValuesในเบราว์เซอร์รุ่นใหม่เพื่อความปลอดภัยในการเข้ารหัสที่มากขึ้น

ตัวอย่าง:

var randomBool = (function() {
  var a = new Uint8Array(1);
  return function() {
    crypto.getRandomValues(a);
    return a[0] > 127;
  };
})();

var trues = 0;
var falses = 0;
for (var i = 0; i < 255; i++) {
  if (randomBool()) {
    trues++;
  }
  else {
    falses++;
  }
}
document.body.innerText = 'true: ' + trues + ', false: ' + falses;

โปรดทราบว่าcryptoวัตถุเป็น DOM API ดังนั้นจึงไม่สามารถใช้ได้ในโหนด แต่มี API ที่คล้ายกันสำหรับโหนด


4
Math.random()ไม่ได้รับการสุ่มอย่างฉาวโฉ่ในหลาย ๆ ด้านข้อเสนอแนะทางเลือกที่ดี
Charles Harris

3
ฉันจะเพิ่มการแก้ไขเล็กน้อยที่นี่ตามที่ฉันค้นพบหลังจาก 50,000,000 รันซึ่งสร้างขึ้นโดยเฉลี่ย 0.78% หรือมากกว่านั้นศูนย์: ส่งกลับ [0] <= 127; (ไม่รวม 127 อื่น ๆ )
Amund Midtskog

2
@AmundMidtskog ดีโทร. ฉันควรจะพิมพ์:a[0] > 127
Alexander O'Mara

1
โดยปกติแล้วคุณอาจต้องการสร้างกลุ่มตัวอย่างจำนวนมากกว่า 255 ตัวอย่าง แต่เพื่อลดสัญญาณรบกวนในข้อมูลเช่น 100,000 หรือหลายสิบล้านตามที่แนะนำในความคิดเห็นอื่น ๆ หาก คุณต้องการเห็นข้อผิดพลาดน้อยที่สุด 0.78%
caw

8
!Math.round(Math.random());

­­­­­­­­­­­­­­


6
โปรดจัดรูปแบบให้เป็นประโยชน์มากขึ้น ( stackoverflow.com/editing-help ) และเพิ่มคำอธิบาย คำตอบที่ใช้รหัสเท่านั้นไม่ได้รับการชื่นชมมากนัก การเพิ่มคำอธิบายจะช่วยต่อสู้กับความเข้าใจผิดที่ว่า StackOverflow เป็นบริการเขียนโค้ดฟรี
Yunnosch

5

ประทับใจมากกับคำตอบของ Kelvinฉันอยากจะแนะนำวิธีแก้ปัญหาที่ค่อนข้างคล้ายกัน แต่ได้รับการปรับปรุงเล็กน้อย

var randomBoolean = Math.random() < 0.5;

วิธีนี้อ่านได้ชัดเจนกว่าเล็กน้อยเนื่องจากตัวเลขทางด้านขวามือของ<จะบอกคุณถึงความน่าจะเป็นที่จะได้รับtrueแทนที่จะได้รับfalseซึ่งเป็นเรื่องธรรมดาที่จะเข้าใจ นอกจากนี้ยัง<เป็นหนึ่งในสัญลักษณ์ที่สั้นกว่า>=;


1

วิธีแก้ปัญหาที่เร็วกว่าที่เป็นไปได้ ...

คุณยังสามารถพิจารณาแนวทางตัวดำเนินการ Bitwise ที่ฉันเพิ่งคิดMath.random() + .5 >> 0ได้ไม่แน่ใจว่าเร็วกว่าหรือไม่ แต่นี่คือการทดสอบประสิทธิภาพเพื่อทดสอบด้วยตัวคุณเอง

let randomBoolean = Math.random() + .5 >> 0;
const randomBoolean = chance => Math.random() + chance >> 0;

วิธีทั่วไปในการรับบูลีนแบบสุ่มMath.random() >= .5มาจากคำตอบของเคลวิน

let randomBoolean = Math.random() >= .5;       
const randomBoolean = chance => Math.random() >= chance;

เหตุผลเดียวที่ใช้Math.round(Math.random())แนวทางนี้คือความเรียบง่ายและความเกียจคร้าน


ฉันไม่แน่ใจว่าสิ่งนี้คุ้มค่าหรือไม่ แต่(.49999999999999997 >= .5) != (.49999999999999997+ .5 >> 0)
Aaron Plocharczyk เมื่อ

ใช่ แต่ทั้งสองวิธีไม่ถูกต้องในระดับนั้นดังนั้นฉันไม่คิดว่ามันสำคัญมาก (.49999999999999997 >=.5) == (.49999999999999991 +.5>>0)และนี่(.49999999999999998 >=.5) == (.49999999999999992 +.5>>0)เป็นทั้งความจริง นอกจากนี้ในเวอร์ชันบิตเรากำหนดโอกาสที่จะได้รับจริงในขณะที่ตัวอย่างเปรียบเทียบเรากำหนดโอกาสที่จะได้รับเท็จ ดังนั้น. 2 จะเท่ากับประมาณ 20% โอกาสที่จะเป็นจริงในระดับบิตหรือ 20% ของเท็จในวิธีการเปรียบเทียบ ..
LeonNikolai

0

แล้วอันนี้ละ?

return Math.round((Math.random() * 1) + 0) === 0;

1
OP ระบุว่าเขาใช้วิธีการที่คล้ายกันอยู่แล้วไม่จำเป็นต้องโพสต์สิ่งนี้
Jacob Gunther

-1

คำตอบของAlexander O'Mara

เพียงแค่เพิ่มข้อมูลโค้ดโหนด

const crypto = require('crypto');
const randomBool = (function () {
    let a = new Uint8Array(1);
    return function () {
        crypto.randomFillSync(a);
        return a[0] > 127;
    };
})();

let trues = 0;
let falses = 0;
for (let i = 0; i < 100; i++) {
    if (randomBool()) {
        trues++;
    }
    else {
        falses++;
    }
}

console.log('true: ' + trues + ', false: ' + falses);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.