ã¯ããã«
é
åã®è¦ç´ ãã©ã³ãã ãªé ã«ä¸¦ã³æ¿ãããã·ã£ããã«ãã¯ãã²ã¼ã åé (ãã¼ã«ã¼ã麻éãªã©) ã®ã¿ãªãããæ©æ¢°å¦ç¿ã®åå¦çãªã©ãå¹
åºãå©ç¨ããã¦ãã¾ãã
æ¬ç¨¿ã§ã¯ããã®ã·ã£ããã«ãåçã«ããã¤é«éã«è¡ãææ³ã«ã¤ãã¦ç´¹ä»ãã¾ãã
ã©ã³ãã ã½ã¼ã
ã¾ãã¯æªãä¾ããé ã追ã£ã¦è¦ã¦ããã¾ãããã
ãããã£ãã³ã¼ããè¦ãããããã¯æ¸ããçµé¨ã®ããæ¹ãå¤ããã¨æãã¾ãã
static IEnumerable<T> LinqShuffle<T>(IEnumerable<T> source) { return source.OrderBy(_ => Random.Shared.Next()); }
ä¹±æ°ããã¼ã¨ãã¦ã½ã¼ããããã¨ã§ã·ã£ããã«ããã¨ãããã¨ã¦ãç°¡åã«å®è£ ã§ããã³ã¼ãã§ãã
ä¹±æ°ã®ä»£ããã« Guid
ã使ããã¿ã¼ã³ãããã¾ããã
æ¬è³ªçã«ã¯ä¹±æ°ã¨åãã§ãã
static IEnumerable<T> LinqShuffleGuid<T>(IEnumerable<T> source) { return source.OrderBy(_ => Guid.NewGuid()); }
ãã ããã®ææ³ã¯çµæ§éå¹çã§ããå ·ä½çã«æãã¦ããã¾ãããã
ã½ã¼ããªã®ã§é ãã»åçã§ã¯ãªã
OrderBy
㯠.NET 9 æç¹ã§ã¯å®å®ãª ã¯ã¤ãã¯ã½ã¼ãã§å®è£
ããã¦ãã¾ã ã
詳ããæ¹ã¯ã¯ã¤ãã¯ã½ã¼ãã¯å®å®ã½ã¼ãã§ã¯ãªãã®ã§ã¯ï¼ã¨æãããããããã¾ãããããã®å®è£
ã§ã¯çå¤ã ã£ãå ´åã«ã¯ã¤ã³ããã¯ã¹ã®å·®ãè¿ãæ¯è¼é¢æ°ãç¨ãããã¨ã§å®å®ã½ã¼ãã«ãã¦ããã¾ãã
ã¯ã¤ãã¯ã½ã¼ãã®å¹³åè¨ç®é㯠ã§ããéãã¨è¨ãã°éãã§ããã
ã§è¨ç®ãããã¨ããã§ãã
OrderBy
ã¯å®å®ã½ã¼ãã®ããããã¼ (ããã§ã¯ Random.Shared.Next()
ã®å¤) ãéè¤ããå ´åã«ãã¨ãã¨ã®é åºãç¶æããã¾ãã
ãããã£ã¦ãä½ç½®çã«å
é ã«è¿ãå¤ã¯å
é ä»è¿ã«ãæ«å°¾ã«è¿ãå¤ã¯æ«å°¾ä»è¿ã«åºç¾ãããããªãã¾ãã
ç´æçã«ã¯ã»ã¼ããããªããããªç¢ºçã«æããããããã¾ãããããããªãã«ç¾å®çã«èµ·ãããã¾ãã
èªçæ¥æ»æ ã®è¨ç®å¼ ããã 54562 åç¨åº¦ã®è¦ç´ ã«ã½ã¼ããè¡ãã¨ç´ 50% ã®ç¢ºçã§è¡çªãçºçãã¾ãã
OrderBy
ã¯ãã¡ã¢ãª (ãã¼ã) ã ã§æ¶è²»ãã¾ããããã¯ã åæããéã«å
é¨çã«ãã¨ã®é
åã®ã³ãã¼ã使ãã ããã§ããã¾ããåºå®ãµã¤ãºã§ãã
IOrderedEnumerable<TElement>
èªä½ãæ¯è¼é¢æ°ãªã©ã®ã¢ãã±ã¼ã·ã§ã³ãè¡ããã¾ãã大ããªé
åã«ãªã£ã¦ããã¨å°å³ã«éããªã£ã¦ãã¾ãã
以ä¸ã«è¿°ã¹ãããã«ãã½ã¼ãã«ããã·ã£ããã«ã¯å®è£ ãæ¥½ãªãããã«æ¬ ç¹ãå¤ãåå¨ãã¾ãã
ãã ãåºæ°ã½ã¼ãã¨ãã£ã ã®ã¢ã«ã´ãªãºã ãå©ç¨ããããããã¯å·¨å¤§ãªé
åã«å¯¾ãã¦ã¯ä¸¦ååå¯è½ãªã½ã¼ããå©ç¨ãããã¨ã§éããªãããããã¾ãããæ¤è¨ã®ä½å°ãããâ¦â¦ããâ¦â¦ï¼
æå
ã§è©¦ããéãã§ã¯ã 10 ä¸è¦ç´ ã® IEnumerable<int>
ã«å¯¾ã㦠source.AsParallel().OrderBy(...)
ã§ä¸¦åã½ã¼ãããå ´åã«ãé並åã®ãã®ãã 2 åç¨åº¦æ©ããªãã¾ããããã ãå°ããã³ã¬ã¯ã·ã§ã³ã«å¯¾ãã¦ã¯ 100 åç¨åº¦é
ããªãã»ãã¼ããæ°åï½æ°ååæ¶è²»ããã»ä¸¦åå®è¡ã®ããæ¬ä¼¼ä¹±æ°ã¾ããã®æ±ããé£ãããªããªã©é£ç¹ãå¤ããããããããã¯ã§ãã¾ããã
å±éºãªã©ã³ãã ã½ã¼ã
ãããã½ã¼ãã使ã£ãã·ã£ããã«ã®å®è£
ã§ããã絶対ã«ãã¦ã¯ããã¾ããã
static IEnumerable<T> LinqShuffle_Danger<T>(IEnumerable<T> source) { return source.OrderBy(_ => _, Comparer<T>.Create((_, _) => Random.Shared.Next(int.MinValue, int.MaxValue))); }
ããã¯ãã¼ã§ã¯ãªãæ¯è¼é¢æ°ãè¿ãçµæãã©ã³ãã ã«ããææ³ãªã®ã§ããããããè¡ã£ã¦ãã¾ãã¨ã½ã¼ãã®åæã¨ãªãé¢ä¿æ§ãç ´ç¶»ãã¦ãã¾ãã¾ãã
ã·ã£ããã«ã®ç§»åå
ãåã£ãããéãæªãã¨ã©ã³ãã ã«ä»¥ä¸ã®ãã㪠ArgumentException
ãçºçããããã¾ãã
ãã©ã³ãã ã«ãã¨ããã®ãåä»ã§ããã¹ãæã«æåãã¦æ¬çªã§ããããã¨ãã£ãäºæ
ãèµ·ããããã¾ããã
System.ArgumentException: 'Unable to sort because the IComparer.Compare() method returns inconsistent results. Either a value does not compare equal to itself, or one value repeatedly compared to another value yields different results. IComparer: 'System.Comparison`1[System.Int32]'.'
Fisher-Yates shuffle
詳ããæ¹ã¯ Fisher-Yates shuffle ããåç¥ãã¨æãã¾ãã
ãã®ã¢ã«ã´ãªãºã ã¯é常ã«å¹ççã§ãã
static void FisherYates<T>(Span<T> source) { for (int i = source.Length - 1; i >= 1; i--) { int j = Random.Shared.Next(i + 1); (source[i], source[j]) = (source[j], source[i]); } }
Fisher-Yates shuffle ã®è¨ç®é㯠ã§ãã©ã³ãã ã½ã¼ãããå¹ççã§ãã
ã¡ã¢ãªã追å ã§æ¶è²»ãããã¨ãããã¾ããã (LINQ çã¨åãããã«å
ã®é
åã夿´ããªã (inside-out ãª) å®è£
ã«ããå ´åã¯ãã¡ããå
ã®é
åã¨åãã¶ãæ¶è²»ãã¾ãããã©ã¡ãã«ããçæ³çã§ãã)
å ãã¦ã æ¬ä¼¼ä¹±æ°çæå¨ãçæ³çã§ããã° åçã«ã·ã£ããã«ããã¾ããããè¦ç´ ãããä½ç½®ã«é
ç½®ããã確çãå
¨ã¦çãããªãã¾ãã
ãã®ã¢ã«ã´ãªãºã 㯠.NET 8 Preview 1 ã§è¿½å ããã Random.Shuffle
ã§ã å©ç¨ ããã¦ãã¾ãã
æ¬ä¼¼ä¹±æ°ã¾ããã®æé©å
ãã¦ã Fisher-Yates shuffle ã¯ååã«å¹ççãªãããã·ã³ãã«ã§ããããèªä½ãæ¹è¯ããã®ã¯ããªãé£ããã§ãããã
ããã§æ¹è¯ã®ä½å°ãããã®ã¯ã Random.Shared.Next()
ãã¤ã¾ãæ¬ä¼¼ä¹±æ°çæã®é¨åã§ãã
æ¬ä¼¼ä¹±æ°çæå¨ã®é¸å®
æ¬ä¼¼ä¹±æ°çæå¨ãã®ãã®ã®é¸å®ãéè¦ã«ãªã£ã¦ãã¾ãã
å®å
¨ã«åçãªã·ã£ããã«ãç®æããªã CSPRNG (æå·è«çæ¬ä¼¼ä¹±æ°çæå¨; RandomNumberGenerator
) ã使ãæãããããããã¾ãããããã®åããã©ã¼ãã³ã¹ã¯ç ç²ã«ãªãã¾ãã
å®ç¨çã«ã¯ãååã«å
é¨ç¶æ
ã®å¤§ãã (ããå³å¯ã«ã¯åçå叿¬¡å
ã®å¤§ãã) æ¬ä¼¼ä¹±æ°çæå¨ã使ç¨ãã¹ãã§ãããã
ãªãããéãé¢ãããããªå ´å (ã¬ãã£ã¨ã) ãã²ã¼ã ã®æµãã大å¹
ã«å·¦å³ããå ´å (麻éã¨ã) ã®å ´åã¯ã CSPRNG ã使ç¨ãã¹ãã¨ããã ã¨æãã¾ãã
ãªãå
é¨ç¶æ
ã®å¤§ããæ¬ä¼¼ä¹±æ°çæå¨ãå¿
è¦ãªã®ããã«ã¤ãã¦ç°¡åã«èª¬æããã¨ã åã®è¦ç´ ã®ã·ã£ããã«ã®çµæã¯
éããã以ä¸ãæ¬ä¼¼ä¹±æ°çæå¨å´ã§ã
éãã®ä¹±æ°ãçæã§ããå¿
è¦ãããããã§ãã
å
·ä½ä¾ãæããã¨ããã©ã³ãï¼ã¸ã§ã¼ã«ã¼ 2 æãå«ãã 54 æï¼ã§ã¯ ã§ããã®ã§ãå°ãªãã¨ã 238 bit 以ä¸ã®ä¹±æ°ãçæã§ããå¿
è¦ãåºã¦ãã¾ãã麻éç (è±çã¯é¤ããå種ã®çãåºå¥ãããã®ã¨ãã) ãªã
ãªã®ã§ 773 bit 以ä¸å¿
è¦ã§ãã
ãããããã¯çæ³çãªå®è£
ãè¡ã£ãå ´åã®è©±ã§ãé常ã¯ãã以ä¸ã®ãããæ°ãå¿
è¦ã«ãªãã¾ãã
Next()
ãä½åãå¼ã³åºãã° 238 bit ãããä½è£ã§çæã§ãããããªãããã¨æãããããããã¾ããããæ¬ä¼¼ä¹±æ°çæå¨ã®å
é¨å®è£
ã«ãã£ã¦ã¯ãåºç¾ããªãçµã¿åããããçããå¯è½æ§ãããã¾ãã
å
·ä½ä¾ãæããã¨ã 64 bit ã®ç·å½¢ååæ³ã§ã¯ã 64 bit ã¾ã§ãªãä»»æã® bit åãåºåã§ãã¾ããããããã大ãã bit åã®å ´åã¯ã»ã¼ç¢ºå®ã«åºç¾ããªãçµã¿åãããçãã¾ãã
ããå
·ä½çã«ã以ä¸ã®ç·å½¢ååæ³ Lcg64
ãç¨ã㦠2 åã®é£ç¶ããåºåã観測ããã¨ããæåã 0
ãªã次ã¯å¿
ã 1442695040888963407
ã«ãªãã¾ãããã以å¤ã®ãã¢ãä¾ãã° [0, 0]
ãªã©ã¯çµ¶å¯¾ã«åºåããã¾ããã
static ulong Lcg64(ref ulong state) => state = state * 6364136223846793005 + 1442695040888963407;
ãããã£ã¦ã 64 bit ã®ç·å½¢ååæ³ãç¨ãã¦ãã©ã³ããã·ã£ããã«ãããã¨ããå ´åã絶対ã«çæãããªãçµã¿åããããåºãããçµã¿åãããåºã¦ãã¦ãã¾ãã¾ãããã®å ´åã¯ãæä½é xoshiro256++
(256 bit) ãä½è£ããã£ã¦ xoroshiro1024++
(1024 bit) ãªã©ã使ç¨ãã¹ãã§ãããã
ããã§ãã¦ããã¡ããé«éæ§ãéè¦ã§ãã
ä¾ãã°ã ã¡ã«ã»ã³ããã¤ã¹ã¿ mt19937
ã§ããã° 19937 bit ã¾ã§çæã§ããã®ã§å¤§æµã®ç¨éã®ã·ã£ããã«ã«èãã¾ã ( ; çè«ä¸ã¯ 2081 æã®ã«ã¼ããåçã«ã·ã£ããã«å¯è½) ããã ãé度ã¯ã¢ãã³ãªæ¬ä¼¼ä¹±æ°çæå¨ã«æ¯ã¹ãã¨é
ãã§ãã
主è¦ãª (?) ã¢ã«ã´ãªãºã ã®å é¨ç¶æ ã® bit æ°ã¨ãããã«ãã£ã¦ã·ã£ããã«ã§ããã«ã¼ãã®ææ°ä¸éã示ãã¾ãã
Algorithm | bits | cards |
---|---|---|
LCG (ç·å½¢ååæ³) |
64 | 20 |
xoroshiro128+ |
128 | 34 |
shioi128 |
128 | 34 |
seiran128 |
128 | 34 |
xoshiro256** |
256 | 57 |
culumi |
256 | 57 |
xoroshiro1024* |
1024 | 171 |
mt19937 (ã¡ã«ã»ã³ããã¤ã¹ã¿) |
19937 | 2081 |
SCP-1214-EX |
4749265984 | 182651279 |
ã¾ãä½è«ã§ããã·ã£ããã«ã«éã£ã話ã§ã¯ããã¾ããããæ¬ä¼¼ä¹±æ°çæå¨ã®åæåã«ãæ°ãé
ãå¿
è¦ãããã¾ããä¾ãã°ãã¡ã«ã»ã³ããã¤ã¹ã¿ã®åæå颿°ã«ã¯ 32 bit ã®ã·ã¼ããåãåããã®ãããã¾ãã (ãªãªã¸ãã«å®è£
ã® init_genrand(unsigned long s)
) ããããå©ç¨ãã¦ãã¾ãã¨é«ã
éãã®ç³»å (ã·ã£ããã«çµæ) ããå¾ãããªããªã£ã¦ãã¾ãã¾ããåæåæã«ã¯å
é¨ç¶æ
以ä¸ã®æ
å ±éãæã£ãã½ã¼ã¹ (CSPRNG ãªã©) ãç¨ãã¦ãå
¨åãã¾ãã¹ããªãã©ã³ãã ã«ããå¿
è¦ãããã¾ãã
ãããªãæåãã CSPRNG ã使ãã°ãããªãï¼ã¨ãã話ãããã¾ããé£ããã§ããã
ã¾ãç¾å®çã«ã¯å®è¡é度ãåãåãã®ãããããåç¾æ§ã®æ
ä¿ã®ããã«æ®éã® PRNG ã使ããã¨ã«ãªãã§ãããã
ãã®éã®ãã¤ã³ãã¨ãã¦ã¯ãã§ããéãæ¬ä¼¼ä¹±æ°çæå¨ã¤ã³ã¹ã¿ã³ã¹ã使ãã¾ããã㨠(é½åº¦åæåããªããã¨) ãæãããã¾ããã·ã¼ãå¤ãæ¬ä¼¼ä¹±æ°çæå¨ã®å
é¨ç¶æ
ããå°ããå ´åã¯ãªãããã
æ¬ä¼¼ä¹±æ°çæå¨ã¯ä½¿ãç¶ãããã¨ãåæã«è¨è¨ããã¦ãããåæåç´å¾ (ç¹ã«å°ããªã·ã¼ãå¤ã«ãããã®) ã¯ã©ã³ãã ã§ãªã (ä½ããã®ç¸é¢ããã£ãããç«ã£ã¦ãããããæ°ãå°ãªãã£ãããã) å¤ãåºåããå ´åãããã¾ãã
ä¹±æ°ãçµãã¤ãã
è©±ãæ»ãã¦ã Fisher-Yates shuffle ã®ã³ã¼ãããããã¡ã©è¦ã¦ã¿ã¾ãããã
static void FisherYates<T>(Span<T> source) { for (int i = source.Length - 1; i >= 1; i--) { int j = Random.Shared.Next(i + 1); (source[i], source[j]) = (source[j], source[i]); } }
ãããè¦ãã¨ã åã®è¦ç´ ã«å¯¾ãã¦
åã®
Next()
å¼ã³åºãããããã¨ããããã¾ãã
Next()
ãã¤ã¾ãä¹±æ°çæã¯ç¸å¯¾çã«éãå¦çã§ããããããã®é¨åã®æé©åãå³ãããã§ãã
64 bit ç°å¢åãã®æ¬ä¼¼ä¹±æ°çæå¨ã¯ã大æµã®å ´åä¸åº¦ã« 64 bit ã®ä¹±æ°ãçæã§ãã¾ãã®ã§ã éãã®ä¹±æ°ãå¾ããã¨ãã§ãã¾ãã
ä¾ãã° 100 è¦ç´ ã®ã·ã£ããã«ãªããä¸åãããé«ã
100 éãã¶ãã®ä¹±æ°ããå¿
è¦ãªãã®ã§ãããã 1 åã§ ã¶ãã®æ
å ±éãæã¤ä¹±æ°ãæ¶è²»ãã¦ãã¾ãã«ã¯ãã£ãããªãã§ãã
ç¸å¯¾çã«éã Next()
å¼ã³åºãã®åæ°ãæ¸ãããããã§ããéãä¹±æ°ãçµãã¤ããå¿
è¦ãããã¾ãã
çµãã¤ããã¨ãããã¨ãããä¸ã¤ããã¾ããä¹±æ°ãçµãã¤ããå®è£
ã§ã¯ãå¿
è¦ãªåçå叿¬¡å
æ° (â å
é¨ç¶æ
ã® bit æ°) ãæ¸ãããã¨ãã§ãã¾ããä¾ãã° 20 è¦ç´ ã®ã·ã£ããã«ã«å¯¾ã㦠19 å Next
ãå¼ã¶ç´ æ´ãªå®è£
ã§ã¯ã Next
ã 64 bit ã®ä¹±æ°ãåºåããå ´å bit ã¶ãå¿
è¦ã§ããã®ã«å¯¾ããçµãã¤ããå®è£
ã§ã¯ 1 åã®
Next
å¼ã³åºãã§ãã ( ) ã®ã§
bit ã§æ¸ã¿ã¾ãã
ä¹±æ°ãçµãã¤ããå®éã®å·¥ç¨ã¯ãããªæãã§ãã
ãæ±ãã
- 64 bit æ¬ä¼¼ä¹±æ°
ãçæãã
ã
ã®ç¯å²ã«åçã«å¤æã§ããããã«èª¿æ´ãã
ãåå²ãã¦ã¤ã³ããã¯ã¹ 2 ï½ 20 ã¶ãã®ä¹±æ°ãå¾ã
- å¾ãä¹±æ°ã§ Fisher-Yates shuffle ãè¡ã
ãæ±ãã以ä¸ç¹°ãè¿ã
ããããã®å·¥ç¨ã«ã¤ãã¦è©³ããè¦ã¦ããã¾ãããã
ãæ±ãã
ãæ±ãã¾ãã
ããã¯ä½ãããã¦ãããã¨ããã¨ã ulong
ã§è¡¨ç¾å¯è½ãª ( ããå°ãã) ç¯å²ã§æå¤§ã®éä¹ã®æ°ã§ãã
64 bit æ¬ä¼¼ä¹±æ°
ãçæãã
ulong
å
¨åã«ä¸æ§åå¸ããä¹±æ° r
ãçæãã¾ãã
System.Random
ã«ã¯æ®å¿µãªãã NextUInt64()
ã¯çãã¦ããªãã®ã§ãèªåã§ã好ã¿ã®ã¢ã«ã´ãªãºã ãå®è£
ããæ¬ä¼¼ä¹±æ°çæå¨ãããã¨è¯ãã§ããããé«éãªãã®ããã§ã¤ã¹ããã°ããé«éã«ãåçå叿¬¡å
ã®é«ããã®ããã§ã¤ã¹ããã°ãã大ããªé
åã®ã·ã£ããã«ã«ä½¿ãã¾ãã
ä¸å¿ Random.NextBytes()
ã§é å¼µãã°ä¸å¯è½ã§ã¯ããã¾ãããããªã¼ãã¼ãããããããããªã®ã§ç´ ç´ã«èªä½ãããã¨ããããããã¾ãã
å®ã¯å
é¨çã«ã¯ NextUInt64()
ã¯å®è£
ããã¦ããã®ã§ããã internal
ãªã®ã§è§¦ãã¾ãããæ®å¿µã
ã
ã®ç¯å²ã«åçã«å¤æã§ããããã«èª¿æ´ãã
ããã¯ä¸è¬çãªæ¬ä¼¼ä¹±æ°çæã«ãããç¯å²å¤æã¨åæ§ã§ã Next(int max)
ãªã©ã¨åãã¤ã¡ã¼ã¸ã§ãã
ãã æ³¨æãã¹ããªã®ã¯ãåçã«å¤æãã¨ããã¨ããã§ãã
ä¾ãã°ãå®ç´ã« r % n
ã§å¤æããå ´å㯠n ã 2 ã®åªä¹ã§ãªãéãæå°å¤ä»è¿ãæå¤§å¤ä»è¿ããåºããããªãã¾ãã
å
·ä½çã«ã¯ã r % n
ã§ç¯å²å¤æããå ´åã ã®ç¯å²ã®æ°ã¯
åã
ã®ç¯å²ã®æ°ã¯
ååºç¾ãã¾ãã
ãããã£ã¦ã確çã«åããåºã¾ãã
ãã®ãããr
ãåçæããã»å¥ã®ä¹±æ°ã¨çµã¿åããã¦è£æ£ãããããªã©ãã¦ãåçã«åºãããã«ãã¾ãã
ä»åã¯ã Swift ã§ææ¡ããã¦ããææ³ ããã¼ã¹ã«ãã¦èª¿æ´ãè¡ãã¾ãã
ãã®ææ³ã¯ããã¨ãã¨ã¯ä¸æ§åå¸ã®ä¹±æ°ãç¹å®ã®ç¯å²ã«åããªã夿ããããã®ææ³ã§ãã
Math.BigMul
ãå·§ã¿ã«ä½¿ããã¨ã«ãã£ã¦éãé¤ç®ãå°ä½ç®ãããå¿
è¦ããªãããã¾ã Lemire æ°ãææ¡ãã¦ããæ¹å¼ ã«æ¯ã¹ã¦é£ç¶å試è¡ã¨ãªã確çãä½ãã¨ããç¹å¾´ããããããé«éã«å®è¡ãããã¨ãã§ãã¾ãã
å
·ä½çã«ã¯ãSwift å¼ã¯ 試è¡ç®ã§å試è¡ã«ãªã確çã¯
ã¨ææ°é¢æ°çã«ä½ããªã£ã¦ããã¾ãã
対ã㦠Lemire å¼ã®å ´å㯠ã¨
ã«ä¾åããªã宿°ã¨ãªãã¾ããæåã® 1 åã®ç¢ºç㯠Swift å¼ã«æ¯ã¹ã¦ä½ããªãã¾ããã試è¡åæ°ãéãã¦ãä¸å®ã§ãã
å ã㦠Lemire å¼ã®å ´åã 2 åç®ã®ä¹±æ°ãæ¯ãåã«å°ä½ç® %
ãå®è¡ããå¿
è¦ãããã¾ããããã¯å ´åã«ãã£ã¦ã¯ 1 åã®ä¹±æ°çæã«å¹æµããã¬ãã«ã®æéããããã¾ãã
ãããã£ã¦ãä»åã®ç¨éã§ã¯ Swift å¼ã®ã»ããæå©ã¨å¤æãã¾ããã
Swift å¼ã®å®è£ ä¾ã以ä¸ã«ç¤ºãã¾ãã
// factorial ã¯æ¬æä¸ã® n ã«å¯¾å¿; ç¯å²ã®ä¸é (ãã®å¤ãå«ã¾ãªã) // 64 bit ä¹±æ° r ãçæ ulong r = rng.Next(); ulong rlo = r * factorial; // r * factorial ã®ä¸ä½ 64 bit (rlo) ãè¦ã¦ãç¹°ãä¸ããã®å¯è½æ§ãããã°â¦ // (å¾ç¶ã®å¦çã§è¶³ãããæå¤§å¤ã factorial - 1 ãªã®ã§ã // rlo <= (2^64) - factorial ãªãç¹°ãä¸ããã¯çºçãããå¦ç½®ä¸è¦) while (rlo > 0ul - factorial) { // 追å ã§ä¹±æ° t ãçæããç¹°ãä¸ãããã調ã¹ã // ä¸è¨ã®çç®ãããã¤ã¡ã¼ã¸ // [rhi] . [rlo] -> r * factorial ã® ä¸ä½ rhi / ä¸ä½ rlo // + 0 . [thi] [tlo] -> t * factorial ã® ä¸ä½ thi / ä¸ä½ tlo // --------------------- // [carry sum] [tlo] -> rhi + carry ãæ±ããã¹ããã® ulong thi = Math.BigMul(rng.Next(), factorial, out ulong tlo); ulong sum = rlo + thi; ulong carry = sum < thi ? 1ul : 0ul; // sum == 0xffff...ffff ã§ããã°ãä»å¾ç¹°ãä¸ããã®å¯è½æ§ãããã®ã§ããä¸åº¦ // ããã§ãªããã°ãã以ä¸ç¹°ãä¸ããã¯çºçããªãã®ã§ã carry ãè¶³ãã¦çµäº if (sum != ~0ul) { // r ã« carry(1) ãè¶³ã â rlo ã factorial å¢ãã â // while ã®æ¡ä»¶å¼ããå¿ ããªã¼ãã¼ããã¼ããã®ã§ rhi ã 1 å¢ãã r += carry; break; } rlo = tlo; } // rhi ã¯åããªã 0 <= x < factorial ã®ç¯å²ã«åå¸ãã䏿§ä¹±æ° ulong rhi = Math.BigMul(r, factorial, out _);
ãåããããã ããã§ããããï¼
ç§ã¯æåãã®ã¢ã«ã´ãªãºã ãè¦ãã¨ãæåãã¾ãããããæãã¤ãã¾ããâ¦â¦
Lemire å¼ã§å®è£
ããå ´åã¯ãã®ããã«ãªãã¾ãã
// 64 bit ä¹±æ° r ãçæ ulong r = rng.Next(); ulong rlo = r * factorial; // äºåãã§ãã¯ã常ã«ä¸å¼ã¯æç«ããã®ã§ã // (0 - factorial) % factorial < factorial // ãã® if ã§å¼¾ããã°æéã®ããã % ãã¹ãããã§ãã if (rlo < factorial) { // 2^64 % factorial == (2^64 - factorial) % factorial ulong mod = (0 - factorial) % factorial; // 0 <= rlo < mod ã®å ´åãåæ½é¸ while (rlo < mod) { r = rng.Next(); rlo = r * factorial; } } // rhi ã¯åããªã 0 <= x < factorial ã®ç¯å²ã«åå¸ãã䏿§ä¹±æ° ulong rhi = Math.BigMul(r, factorial, out _);
使ã§ãããé常æã®ç¯å²å¤æã¯ãã¡ãã®ã»ããéãå ´åãå¤ãã§ãã
Lemire å¼ã®ã»ããä¹±æ°ãè¤æ°çæãã確çãä½ãã®ã§ãç¹ã«ä¹±æ°çæãéãå ´åã«æå©ã«ãªããã¡ã§ãã
使ãåã (ã¨ãã³ããã¼ã¯) ã大åã¨ãããã¨ããããã¾ããã
ãåå²ãã¦ã¤ã³ããã¯ã¹ 2 ï½ 20 ã¶ãã®ä¹±æ°ãå¾ã
ãè¨ç®ã§ããããåã¤ã³ããã¯ã¹ãåãåºãã¾ãã
int t2 = (int)Math.BigMul(r, 2ul, out r); // [0, 2) int t3 = (int)Math.BigMul(r, 3ul, out r); // [0, 3) // ... int t20 = (int)Math.BigMul(r, 20ul, out r); // [0, 20)
64 bit . 64 bit ã®åºå®å°æ°ç¹æ°ãã¤ã¡ã¼ã¸ããã¨ããããããããããã¾ããã
æåã® r
ã 0.r ãã¤ã¾ã 0 ï½ 1 ã®ä¹±æ°ã¨è¦ç«ã¦ã¦ã 2, 3, ... ãæããã¨ãã®ä¸ä½ 64 bit = æ´æ°é¨åãå¾ããã¨ã§ 0 ä»¥ä¸ 2, 3, ... æªæºã®ä¹±æ°ãåå¾ãã¾ãã
è«æ "Batched Ranged Random Integer Generation" *1 ã§ã¯ãå¯å¤é²æ°ã®ãããªèãæ¹ããã¦ãã¾ããã ã®ä½ (0 ~ 1) ããå§ã¾ãã
ã®ä½ (0 ï½ 2)ã
ã®ä½ (0 ï½ 3)ãâ¦â¦ ã¨ãã£ãæãã§ãã
Fisher-Yates shuffle ãè¡ã
ããã¯ãã¼ã¹ã®ã³ã¼ãã¨ã»ã¼åãã§ãã
éãç¹ãããã¨ããã°ããªãªã¸ãã«ã®ã³ã¼ãã§ã¯ i <= x < source.Length
ã®ç¯å²ã§ã©ã³ãã ãªã¤ã³ããã¯ã¹ãçæãã¦ãã¾ãããããã¡ãã§ã¯ 0 <= x < i
ã®ç¯å²ã§çæãã¦ãã¾ãã
for æã i++;
ã§åããã¨ã«ãã£ã¦ã ãäºåã«è¨ç®ãã¦ãã£ãã·ã¥ãã¦ãããããã«ããããã§ãã
ãããããã¨ããã¦ã大ä¸å¤«ããã¨ä¸å®ã«ãªããããããªãã®ã§ãæ°å¦çå¸°ç´æ³ã£ã½ã証æï¼ãã¦ããã¾ãã
ã¾ããé·ã 1 ã®é
åã¯ãåè¦ç´ (ã¨ãã£ã¦ãè¦ç´ [0]
ã ãã§ã) ãåçãªç¢ºç (1) ã§åä½ç½® ([0]
) ã«åå¨ããã®ã§ãåçã«ã·ã£ããã«ããã¦ããã¨è¨ãã¾ãã
次ã«ãé·ã ã®é
åããããããã¯åçã«ã·ã£ããã«ããã¦ããã¨ãã¾ãããã®é
åã«
çªç®ã®è¦ç´ ã追å ããããã§ã©ã³ãã ã«
(
) çªç®ã®è¦ç´ ã¨äº¤æããã¨ããåçã«ã·ã£ããã«ããã¦ããã¨è¨ããã§ããããã
ã¾ãã追å ãã çªç®ã®è¦ç´ ã¯çãã確ç (
) ã§å
¨ã¦ã®å ´æã«ç§»åãããããåçã§ããã¨è¨ãã¾ãããã®ä»ã®è¦ç´ ã¯ç§»åãã¦ããªããã
ã®ç¢ºçã§æ«å°¾ã¨äº¤æãããããªã®ã§ãåä½ç½®ã«åçãªç¢ºçã§åå¨ãã¦ããç¶æ
ãç¶æãã¾ãã
以ä¸ããããã®ã·ã£ããã«æ¹å¼ã§ãåé¡ãªãã·ã£ããã«ã§ããã¨ããã¾ãããµãã£ã¨ãã¦ãã¾ãããããªæãã§ãããã§ããããâ¦â¦
次ã®
ãæ±ãã¦ãå¿
è¦ãªã¶ãç¹°ãè¿ã
ãæ±ãã¦ãåæ§ã«æä½ãç¹°ãè¿ãã¾ãã
ãããå
ã®é
åã®é·ãã¨åãåã¾ã§ããã¾ãã
éä¸ã¾ã§å¿
è¦ã§ããã° (é·ãã 25 ã ã£ãå ´åãªã©) ãããã¾ã§ã§ä¹ç®ãæã¡åã£ã¦ãã¾ã£ã¦ããã§ãã
çµæ
ãã³ããã¼ã¯çµæã示ãã¾ãã
BatchedSwift
ãä¸è¨ã®ãä¹±æ°ãçµãã¤ããããå®è£
ã§ãã
DataClass
㯠record DataClass(double x, double y, double z, double w)
ã®ã¯ã©ã¹ã§ããã¯ã©ã¹ã¨æ§é ä½ã§æ§è½ç¹æ§ãéãå¯è½æ§ãèæ
®ãã¦ãã¹ããã¦ãã¾ãã
Method | array | Mean | Error | StdDev |
---|---|---|---|---|
LinqSort | DataClass[1024] | 52,252.68 ns | 1,007.564 ns | 1,237.379 ns |
FisherYatesSwift | DataClass[1024] | 8,163.16 ns | 63.845 ns | 59.721 ns |
BatchedSwift | DataClass[1024] | 6,221.22 ns | 101.979 ns | 90.401 ns |
LinqSort | DataClass[32] | 969.79 ns | 11.481 ns | 10.739 ns |
FisherYatesSwift | DataClass[32] | 261.47 ns | 2.584 ns | 2.417 ns |
BatchedSwift | DataClass[32] | 134.73 ns | 2.616 ns | 2.569 ns |
LinqSort | Int32[1024] | 49,661.06 ns | 727.360 ns | 680.373 ns |
FisherYatesSwift | Int32[1024] | 3,425.73 ns | 46.750 ns | 43.730 ns |
BatchedSwift | Int32[1024] | 1,532.79 ns | 18.482 ns | 16.384 ns |
LinqSort | Int32[32] | 878.98 ns | 10.204 ns | 7.966 ns |
FisherYatesSwift | Int32[32] | 94.11 ns | 1.894 ns | 2.528 ns |
BatchedSwift | Int32[32] | 32.54 ns | 0.227 ns | 0.212 ns |
Linq ã¨ã¯æ¯ã¹ç©ã«ãªããªãã¬ãã«ã§ Fisher-Yates 群ãéãã§ããããã¯ããã
ã¾ãã Batched ã¯çã® Fisher-Yates ã«æ¯ã¹ã¦ 1.5 ï½ 2 åç¨åº¦æ©ããªã£ã¦ãããã¨ãåããã¾ãã
å°æå ã®é«éå
ã¢ã«ã´ãªãºã ã¬ãã«ã§ã¯ãªããå°æå
ã®é«éåææ³ã«ã¤ãã¦æ¸ãã¾ãã
ãã¾ããã£ããã¤ã¨ããã§ã¯ãªããã¤ãããã®ã§æ³¨æãã¦ãã ããã
Next()
ã¡ã½ããã® (æå) ã¤ã³ã©ã¤ã³å±é
ä¹±æ°çæãã¤ã³ã©ã¤ã³å±éãããã¨ã§é«éåãå³ãã¾ãã
ä¾ãã°ã
for (int i = 0; i < length; i++) { ulong r = rng.Next(); // do something }
ããããããããæãã«ãã¾ãã
var state = rng.State; for (int i = 0; i < length; i++) { ulong r = StaticNext(state); // do something } rng.State = state; // --- [MethodImpl(MethodImplOptions.AggressiveInlining)] static ulong StaticNext(State state) { /* same as Next()*/ }
rng.State
ã®æ´æ°ãæå¾ã«ç§»åããã Next()
ãéç颿°ã«å®è£
ããªããã¦ããã®ããã¤ã³ãã§ãã
颿°å¼ã³åºããã¹ãããã§ããããã«ãªãã»ããæåã§å·¥å¤«ãã¦å±éããã¨é½åº¦ã¡ã¢ãªã«æ¸ããã«ã¬ã¸ã¹ã¿ä¸ã§å®çµããããã«ãªããããå¤å°ã®é«éåãè¦è¾¼ãã¾ãã
ãã¡ãããæ¬ä¼¼ä¹±æ°çæå¨ã¨ã¹ã£ããççãããã¨ã«ãªãã®ã§ãä¸é·ä¸çã§ãã
ä¸éãåã
ä¹±æ°ã®åçæãå¿
è¦ã«ãªãã®ã¯ r > 0 - n
ã®å ´åã§ããããã¤ã¾ãã n
ãå°ããã»ã©ä¹±æ°ãåçæãã確çãä¸ããã¾ãã
ä»ã¾ã§ ã¨ãã¦è¨ç®ãã¦ãã¾ããããããã
ã®ããã«ãããã©ãã§ããããï¼
åçå叿¬¡å
ãæ¸ãã®ã¨å¼ãæãã«ãæ£å´çãä¸ãã¦åçæ (=é
å»¶) ãæ¸ããããã¨ãã試ã¿ã§ãã
ã¡ãã£ã¨è©¦ããæãã§ã¯ ã®å¶ç´ãã¤ããã¨ãã«é度ã®ãã©ã³ã¹ãè¯ããã¨ãããã¨ãããã£ã¦ãã¾ãããåçå叿¬¡å
ãç ç²ã«ããã»ã©ã®åçãªå éã¯å¾ããã¦ãã¾ããã®ã§ãå¾®å¦ã§ãã
ã¿ãã«ã§ã®äº¤æãããã
ç¾ä»£ã® C# ã§ã¯ã以ä¸ã®ã³ã¼ãã§è¦ç´ ã®ã¹ã¯ãããã§ãã¾ãã
(span[a], span[b]) = (span[b], span[a]);
ããããããã¯ã©ããã¦ãã以ä¸ã®å¾æ¥ã®ã³ã¼ãã®ã»ãã¨ã¢ã»ã³ããªã®çæçµæãç°ãªãå ´åãããã¾ãã
var t = span[a]; span[a] = span[b]; span[b] = t;
使ã¨ãã¦ã¯ãã¿ãã«ã使ããªãã³ã¼ãã®ã»ããç°¡æ½ãªã¢ã»ã³ããªãçæããå¾åãããã¾ãã
å ·ä½ä¾ã¯ Sharplab ã確èªãã¦ã¿ã¦ãã ããã
SIMD å
C# ã§ã¯ Vector128 ãªã©ãçµç±ã㦠SIMD åãããã¨ãã§ãã¾ãã
ãã®ã³ã¼ãã§ SIMD åã§ããããªã¨ããã¨ãã¦ã¯ã
ã®è¨ç®
- åã¤ã³ããã¯ã¹ã®è¨ç®
ãæãããã¾ãã
ãã ãã¡ãã£ã¨è©¦ããéãã§ã¯ãªã¼ãã¼ãããã®ã»ãã大ãããé«éåã«ã¯ã¤ãªããã¾ããã§ããã
é åã¢ã¯ã»ã¹æã®ç¯å²ãã§ãã¯åé¤
// values[m] = something; Unsafe.Add(ref MemoryMarshal.GetReference(values), m) = something;
ããæ¸ã㨠IndexOutOfRangeException
ãé£ã°ãã³ã¼ãããªããªãã¾ãã
ãã®ã³ã¼ãã¯é«éæ§ã¨å±éºæ§ã表è£ä¸ä½ãªã®ã§ãååãªãããã°ããã¦ããæå¾ã«å®è£
ãã¦ãã ããã
ã®ãã£ãã·ã¥
ã®å¤ã¯å®è¡ãã¨ã«å¤ãããªãã®ã§ããã£ãã·ã¥ãã¦ããããäºåè¨ç®ãã¦åãè¾¼ãã§ãããããããã¨ãã§ãã¾ãã
éçãã£ãã·ã¥ (äºåè¨ç®ã㦠switch) ãåçãã£ãã·ã¥ (Dictionary
ã«ç»é²) ãªã©è©¦ãã¦ã¿ã¾ããããæéã®å²ã«é«éåãã¾ããã§ããããªã®ã§åæã® ã ãåãè¾¼ãã®ãããããã§ãã
Fisher-Yates shuffle ã®èª¤ã£ãå®è£ ä¾
誤ã£ãä¾ã§ãã®ã§ãçä¼¼ããªãã§ãã ããï¼
ä¾ãã°ãä¹±æ°çæã®ç¯å²æå®ã§ +1 ãå¿ããå ´å () ã以ä¸ã®ããã«ãªãã¾ãã
static void FisherYates_Wrong_OffByOne<T>(Span<T> source) { for (int i = source.Length - 1; i >= 1; i--) { int j = Random.Shared.Next(i); // instead of i + 1 (source[i], source[j]) = (source[j], source[i]); } }
ãã®å ´åãããµãããã®ã¢ã«ã´ãªãºã ãã¨ããå¤ç¨®ã«ãªããåé åãçæããããã«ãªãã¾ãã
ã¾ããããè¦ç´ ãã·ã£ããã«å¾ã«åãä½ç½®ã«é
ç½®ããã確çã 0 ã«ãªãã¾ãã
ã¾ããä¹±æ°çæã®ç¯å²æå®ã§å¸¸ã«é åå ¨é¨ã®ç¯å²ãæå®ããå ´åããåããçãã¦ãã¾ãã¾ãã
static void FisherYates_Wrong_Entire<T>(Span<T> source) { for (int i = 0; i < source.Length; i++) { int j = Random.Shared.Next(source.Length); // instead of i + 1 (source[i], source[j]) = (source[j], source[i]); } }
åå¿è ãä½ãè¦ãã«å®è£ ããã¨ãããªãå ´åãå¤ãæ°ããã¾ãã
交æã«ãã£ã¦çãããã¿ã¼ã³æ°ã ã«ãªã䏿¹ã§ãã·ã£ããã«ã«ãã£ã¦çãããã¿ã¼ã³æ°ã¯
ã§ãã
ã§ãã®ã§ãå¿
ãåããçãã¾ãã
å®éã«ã©ã®ããã«åãã®ãã«ã¤ãã¦ã¯ã Wikipedia ã詳ããã§ãã
ã¨ããã§ãã·ã£ããã«ã®å®ä¾ã¨ãã¦ã³ã¼ããæ¢ãã¦ããã¨ããããããè¦ã¤ãã¾ããã
ãã®ããµã³ãã«ã³ã¼ããã®å®è£
ã§ã¯ã¾ãããä¸è¨ã®ééã£ãã·ã£ããã«æ³ãå®è£
ããã¦ãã¾ãã
ãã®ããç¯å²å¤æãå°ä½ã§å®è£
ããã¦ããã®ã§ããã§ãåã£ã¦ãã¾ããäºéè¦ã
MergeShuffle
ãã¦ãé«éåã«ããã£ã¦æãã¤ãææ³ã®ã²ã¨ã¤ã¨ãã¦ã並ååãæãããã¾ãã
並åã«ã·ã£ããã«ãå®è¡ããã¢ã«ã´ãªãºã ã¨ãã¦ã MergeShuffle ãããã¾ãã *2
å®è£
ä¾ã¯ãããªæãã§ããåå²çµ±æ²»æ³ã®ãããªæãã§ããã
åã®é åã«åå²ãã¦ãããã Fisher-Yates ã§ã·ã£ããã«ãããããããã¼ã¸ãã¦ããæãã§ãã
public static void Shuffle<TRng, TSpan>(TRng rng, Span<TSpan> span) where TRng : IRandom { Divide(rng, dist, span); } private static void Divide<TRng, TSpan>(TRng rng, Span<TSpan> span) where TRng : IRandom { if (span.Length <= 16) { FisherYates(rng, dist, span); } else { Divide(rng, dist, span[..(span.Length / 2)]); Divide(rng, dist, span[(span.Length / 2)..]); Merge(rng, dist, span); } } private static void Merge<TRng, TSpan>(TRng rng, Span<TSpan> span) where TRng : IRandom { int start = 0; int mid = span.Length / 2; int end = span.Length - 1; ulong r = rng.Next(); int entropy = 64; while (true) { // ã¨ã³ãããã¼ããªããªã£ããè£å if (entropy == 0) { r = rng.Next(); entropy = 64; } // 1 bit åãåºã ulong bit = r & 1ul; r >>= 1; entropy--; // bit 1 ãªã [start] 㨠[end] ã交æ if (bit == 0) { if (start == mid) { break; } } else { if (mid == end) { break; } (span[start], span[end]) = (span[end], span[start]); mid++; } start++; } while (start < end) { // [0, start) ã®ä¹±æ°ãçæããã㨠[start] ã交æ int index = (int)rng.Next((ulong)start); (span[start], span[index]) = (span[index], span[start]); start++; } }
ãã ãå®éã«å®è£
ãã¦ã¿ãã¨é
ãã§ãã Fisher-Yates ã«å¦çãè¶³ãã¦ããæããªã®ã§ããã¯ãããå®è£
ãæªãã ãããããã¾ãããã
ä¹±æ°çæãã·ã£ããã«ããã¾ã並ååã§ããã°ã大ããªé
åã«å¯¾ãã¦å¹æãè¦è¾¼ãããâ¦â¦ã§ã¯ããã¾ãã
Feistel æ§é ãå©ç¨ããã·ã£ããã«
é¢ç½ãæ§è³ªãæã£ãã·ã£ããã«ææ³ã®ã²ã¨ã¤ã¨ãã¦ã Feistel æ§é ãå©ç¨ããã·ã£ããã«ãæãããã¾ãã
Feistel æ§é ã¯ã ãããã¯æå·ã®æ§ææ³ã®ä¸ç¨®ã§ãã DES ãªã©ã§ä½¿ããã¦ãã¾ãã
ç°¡åãªå®è£
ä¾ã¯ä»¥ä¸ã®ããã«ãªãã¾ãã
// internal state uint left = ..., right = ...; // 4 rounds (any number of rounds) for (int round = 0; round < 4; round++) { (left, right) = (right, left ^ Round(right)); } // here, left and right are encrypted uint Round(uint x) => /* returns any value */;
ããã§ãã¤ã³ãã¨ãªãã®ã¯ã Round()
ã«ã¯ä»»æã®é¢æ°ãç¨ãããã¨ãã§ãããã¨ã§ãã
é度ã¨å質ã天秤ã«ããã¦ã (ããæå³ã§) é©å½ãªé¢æ°ãè¨å®ã§ãã¾ãã
ãã¦ããããã¯æå·ã¨ã·ã£ããã«ã«ä½ã®é¢ä¿ãããã®ããã¨æã£ãæ¹ããããã¨æãã¾ãã
æå·åã§ããã¨ãããã¨ã¯ã復å·ãã§ãã¾ããããã¯ããã
ããã¦å¾©å·ãã§ããã¨ãããã¨ã¯ããã種ã®å
¨åå°é¢æ°ã®ããã«æ¯ãèãã¨ãããã¨ã§ãã
ã©ããããã¨ãã¨ããã¨ãä¾ãã° 4 bit ã® Feistel æ§é ãæ§æãã¦é£çª [0, 1, 2, ..., 15]
ãå
¥åããã¨ãããããæå·åããå¾ã®å¤ã¯ [0, 12, 8, ..., 7]
ã¿ããã«ãªãã®ã§ãããããã¯é£çªã¨ä¸å¯¾ä¸å¯¾å¿ãããããªãã¡é£çªã®é åºããã·ã£ããã«ããããã®ã¨åãã«ãªãã¾ãã
ã¨ãããã¨ã¯ã¤ã¾ããã·ã£ããã«ã«ä½¿ãããã¨ããããã§ãã
å ·ä½çãªæµãã¨ãã¦ã¯ã
è¦ç´ ã®ä¸¦ã¹æ¿ãããããã¨ãã
ãæºãã
ãããã® Feistel æ§é ãã¤ãã
ã§ã«ã¼ã
ãæå·åãã¦
ãæ±ãã
ãªãã
çªç®ã®è¦ç´ ãè¿ã (yield return)
ã¨ããæãã§ãã
ã ãããã® Feistel æ§é ãã¯ãåã«
uint
ã®ã㢠(64 bit) ã«ããããã¹ã¯ãæããã°ããã§ããå
·ä½çã«ã¯ã 18 bit ãå¿
è¦ãªã 0x1ff
(9 ããã) ã®ãã¹ã¯ãæããã°ããã 2 åãªã®ã§ 18 bit ã«ãªãã¾ãã
ãã®ã·ã£ããã«ã®å©ç¹ã¯ã çªç®ã®è¦ç´ ãã©ãã«ç§»åãããã
ã§åå¾ã§ããç¹ã§ãã Fisher-Yates ã®å ´åã¯å
¨è¦ç´ ã®å¦çãçµããã¾ã§åº§æ¨ã¯ç¢ºå®ãã¾ãããã Feistel æ§é ãªã
ãæå·åããã ããªã®ã§é·ãã«ä¾åããã«åº§æ¨ãåå¾ã§ãã¾ãããªã®ã§ãè¶
巨大ãªé
åããããã¤ãã®è¦ç´ ãã©ã³ãã ã«æ½åºããããã¨ãã£ãç¨éã«ã¤ãã¦ã¯å¹ççã«è¡ããããããã¾ããã
ã¾ããé¢ç½ãæ§è³ªã¨ãã¦ã¯ã復å·ãããã¨ã§ã·ã£ããã«ããå
ã«æ»ãããã¨ãã§ãã¾ãã
対ãã¦ãæ¬ ç¹ã¨ãã¦ã¯ãè¦ç´ æ°ã 2 åªã§ãªãå ´åã®å¦çãçµæ§ããã©ããããã¨ãæãããã¾ããè¦ç´ æ°ã 2 åªã§ãªãå ´åãç¯å²å¤åç
§ã«ãªãå ´åãããã®ã§ããããèªã¿é£ã°ãå¿
è¦ãåºã¦ãã¾ãã yield return
ãããããªå®è£
ãªãããã¯ç°¡åãªã®ã§ãããã¤ã³ãã¬ã¼ã¹ãª (追å é åã確ä¿ãããå
ã®é
åãããããããª) å®è£
ã¯é£ããã§ãã
ã¾ãã 1 ã¤ã®è¦ç´ ãåå¾ããã®ã«ãããæéãæ¯è¼çé·ããªã£ã¦ãã¾ãåé¡ãããã¾ããã¡ããã¨ããæå·å (ã·ã£ããã«) ãããããã«ã¯æä½ã§ã 2 ã©ã¦ã³ãå¿
è¦ã§ããããã¡ãã¨ããããã·ã¥é¢æ°ã使ãå¿
è¦ãããã¾ããããã«å¯¾ãã¦ã Fisher-Yates ã§ããã° 1 ã¤ããã 1 åã®ä¹±æ°çæãããæé©åããã° 1 åã®ä¹ç®ã¨æ°åã« 1 åã®ä¹±æ°çæã ãã§æ¸ãã§ãã¾ãã¾ãã
ãããã«
ãããããªã·ã£ããã«ææ³ã¨ãé«éã§åçãªã·ã£ããã«ãè¡ãã«ããã£ã¦ã®å·¥å¤«ã«ã¤ãã¦ã¾ã¨ãã¾ããã
ããã©ã® Fisher-Yates ããéãææ³ããããã¨ããã®ãåãã¦ç¥ã£ãæã¯é©ãã¾ããã
æå¾ã«ãé«éã§åçãªå®è¡ãã§ããææ³ã®å®è£ ä¾ãæãã¦ããã¾ãã