उद्देश्य-सी में यादृच्छिक संख्या उत्पन्न करना


741

मैं मुख्य रूप से जावा प्रमुख हूं, और मुझे 0 से 74 के बीच छद्म यादृच्छिक संख्या उत्पन्न करने का एक तरीका चाहिए। जावा में मैं इसका उपयोग नहीं करूंगा:

Random.nextInt(74)

मैं बीज या सच्ची यादृच्छिकता के बारे में चर्चा में दिलचस्पी नहीं रखता, बस आप उद्देश्य-सी में एक ही कार्य को कैसे पूरा करते हैं। मैंने Google को परिहास किया है, और बस जानकारी के विभिन्न और परस्पर विरोधी बिट्स प्रतीत होते हैं।

जवाबों:


1025

आपको arc4random_uniform()फ़ंक्शन का उपयोग करना चाहिए । यह एक बेहतर एल्गोरिथ्म का उपयोग करता है rand। तुम भी एक बीज सेट करने की जरूरत नहीं है।

#include <stdlib.h>
// ...
// ...
int r = arc4random_uniform(74);

arc4randomआदमी पेज:

NAME
     arc4random, arc4random_stir, arc4random_addrandom -- arc4 random number generator

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <stdlib.h>

     u_int32_t
     arc4random(void);

     void
     arc4random_stir(void);

     void
     arc4random_addrandom(unsigned char *dat, int datlen);

DESCRIPTION
     The arc4random() function uses the key stream generator employed by the arc4 cipher, which uses 8*8 8
     bit S-Boxes.  The S-Boxes can be in about (2**1700) states.  The arc4random() function returns pseudo-
     random numbers in the range of 0 to (2**32)-1, and therefore has twice the range of rand(3) and
     random(3).

     The arc4random_stir() function reads data from /dev/urandom and uses it to permute the S-Boxes via
     arc4random_addrandom().

     There is no need to call arc4random_stir() before using arc4random(), since arc4random() automatically
     initializes itself.

EXAMPLES
     The following produces a drop-in replacement for the traditional rand() and random() functions using
     arc4random():

           #define foo4random() (arc4random() % ((unsigned)RAND_MAX + 1))

96
arc4random_uniform(x)नीचे वर्णित @yood द्वारा उपयोग करें । यह stdlib.h में भी है (OS X 10.7 और iOS 4.3 के बाद) और यादृच्छिक संख्याओं का अधिक समान वितरण देता है। उपयोगint r = arc4random_uniform(74);
लावास्लाइडर

4
एनबी: आर्क 4 आयामी से वितरण बहुत खराब हो सकता है, यदि आप एक खराब सीमा चुनने के लिए होते हैं। मुझे शक्तियों-दो की उम्मीद का एहसास नहीं था। +1 @ यूज़ के संस्करण के लिए - बड़ी संख्या के लिए एक ध्यान देने योग्य अंतर बनाया (उदाहरण के लिए 400 की सीमा)
एडम

क्या यह केवल ३२ बिट संख्या उत्पन्न करता है?
jjxtra

4
@codecowboy यह नहीं है। यह हमेशा सीमा में पूर्णांक देता है [0, (2 ^ 32) -1]। यह मोडुलो है जो आपके द्वारा निर्दिष्ट संख्या तक सीमा के ऊपरी-सीमा को सीमित करता है।
मोटासिम

1
क्या यह 0 और 73 के बीच एक यादृच्छिक संख्या नहीं देगा?
टॉम हावर्ड

424

arc4random_uniform(upper_bound)एक सीमा के भीतर एक यादृच्छिक संख्या उत्पन्न करने के लिए फ़ंक्शन का उपयोग करें । निम्नलिखित 0 और 73 के बीच एक संख्या उत्पन्न करेगा।

arc4random_uniform(74)

arc4random_uniform(upper_bound)मैन पेज में वर्णित मोडुलो पूर्वाग्रह से बचा जाता है :

arc4random_uniform () एक समान रूप से वितरित यादृच्छिक संख्या को ऊपरी_बाउंड से कम लौटाएगा। arc4random_uniform () के निर्माण की सिफारिश की जाती है जैसे `` arc4random ()% ऊपरी_बाउंड '' के रूप में यह " modulo पूर्वाग्रह " से बचा जाता है जब ऊपरी बाध्य दो की शक्ति नहीं होती है।


32
ध्यान दें कि arc4random_uniform () में iOS 4.3 की आवश्यकता है। यदि आप पुराने उपकरणों का समर्थन कर रहे हैं, तो आपको एक चेक जोड़ना चाहिए: #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_3 यदि यह चेक में विफल रहता है, तो दूसरे समाधान पर वापस जाएं।
रॉन

6
arc4random_uniform () के लिए 10.7 या बाद में भी आवश्यकता होती है। यह आपके ऐप को 10.6
टिबिडाबो

@ टिबिदाबो आपकी टिप्पणी बहुत गलत और भ्रामक है। मैं सिर्फ iOS4.3 पर arc4random_uniform () का उपयोग करके थक गया हूं और कोई समस्या नहीं है। इसके लिए 10.7 या बाद की आवश्यकता नहीं है
चौथा

1
@Fourth iOS 10.7 जैसी कोई चीज नहीं है, यह macOS 10.7 है। यह 5 साल से अधिक हो गया है क्योंकि मैंने टिप्पणी लिखी थी कि यह अधिकतम iOS 5 वापस था।
टिबिडाबो

63

सी के रूप में ही, आप क्या करेंगे

#include <time.h>
#include <stdlib.h>
...
srand(time(NULL));
int r = rand() % 74;

(आप 0 सहित मतलब है, लेकिन 74 को छोड़कर, जो आपके जावा उदाहरण करता है)

संपादित करें: स्थानापन्न random()या के arc4random()लिए स्वतंत्र महसूस करें rand()(जो कि, जैसा कि दूसरों ने बताया है, काफी बेकार है)।


43
-1। आपको यादृच्छिक संख्या जनरेटर को बीजने की आवश्यकता है या आपको प्रत्येक निष्पादन पर संख्याओं का समान पैटर्न मिलेगा।
एलेक्स रेनॉल्ड्स

मैं शून्य से अलग संख्या से कैसे शुरू करना चाहता हूं?
अमुक

2
@amok: तुम बस संख्या है कि आप परिणाम से शुरू करना चाहते हैं जोड़ सकते हैं
फ्लोरिन

2
मैं नंबर 9 प्राप्त करता रहता हूं। सुंदर यादृच्छिक रूप से मैं कहूंगा; डी
अलेक्सयॉर्क

मैं बस यादृच्छिक परीक्षण (), और यह रैंड के रूप में एक ही समस्या से पता चला ()
LolaRun

50

मैंने सोचा कि मैं कई परियोजनाओं में एक विधि जोड़ सकता हूं।

- (NSInteger)randomValueBetween:(NSInteger)min and:(NSInteger)max {
    return (NSInteger)(min + arc4random_uniform(max - min + 1));
}

अगर मैं इसे कई फाइलों में इस्तेमाल करता हूं, तो आमतौर पर मैक्रो घोषित करता हूं

#define RAND_FROM_TO(min, max) (min + arc4random_uniform(max - min + 1))

उदाहरण के लिए

NSInteger myInteger = RAND_FROM_TO(0, 74) // 0, 1, 2,..., 73, 74

नोट: केवल iOS 4.3 / OS X v10.7 (शेर) और बाद के लिए


जुड़वाँ-पूरक का उपयोग करके द्विआधारी पूर्णांक के साथ तय होने पर भी, सराहनीय है। जैसे कि अधिकतम - min + 1 ठीक उसी प्रकार है जैसे कि अधिकतम + 1 - min साथ ही 1 + max - min।
माइकल मॉरिस

44

यह आपको 0 और 47 के बीच एक फ्लोटिंग पॉइंट नंबर देगा

float low_bound = 0;      
float high_bound = 47;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

या यूँ ही

float rndValue = (((float)arc4random()/0x100000000)*47);

निचले और ऊपरी दोनों बाउंड नकारात्मक भी हो सकते हैं । नीचे दिया गया उदाहरण कोड आपको -35.76 और +12.09 के बीच एक यादृच्छिक संख्या देता है

float low_bound = -35.76;      
float high_bound = 12.09;
float rndValue = (((float)arc4random()/0x100000000)*(high_bound-low_bound)+low_bound);

परिणाम को एक राउंडर पूर्णांक मान में बदलें :

int intRndValue = (int)(rndValue + 0.5);

ये गलत है। आप फ्लोट का उपयोग क्यों कर रहे हैं, और डबल नहीं? और यदि आपके फ्लोटिंग पॉइंट वैल्यू 0 से 47 तक हैं, तो (int) (rndValue + 0.5) केवल वैल्यू को 0.0 से 0.5 से 0 में बदल देगा, लेकिन 0.5 से 1.5 तक के वैल्यू को 1 आदि में बदल दिया जाएगा। 47 सभी अन्य संख्याओं के समान ही आधी आएगी।
gnasher729

@ gnasher729 क्षमा करें, मुझे आपकी बात दिखाई नहीं दे रही है। जाहिर है अगर आपको दोहरी सटीकता की आवश्यकता है तो आप "फ्लोट" को "डबल" से बदल सकते हैं
टिबिडाबो

मुझे नहीं लगता कि यह एक बड़ी बात है। यदि आपको पूर्णांक की आवश्यकता है, तो केवल आप से अधिक मूल्यों का उपयोग कर सकते हैं arc4random () / 0x100000000) * (high_bound-low_bound) + low_bound फ़्लोट / डबल रूपांतरण को हटाकर।
टिबिडाबो

जब आप पूर्णांक को फ़्लोटिंग पॉइंट में परिवर्तित करते हैं तो आप पूर्वाग्रह प्राप्त करते हैं। drand48फ़्लोटिंग पॉइंट्स के बजाय उपयोग करें ।
फ्रैंकलिन यू

37

रैंड (3) के लिए मैनुअल पेज के अनुसार, कार्यों के रैंड परिवार को यादृच्छिक (3) द्वारा बाधित किया गया है। यह इस तथ्य के कारण है कि रैंड के निचले 12 बिट्स () चक्रीय पैटर्न से गुजरते हैं। एक यादृच्छिक संख्या प्राप्त करने के लिए, बस अहस्ताक्षरित बीज के साथ srandom () कॉल करके जनरेटर को बीज दें, और फिर यादृच्छिक () कॉल करें। तो, ऊपर दिए गए कोड के बराबर होगा

#import <stdlib.h>
#import <time.h>

srandom(time(NULL));
random() % 74;

जब तक आप अपना बीज नहीं बदलना चाहते, आपको केवल अपने कार्यक्रम में एक बार srandom () को कॉल करने की आवश्यकता होगी। यद्यपि आपने कहा था कि आप वास्तव में यादृच्छिक मूल्यों की चर्चा नहीं करना चाहते थे, रैंड () एक बहुत बुरा यादृच्छिक संख्या जनरेटर है, और यादृच्छिक () अभी भी मोडुलो पूर्वाग्रह से ग्रस्त है, क्योंकि यह 0 और RAND_MAX के बीच एक संख्या उत्पन्न करेगा। तो, उदाहरण के लिए अगर RAND_MAX 3 है, और आप 0 और 2 के बीच एक यादृच्छिक संख्या चाहते हैं, तो आप एक 1 या 2 की तुलना में 0 प्राप्त करने की संभावना से दोगुना हैं।


7
आप srandomdev () को srandom () को समय पास करने के बजाय कह सकते हैं; यह उतना ही आसान और गणितीय रूप से बेहतर है।
बेंज़ैडो

31

उपयोग करने के लिए बेहतर है arc4random_uniform। हालाँकि, यह iOS 4.3 से नीचे उपलब्ध नहीं है। सौभाग्य से iOS इस प्रतीक को रनटाइम पर बांध देगा, संकलन समय पर नहीं (इसलिए यदि यह उपलब्ध है तो यह जांचने के लिए #if प्रीप्रोसेसर निर्देश का उपयोग न करें)।

यह निर्धारित करने का सबसे अच्छा तरीका है कि क्या arc4random_uniformउपलब्ध है, ऐसा कुछ करना है:

#include <stdlib.h>

int r = 0;
if (arc4random_uniform != NULL)
    r = arc4random_uniform (74);
else
    r = (arc4random() % 74);

9
यह प्रश्न ऑब्जेक्टिव-सी के बारे में है जो देर से बाध्यकारी का उपयोग करता है। C के विपरीत जो संकलित / लिंक समय पर बांधता है, Objective-C रनटाइम पर प्रतीकों को बांधता है, और यह कैंट बाइंड के प्रतीकों को NULL पर सेट करता है। जब आप सही हैं कि यह मान्य सी नहीं है, तो यह निश्चित रूप से वैध उद्देश्य-सी है। मैं अपने iPhone ऐप में इस सटीक कोड का उपयोग करता हूं। [पीएस कृपया आप अपने डाउनवोट को सही कर सकते हैं]।
AW101

जबकि ऑब्जेक्टिव-सी, objc मेथड के लिए लेट बाइंडिंग का उपयोग करता है, C फ़ंक्शन के लिए यह ऐसा नहीं है। यदि फ़ंक्शन रन-टाइम पर मौजूद नहीं है, तो यह कोड निश्चित रूप से क्रैश हो जाएगा।
रिचर्ड जे। रॉस III

8
Apple के अनुसार "... लिंक करने वाला NULL के लिए अनुपलब्ध फ़ंक्शन का पता सेट करता है ...", 3.2 देखें: डेवलपर . apple.com/library/mac/#documentation/DeveloperTools/… । ठीक है, इसलिए इसे कमजोर रूप से जोड़ा जाना चाहिए, लेकिन यह दुर्घटना नहीं करता है।
AW101 22

1
यह जाँचना कि एक फ़ंक्शन का पता NULL है, एक विधि है जिसका उपयोग MacOS X और iOS दोनों पर C, C ++ और Objective-C दोनों के सभी संस्करणों में किया गया है।
gnasher729

14

मैंने अपना रैंडम नंबर यूटिलिटी क्लास सिर्फ इसलिए लिखा ताकि मेरे पास कुछ ऐसा हो, जो जावा में Math.random () जैसा कुछ और काम करे। इसके केवल दो कार्य हैं, और यह सभी C में बना है।

शीर्ष लेख फ़ाइल:

//Random.h
void initRandomSeed(long firstSeed);
float nextRandomFloat();

कार्यान्वयन फ़ाइल:

//Random.m
static unsigned long seed;

void initRandomSeed(long firstSeed)
{ 
    seed = firstSeed;
}

float nextRandomFloat()
{
    return (((seed= 1664525*seed + 1013904223)>>16) / (float)0x10000);
}

यह छद्म रैंडम उत्पन्न करने का एक सुंदर क्लासिक तरीका है। मेरे ऐप के प्रतिनिधि को मैं कॉल करता हूं:

#import "Random.h"

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    initRandomSeed( (long) [[NSDate date] timeIntervalSince1970] );
    //Do other initialization junk.
}

फिर बाद में मैं सिर्फ कहता हूं:

float myRandomNumber = nextRandomFloat() * 74;

ध्यान दें कि यह विधि 0.0f (सम्मिलित) और 1.0f (अनन्य) के बीच एक यादृच्छिक संख्या देता है।


3
1. यादृच्छिक पर बनाए गए यादृच्छिक संख्या फ़ंक्शन आमतौर पर बहुत यादृच्छिक नहीं होते हैं। 2. यह 64 बिट प्रोसेसर पर पूरी तरह से टूट गया है। 3. 1970 के बाद से सेकंड के रूप में यादृच्छिक बीज संख्या का अनुमान लगाने योग्य बनाता है।
gnasher729

7

कुछ शानदार, स्पष्ट उत्तर पहले से ही हैं, लेकिन सवाल 0 और 74 के बीच एक यादृच्छिक संख्या के लिए पूछता है।

arc4random_uniform(75)


4

IOS 9 और OS X 10.11 के रूप में, आप विभिन्न तरीकों से यादृच्छिक संख्या उत्पन्न करने के लिए नई GameplayKit कक्षाओं का उपयोग कर सकते हैं।

आपके पास चुनने के लिए चार स्रोत प्रकार हैं: एक सामान्य यादृच्छिक स्रोत (अनाम नाम, यह चुनने के लिए सिस्टम के नीचे), रैखिक बधाई, ARC4 और Mersenne ट्विस्टर। ये यादृच्छिक ints, फ़्लोट्स और बूल उत्पन्न कर सकते हैं।

सबसे सरल स्तर पर, आप सिस्टम के अंतर्निहित यादृच्छिक स्रोत से इस तरह एक यादृच्छिक संख्या उत्पन्न कर सकते हैं:

NSInteger rand = [[GKRandomSource sharedRandom] nextInt];

यह -2,147,483,648 और 2,147,483,647 के बीच एक संख्या उत्पन्न करता है। यदि आप 0 और एक ऊपरी बाउंड (अनन्य) के बीच एक संख्या चाहते हैं, तो आप इसका उपयोग करेंगे:

NSInteger rand6 = [[GKRandomSource sharedRandom] nextIntWithUpperBound:6];

गेमप्लेकिट में पासे के साथ काम करने के लिए कुछ सुविधा निर्माणकर्ता हैं। उदाहरण के लिए, आप इस तरह से छह-पक्षीय मर सकते हैं:

GKRandomDistribution *d6 = [GKRandomDistribution d6];
[d6 nextInt];

साथ ही आप चीजों का उपयोग करके यादृच्छिक वितरण को आकार दे सकते हैं GKShuffledDistribution


मेरसेन गेम देव जैसी चीजों के लिए सबसे तेज और सर्वश्रेष्ठ है जहां उत्पन्न यादृच्छिक संख्या की गुणवत्ता आमतौर पर बहुत महत्वपूर्ण नहीं है।
रॉबर्ट वासमैन

3

0 से 99 के बीच यादृच्छिक संख्या उत्पन्न करें:

int x = arc4random()%100;

500 और 1000 के बीच यादृच्छिक संख्या उत्पन्न करें:

int x = (arc4random()%501) + 500;

1

// निम्नलिखित उदाहरण 0 और 73 के बीच एक संख्या उत्पन्न करने वाला है।

int value;
value = (arc4random() % 74);
NSLog(@"random number: %i ", value);

//In order to generate 1 to 73, do the following:
int value1;
value1 = (arc4random() % 73) + 1;
NSLog(@"random number step 2: %i ", value1);

आउटपुट:

  • यादृच्छिक संख्या: 72

  • यादृच्छिक संख्या चरण 2: 52


1

खेल के लिए देव रैंडम उत्पन्न करने के लिए यादृच्छिक () का उपयोग करें। शायद कम से कम 5x की तुलना में अधिक तेजी से आर्क 4 आयामी () का उपयोग कर रहा है। मोडुलो पूर्वाग्रह कोई मुद्दा नहीं है, विशेष रूप से खेलों के लिए, जब रैंडम को पूरी तरह से यादृच्छिक () का उपयोग करके उत्पन्न किया जाता है। पहले बीजारोपण अवश्य करें। AppDelegate में srandomdev () को कॉल करें। यहाँ कुछ सहायक कार्य हैं:

static inline int random_range(int low, int high){ return (random()%(high-low+1))+low;}
static inline CGFloat frandom(){ return (CGFloat)random()/UINT32_C(0x7FFFFFFF);}
static inline CGFloat frandom_range(CGFloat low, CGFloat high){ return (high-low)*frandom()+low;}

इस बात से अवगत रहें कि रैंडम () काफी रैंडम नहीं है, इसलिए यदि गति आपके कोड में महत्वपूर्ण नहीं है (जैसे यदि केवल एक बार उपयोग किया जाता है) तो आर्क 4random () का उपयोग करें।
रॉबर्ट वासमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.