一道面试题引发的有关随机数的思考(6)

在上一篇文章(http://blog.csdn.net/xzjxylophone/article/details/6853624)中,关于效率的问题进行简单的讨论,

现在我就用C#中委托来实现RandN_2,算法都是一样的。

类RandN_2:

//支持2-49,包括2和49
public class RandN_2 : Rand7Base
{
	//声明委托,返回true表示已经计算完毕
	protected delegate bool GetNextResult(int remain, int ceiling, ref int result);
	private GetNextResult _getNextResult;

	protected int _remain;       //剩余
	protected int _ceiling;      //大于的最小数
	private RandN_2(int maxNum)
	{
		UpdateMaxNum(maxNum);
	}
	public void UpdateMaxNum(int maxNum)
	{
		_maxNum = maxNum;
		_remain = _maxNum % 7;
		decimal chushu = (decimal)_maxNum / 7;
		_ceiling = (int)Math.Ceiling(chushu);
		switch (_ceiling)
		{
			case 1:
				_getNextResult = NextResult1;
				break;
			case 2:
				_getNextResult = NextResult2;
				break;
			case 3:
				_getNextResult = NextResult3;
				break;
			default:
				_getNextResult = NextResult4567;
				break;
		}
	}
	//小于等于7的时候
	protected bool NextResult1(int remain, int ceiling, ref int result)
	{
		if (remain > _remain)
		{
			result = Next();
			return true;
		}
		result = remain;
		return true;
	}
	//8-14的时候
	protected bool NextResult2(int remain, int ceiling, ref int result)
	{
		if (ceiling == 1)
		{
			return false;
		}
		if (ceiling > 4)
		{
			result = remain;
		}
		else
		{
			if (remain > _remain)
			{
				result = Next();
				
			}
			else
			{
				result = remain + 7;
			}
		}
		return true;
	}
	//15-21的时候
	protected bool NextResult3(int remain, int ceiling, ref int result)
	{
		if (ceiling == 1)
		{
			return false;
		}
		//6,7
		if (ceiling > 5)
		{
			result = remain;
		}
		else if (ceiling > 3)//4,5
		{
			result = remain + 7;
		}
		else //2,3
		{
			if (remain > _remain)
			{
				result = Next();
				
			}
			else
			{
				result = remain + 7 * 2;
			}
		}
		return true;
	}
	//22-49的时候
	protected bool NextResult4567(int remain, int ceiling, ref int result)
	{
		if (ceiling > _ceiling)
			return false;

		result = remain + (ceiling - 1) * 7;
		if (ceiling == _ceiling && _remain != 0)
		{
			if (remain > _remain)
			{
				result = Next();
				
			}
		}
		return true;
	}
	public static RandN_2 GetInstance(int maxNum)
	{
		if (rand == null || !(rand is RandN_2))
		{
			rand = new RandN_2(maxNum);
		}
		else if (rand is RandN_2 && rand.MaxNum != maxNum)
		{
			((RandN_2)rand).UpdateMaxNum(maxNum);
		}
		return (RandN_2)rand;
	}

	override public int Next()
	{
		int result = 0;
		int remain = _rand7.Next();
		bool loop = false;
		int ceiling = 0;
		while (!loop)
		{
			ceiling = _rand7.Next();
			loop = _getNextResult(remain, ceiling, ref result);
		}
		return result;
	}
}


添加测试代码:

static void TestRandN_2()
{
	RandN_2 rand = RandN_2.GetInstance(34);
	TestRand(rand);
	rand = RandN_2.GetInstance(35);
	TestRand(rand);
	rand = RandN_2.GetInstance(6);
	TestRand(rand);
}

测试结果如下:

计算Rand34的概率如下
产生1的概率是:0.0293664
产生2的概率是:0.0293180
产生3的概率是:0.0293527
产生4的概率是:0.0293710
产生5的概率是:0.0295124
产生6的概率是:0.0293318
产生7的概率是:0.0293360
产生8的概率是:0.0293739
产生9的概率是:0.0294344
产生10的概率是:0.0293604
产生11的概率是:0.0294201
产生12的概率是:0.0293619
产生13的概率是:0.0293823
产生14的概率是:0.0295176
产生15的概率是:0.0293114
产生16的概率是:0.0294928
产生17的概率是:0.0294471
产生18的概率是:0.0293353
产生19的概率是:0.0293968
产生20的概率是:0.0294575
产生21的概率是:0.0294152
产生22的概率是:0.0294324
产生23的概率是:0.0294275
产生24的概率是:0.0294937
产生25的概率是:0.0293569
产生26的概率是:0.0294170
产生27的概率是:0.0294112
产生28的概率是:0.0294705
产生29的概率是:0.0294017
产生30的概率是:0.0293598
产生31的概率是:0.0294615
产生32的概率是:0.0294824
产生33的概率是:0.0295156
产生34的概率是:0.0294748
耗时: 3.17424430414457 秒
Average:0.0294118;Max:0.0295176;Min:0.0293114
Max:0.0295176, Max-Average:0.0001058, Bits:0.3598400%
Min:0.0293114, Min-Average:-0.0001004, Bits:-0.3412400%
计算Rand35的概率如下
产生1的概率是:0.0285922
产生2的概率是:0.0285493
产生3的概率是:0.0285821
产生4的概率是:0.0285874
产生5的概率是:0.0285950
产生6的概率是:0.0286506
产生7的概率是:0.0284996
产生8的概率是:0.0285676
产生9的概率是:0.0285698
产生10的概率是:0.0285851
产生11的概率是:0.0285485
产生12的概率是:0.0286162
产生13的概率是:0.0286179
产生14的概率是:0.0285686
产生15的概率是:0.0286348
产生16的概率是:0.0286025
产生17的概率是:0.0285430
产生18的概率是:0.0285673
产生19的概率是:0.0284558
产生20的概率是:0.0286432
产生21的概率是:0.0285322
产生22的概率是:0.0285425
产生23的概率是:0.0285563
产生24的概率是:0.0286283
产生25的概率是:0.0285434
产生26的概率是:0.0285640
产生27的概率是:0.0285837
产生28的概率是:0.0285114
产生29的概率是:0.0285032
产生30的概率是:0.0284974
产生31的概率是:0.0285877
产生32的概率是:0.0286038
产生33的概率是:0.0286174
产生34的概率是:0.0285587
产生35的概率是:0.0285935
耗时: 3.20557551823726 秒
Average:0.0285714;Max:0.0286506;Min:0.0284558
Max:0.0286506, Max-Average:0.0000792, Bits:0.2771000%
Min:0.0284558, Min-Average:-0.0001156, Bits:-0.4047000%
计算Rand6的概率如下
产生1的概率是:0.1670055
产生2的概率是:0.1666923
产生3的概率是:0.1664376
产生4的概率是:0.1666388
产生5的概率是:0.1665858
产生6的概率是:0.1666400
耗时: 2.94888697894323 秒
Average:0.1666667;Max:0.1670055;Min:0.1664376
Max:0.1670055, Max-Average:0.0003388, Bits:0.2033000%
Min:0.1664376, Min-Average:-0.0002291, Bits:-0.1374400%

可以看出在计算Rand6的时候,速度快了很多。

现在既然已经解决了49以内的随机数,那么有没有可能用Rand7计算任意的一个随机数了?

答案是肯定的,下一篇文章我们来解决如何去解决任意一个数


你可能感兴趣的:(算法,面试,C#,测试,Class,360)