@@ -450,6 +450,113 @@ func TestReadSeedReset(t *testing.T) {
450450	}
451451}
452452
453+ func  TestShuffleSmall (t  * testing.T ) {
454+ 	// Check that Shuffle allows n=0 and n=1, but that swap is never called for them. 
455+ 	r  :=  New (NewSource (1 ))
456+ 	for  n  :=  0 ; n  <=  1 ; n ++  {
457+ 		r .Shuffle (n , func (i , j  int ) { t .Fatalf ("swap called, n=%d i=%d j=%d" , n , i , j ) })
458+ 	}
459+ }
460+ 
461+ // encodePerm converts from a permuted slice of length n, such as Perm generates, to an int in [0, n!). 
462+ // See https://en.wikipedia.org/wiki/Lehmer_code. 
463+ // encodePerm modifies the input slice. 
464+ func  encodePerm (s  []int ) int  {
465+ 	// Convert to Lehmer code. 
466+ 	for  i , x  :=  range  s  {
467+ 		r  :=  s [i + 1 :]
468+ 		for  j , y  :=  range  r  {
469+ 			if  y  >  x  {
470+ 				r [j ]-- 
471+ 			}
472+ 		}
473+ 	}
474+ 	// Convert to int in [0, n!). 
475+ 	m  :=  0 
476+ 	fact  :=  1 
477+ 	for  i  :=  len (s ) -  1 ; i  >=  0 ; i --  {
478+ 		m  +=  s [i ] *  fact 
479+ 		fact  *=  len (s ) -  i 
480+ 	}
481+ 	return  m 
482+ }
483+ 
484+ // TestUniformFactorial tests several ways of generating a uniform value in [0, n!). 
485+ func  TestUniformFactorial (t  * testing.T ) {
486+ 	r  :=  New (NewSource (testSeeds [0 ]))
487+ 	top  :=  6 
488+ 	if  testing .Short () {
489+ 		top  =  4 
490+ 	}
491+ 	for  n  :=  3 ; n  <=  top ; n ++  {
492+ 		t .Run (fmt .Sprintf ("n=%d" , n ), func (t  * testing.T ) {
493+ 			// Calculate n!. 
494+ 			nfact  :=  1 
495+ 			for  i  :=  2 ; i  <=  n ; i ++  {
496+ 				nfact  *=  i 
497+ 			}
498+ 
499+ 			// Test a few different ways to generate a uniform distribution. 
500+ 			p  :=  make ([]int , n ) // re-usable slice for Shuffle generator 
501+ 			tests  :=  [... ]struct  {
502+ 				name  string 
503+ 				fn    func () int 
504+ 			}{
505+ 				{name : "Int31n" , fn : func () int  { return  int (r .Int31n (int32 (nfact ))) }},
506+ 				{name : "int31n" , fn : func () int  { return  int (r .int31n (int32 (nfact ))) }},
507+ 				{name : "Perm" , fn : func () int  { return  encodePerm (r .Perm (n )) }},
508+ 				{name : "Shuffle" , fn : func () int  {
509+ 					// Generate permutation using Shuffle. 
510+ 					for  i  :=  range  p  {
511+ 						p [i ] =  i 
512+ 					}
513+ 					r .Shuffle (n , func (i , j  int ) { p [i ], p [j ] =  p [j ], p [i ] })
514+ 					return  encodePerm (p )
515+ 				}},
516+ 			}
517+ 
518+ 			for  _ , test  :=  range  tests  {
519+ 				t .Run (test .name , func (t  * testing.T ) {
520+ 					// Gather chi-squared values and check that they follow 
521+ 					// the expected normal distribution given n!-1 degrees of freedom. 
522+ 					// See https://en.wikipedia.org/wiki/Pearson%27s_chi-squared_test and 
523+ 					// https://www.johndcook.com/Beautiful_Testing_ch10.pdf. 
524+ 					nsamples  :=  10  *  nfact 
525+ 					if  nsamples  <  200  {
526+ 						nsamples  =  200 
527+ 					}
528+ 					samples  :=  make ([]float64 , nsamples )
529+ 					for  i  :=  range  samples  {
530+ 						// Generate some uniformly distributed values and count their occurrences. 
531+ 						const  iters  =  1000 
532+ 						counts  :=  make ([]int , nfact )
533+ 						for  i  :=  0 ; i  <  iters ; i ++  {
534+ 							counts [test .fn ()]++ 
535+ 						}
536+ 						// Calculate chi-squared and add to samples. 
537+ 						want  :=  iters  /  float64 (nfact )
538+ 						var  χ2  float64 
539+ 						for  _ , have  :=  range  counts  {
540+ 							err  :=  float64 (have ) -  want 
541+ 							χ2  +=  err  *  err 
542+ 						}
543+ 						χ2  /=  want 
544+ 						samples [i ] =  χ2 
545+ 					}
546+ 
547+ 					// Check that our samples approximate the appropriate normal distribution. 
548+ 					dof  :=  float64 (nfact  -  1 )
549+ 					expected  :=  & statsResults {mean : dof , stddev : math .Sqrt (2  *  dof )}
550+ 					errorScale  :=  max (1.0 , expected .stddev )
551+ 					expected .closeEnough  =  0.10  *  errorScale 
552+ 					expected .maxError  =  0.08  // TODO: What is the right value here? See issue 21211. 
553+ 					checkSampleDistribution (t , samples , expected )
554+ 				})
555+ 			}
556+ 		})
557+ 	}
558+ }
559+ 
453560// Benchmarks 
454561
455562func  BenchmarkInt63Threadsafe (b  * testing.B ) {
@@ -514,6 +621,30 @@ func BenchmarkPerm30(b *testing.B) {
514621	}
515622}
516623
624+ func  BenchmarkPerm30ViaShuffle (b  * testing.B ) {
625+ 	r  :=  New (NewSource (1 ))
626+ 	for  n  :=  b .N ; n  >  0 ; n --  {
627+ 		p  :=  make ([]int , 30 )
628+ 		for  i  :=  range  p  {
629+ 			p [i ] =  i 
630+ 		}
631+ 		r .Shuffle (30 , func (i , j  int ) { p [i ], p [j ] =  p [j ], p [i ] })
632+ 	}
633+ }
634+ 
635+ // BenchmarkShuffleOverhead uses a minimal swap function 
636+ // to measure just the shuffling overhead. 
637+ func  BenchmarkShuffleOverhead (b  * testing.B ) {
638+ 	r  :=  New (NewSource (1 ))
639+ 	for  n  :=  b .N ; n  >  0 ; n --  {
640+ 		r .Shuffle (52 , func (i , j  int ) {
641+ 			if  i  <  0  ||  i  >=  52  ||  j  <  0  ||  j  >=  52  {
642+ 				b .Fatalf ("bad swap(%d, %d)" , i , j )
643+ 			}
644+ 		})
645+ 	}
646+ }
647+ 
517648func  BenchmarkRead3 (b  * testing.B ) {
518649	r  :=  New (NewSource (1 ))
519650	buf  :=  make ([]byte , 3 )
0 commit comments