一道華爲的機試題

同學最近找工作,遇到了一個機試題,咋一看感覺很簡單,後來做了一下,才發現裏面考察了很多東西,如字符串的操作,大數的計算等等....

廢話不說,直接上題目

 

1、程序實現目標:輸入1~20的數字n,求n以內數據的階乘之和。
1! + 2! + 3! +......+n! = ?

void GetCount(int Num ,float pOutput[])
{

}
void main()
{
    float pNumber[2] = {0};
    Number = 20;
    GetCount(Number ,pNumber);
}


下面是lz寫的程序

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN		50

// float佔4個字節,有符號 表示數的範圍2^31 = 正負2147483648
// 2147483648反方向存儲到maxStr中,低位存儲低位數,方便計算
// maxStr 序號 9  8  7  6  5  4  3  2  1  0
//         值  2  1  4  7  4  8  3  6  4  8
static const char SIGN_NUM[10] = {'8', '4', '6', '3', '8', '4', '7', '4', '1', '2'};

// 緩存上一次階乘的結果
static char lastResult[LEN] = {0};

// 獲得有效位
int GetValidBits(char result[], int len)
{
	int pos = len - 1;
	while(result[pos] == 0) {
		--pos;
	}
	return pos;
}

void Add(char num1[], char num2[], char result[]) 
{
	int iadd = 0;
	int carryAdd = 0;
	for (iadd=0; iadd < LEN; ++iadd) {
		int sum = num1[iadd] + num2[iadd];
		result[iadd] = sum % 10 + carryAdd;
		carryAdd = sum / 10;
	}
	if (carryAdd != 0) {
		result[iadd] += carryAdd;
	}

	// 處理所有的進位
	for (iadd = 0; iadd < LEN; ++iadd) {
		if (result[iadd] >= 10) {
			int sum = result[iadd];
			result[iadd] = sum % 10;
			result[iadd+1] += sum/10;
		}
	}

}

void Factorial(int num, char result[])
{
	if (num == 1) {
		result[0] = 1;
		lastResult[0] = 1;
		return;
	}

	int addPos = 0;
	while (num != 0) {
		int tmpNum = num % 10;
		int carry = 0;

		char middleNum[LEN] = {0};

		// high其中的一位和lastResult 相乘
		int ipos = 0;
		for (ipos=0; ipos<LEN; ++ipos) {
			int multi = lastResult[ipos] * tmpNum;
			middleNum[ipos] = multi % 10 + carry;
			carry = multi / 10;
		}
		if (carry != 0) {
			middleNum[ipos] += carry;
		}
		// 處理所有的進位
		for (ipos = 0; ipos < LEN; ++ipos) {
			if (middleNum[ipos] >= 10) {
				int sum = middleNum[ipos];
				middleNum[ipos] = sum % 10;
				middleNum[ipos+1] += sum/10;
			}
		}


		// middleNum 和 result 錯位相加
		int iadd = 0;
		int carryAdd = 0;
		for (iadd=0; iadd < LEN; ++iadd) {
			int sum = result[iadd+addPos] + middleNum[iadd];
			result[iadd+addPos] = sum % 10 + carryAdd;
			carryAdd = sum / 10;
		}
		// 加法進位,直到處理完
		if (carryAdd != 0) {
			result[iadd+addPos] += carryAdd;
		}
		// 處理所有的進位
		for (iadd = 0; iadd < LEN; ++iadd) {
			if (result[iadd] >= 10) {
				int sum = result[iadd];
				result[iadd] = sum % 10;
				result[iadd+1] += sum/10;
			}
		}

		num /= 10;
		++addPos;
	}
	
	memcpy(lastResult, result, LEN);
}

void Multi(int num, char result[])
{
	int ipos = 0;
	int carry = 0;
	for (ipos; ipos < sizeof(SIGN_NUM); ++ipos) {
		int muti = (SIGN_NUM[ipos] - '0') * num;
		result[ipos] = muti % 10 + carry;
		carry = muti / 10;
	}
	if (carry != 0) {
		result[ipos] += carry;
	}

	// 處理所有的進位
	for (ipos = 0; ipos < sizeof(SIGN_NUM); ++ipos) {
		if (result[ipos] >= 10) {
			int sum = result[ipos];
			result[ipos] = sum % 10;
			result[ipos+1] += sum/10;
		}
	}
}

int BigNumCompare(char numStr1[], char numStr2[])
{
	// ipos指向高位
	int ipos1 = GetValidBits(numStr1, 11);
	int ipos2 = GetValidBits(numStr2, 11);

	// 如 numStr1 : 00123			有效位下標2
	// 	  numStr2 :  01234			有效位下標1
	if (ipos1 > ipos2) {
		return 1;
	}
	if (ipos1 < ipos2) {
		return -1;
	}

	while (true) {
		if ((ipos1 < 0) || (ipos2 < 0)) {
			break;
		}

		if (numStr1[ipos1] > numStr2[ipos2]) {
			return 1;
		}
		if (numStr1[ipos1] < numStr2[ipos2]) {
			return -1;
		}
		--ipos1;
		--ipos2;
	}
	return 0;
}

void StrSubtract(char ret[], char num[], int len)
{
	int carry = 0;
	int ipos = 0;
	for (ipos=0; ipos<len; ++ipos) {
		ret[ipos] -= num[ipos];
		carry = ipos;
		while (ret[carry] < 0) {
			// 後位向前位借10
			ret[carry+1] -= 1;
			ret[carry] += 10;
			++carry;
		}
	}
}

void CharToFloat(char numStr[], float result[])
{
	// result[0]存儲numStr與2147483648相除的餘數
	// result[1]存儲numStr與2147483648相除的倍數

	// 存儲2147483648 與 1-9相乘的結果,  n位數和個位數相乘,結果最大爲n+1位數,故numStrList的列大小爲11個字節
	char multiBuf[9][11] = {0};
	Multi(1, multiBuf[0]);
	Multi(2, multiBuf[1]);
	Multi(3, multiBuf[2]);
	Multi(4, multiBuf[3]);
	Multi(5, multiBuf[4]);
	Multi(6, multiBuf[5]);
	Multi(7, multiBuf[6]);
	Multi(8, multiBuf[7]);
	Multi(9, multiBuf[8]);
	
	int integerPos = 10;
	// 整數部分
	char *integerStr = new char[11];
	memset(integerStr, 0, 11);
	// 餘數部分
	char *remainderStr = new char[11];
	int remainderLen = 11;
	memset(remainderStr, 0, remainderLen);

	char *bigNumStr = new char[LEN];

	memset(bigNumStr, 0, LEN);
	memcpy(bigNumStr, numStr, LEN);

	int validPos = GetValidBits(bigNumStr, LEN);

	
	if (validPos < 9) {
		// bigNumStr小於2147483648,故不用相除, bigNumStr就爲餘數
		int low = 0;
		int remainderValidPos = GetValidBits(bigNumStr, LEN);
		for (int i=remainderValidPos; i>=0; --i) {
			low *= 10;
			low += bigNumStr[i];
		}
		memcpy(&result[0], &low, sizeof(int));

		int high = 0;
		memcpy(&result[1], &high, sizeof(int));
		return;
	}

	// 從bigNumStr取出前10位數
	int curPos = validPos;
	for (int i=remainderLen-2; i>=0; --i, --curPos) {
		remainderStr[i] = bigNumStr[curPos];
	}

	while (true) {
		if (curPos < 0 && BigNumCompare(remainderStr, multiBuf[0]) < 0) {
			break;
		}
		// 取出的數小於2147483648,則商補0,再取一位
		while (BigNumCompare(remainderStr, multiBuf[0]) < 0) {
			integerStr[integerPos--] = 0;
			// 左移,然後補一位
			
			for (int i=remainderLen-1; i>0; --i) {
				remainderStr[i] = remainderStr[i-1];
			}
			remainderStr[0] = bigNumStr[curPos];
			curPos--;
		}

		// 獲得最接近的一個multiBuf值
		int ipos = 0;
		for (ipos=0; ipos<9; ipos++) {
			if (BigNumCompare(remainderStr, multiBuf[ipos]) < 0) {
				break;
			}
		}

		// i放入integer
		integerStr[integerPos--] = ipos;
		// 相減
		StrSubtract(remainderStr, multiBuf[ipos-1], 11);

		if (curPos >= 0) {
			// 左移,然後補一位
			for (int i=remainderLen-1; i>0; --i) {
				remainderStr[i] = remainderStr[i-1];
			}
			remainderStr[0] = bigNumStr[curPos];
			--curPos;
		}
	}

	int low = 0;
	int remainderValidPos = GetValidBits(remainderStr, 11);
	for (int i=remainderValidPos; i>=0; --i) {
		low *= 10;
		low += remainderStr[i];
	}
        // 不能用 賦值語句,否則精度會有丟失
	memcpy(&result[0], &low, sizeof(int));

	int high = 0;
	for (int i=10; i>=integerPos+1; --i) {
		high *= 10;
		high += integerStr[i];
	}
	memcpy(&result[1], &high, sizeof(int));
}

void FloatToChar(float data[], char resultStr[])
{
	// high爲2147483648的倍數
	int low = 0;
	int high = 0;
        
        // 不能用 賦值語句,否則精度會有丟失
	memcpy(&low, &data[0], sizeof(int));
	memcpy(&high, &data[1], sizeof(int));

	int addPos = 0;
	while (high != 0) {
		int num = high % 10;
		int carry = 0;

		// n位數和個位數相乘,結果最大爲n+1位數,故middleNum大小爲11個字節
		char middleNum[11] = {0};

		// high其中的一位和SIGN_NUM 相乘
		int ipos = 0;
		for (ipos=0; ipos<10; ++ipos) {
			// 把字符的數字 轉換成 相應的int型
			int num1 = SIGN_NUM[ipos] - '0';
			int multi = num * num1;

			middleNum[ipos] = multi % 10 + carry;
			carry = multi / 10;
		}
		if (carry != 0) {
			middleNum[ipos] += carry;
		}
		// 處理所有的進位
		for (ipos = 0; ipos < 10; ++ipos) {
			if (middleNum[ipos] >= 10) {
				int sum = middleNum[ipos];
				middleNum[ipos] = sum % 10;
				middleNum[ipos+1] += sum/10;
			}
		}

		// middleNum 和 resultStr 錯位相加
		int iadd = 0;
		int carryAdd = 0;
		for (iadd=0; iadd < sizeof(middleNum); ++iadd) {
			int sum = resultStr[iadd+addPos] + middleNum[iadd];
			resultStr[iadd+addPos] = sum % 10 + carryAdd;
			carryAdd = sum / 10;
		}
		if (carryAdd != 0) {
			resultStr[iadd+addPos] += carryAdd;
		}
		// 處理所有的進位
		for (iadd = 0; iadd < LEN; ++iadd) {
			if (resultStr[iadd] >= 10) {
				int sum = resultStr[iadd];
				resultStr[iadd] = sum % 10;
				resultStr[iadd+1] += sum/10;
			}
		}

		high /= 10;
		++addPos;
	}

	// 把low轉化成字符串
	int ipos = 0;
	char middleNum[11] = {0};
	while(low != 0) {
		middleNum[ipos] = low % 10;
		low /= 10;
		ipos ++;
	}

	// resultStr 和 low相加
	int iadd = 0;
	int carryAdd = 0;
	for (iadd=0; iadd < sizeof(middleNum); ++iadd) {
		int sum = resultStr[iadd] + middleNum[iadd];
		resultStr[iadd] = sum % 10 + carryAdd;
		carryAdd = sum / 10;
	}
	if (carryAdd != 0) {
		resultStr[iadd] += carryAdd;
	}
	// 處理所有的進位
	for (iadd = 0; iadd < LEN; ++iadd) {
		if (resultStr[iadd] >= 10) {
			int sum = resultStr[iadd];
			resultStr[iadd] = sum % 10;
			resultStr[iadd+1] += sum/10;
		}
	}
}

void GetCount(int Num ,float pOutput[])
{
	// float佔4個字節,有符號 表示數的範圍2^31 = 正負2147483648
	// pOutput[0]存儲大數與2147483648相除的餘數
	// pOutput[1]存儲大數與2147483648相除的倍數

	char *multi = new char[LEN];
	char *sum   = new char[LEN];
	char *total = new char[LEN];
	memset(total, 0, LEN);

	if (Num > 20) {
		printf("輸入數字不能大於20......");
		getchar();
		return;
	}

	for (int i=1; i <= Num; ++i) {
		memset(multi, 0, LEN);
		memset(sum, 0, LEN);

		Factorial(i, multi);
		Add(total, multi, sum);
		memcpy(total, sum, LEN);
	}

	// 上面已經完成了計算, 接下來把total存儲到pOutput中
	CharToFloat(total, pOutput);

	delete [] total;
	delete [] sum;
	delete [] multi;
}

void Printf(char bigData[], int len)
{
	int ipos = GetValidBits(bigData, LEN);
	for (ipos; ipos >= 0; --ipos) {
		printf("%c", bigData[ipos] + '0');
	}
}

int main(void)
{
	float  pNumber[2] = {0};
	int Number = 20;
	GetCount(Number ,pNumber);

	char bigData[LEN] = {0};
	FloatToChar(pNumber, bigData);
	Printf(bigData, LEN);

	getchar();
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章