字符串加減法(整數,小數)

最近在做華爲的機試題的時候發現有字符串的小數減法,在百度知道上又看到有人問字符串減法的問題,於是也想練練手。

#ifndef _STRING_OPS_H_ 
#define _STRING_OPS_H_

//[left, right),翻轉字符串
void string_swap(char* input, size_t left, size_t right)
{
	for (; left < --right; left++)
	{//
		if (input[left] != input[right])
		{//
			char t = input[left];
			input[left] = input[right];
			input[right] = t;
		}
	}
}

//找到字符串中的小數點
size_t find_dot(const char* str)
{
	size_t pos = (size_t)-1;
	for (pos = 0; pos < strlen(str); pos++)
	{//
		if (str[pos] == '.')
		{//
			break;
		}
	}

	return pos;
}

//str1+str2
//首先只簡單考慮全是正數的情況
int two_positive_integer_add(const char* str1, size_t len1, 
															const char* str2, size_t len2, 
															char* out, size_t& olen,
															int carry = 0/*用於小數加法的傳遞*/)
{
	int res; //兩個數相加的結果
	size_t ptr1 = len1-1, ptr2 = len2-1;
	olen = len1 > len2 ? len1+1 : len2+1;
	size_t p = olen-1;
	for (size_t ptr = len1 < len2 ? len1 : len2; 
		ptr > 0; ptr1--, ptr2--, ptr--, p--)
	{//
		res = str1[ptr1] - '0' + str2[ptr2] - '0' + carry;
		carry = res>9;
		res = carry ? res-10: res;
		out[p] = res+'0';
	}	

	//把剩餘的位數相加
	for (; ptr1 != (size_t)-1; ptr1--, p--)
	{//
		res = str1[ptr1] - '0' + carry;
		carry = res>9;
		res = carry ? res-10: res;
		out[p] = res+'0';
	}
	for (; ptr2 != (size_t)-1; ptr2--, p--)
	{//
		res = str2[ptr2] - '0' + carry;
		carry = res>9;
		res = carry ? res-10: res;
		out[p] = res+'0';
	}
	int shift = 0;
	//把carry加上
	if (carry == 1)
	{//
		out[p--] = '1';
	}
	else
	{
		olen -= 1;
		for (p = 0; p < olen; p++)
		{//
			out[p] = out[p+1];
		}
		shift = 1;
	}
	return shift;
}

//小數部分相加
//返回整數部分相加時需要的carry
int two_positive_fraction_add(const char* str1, size_t len1,
															const char* str2, size_t len2,
															char* out, size_t& olen)
{
	int carry = 0;
	
	size_t left = len1 < len2 ? len1 : len2; //取最短的那個的末尾
	size_t right = len1 > len2 ? len1 : len2; //取最長的那個的末尾
	const char* longer = len1  > len2 ? str1 : str2;
	//把left,right之間的部分直接複製給out
	olen = right;
	size_t p = olen-1;
	for (--left; --right != left;)
	{//
		out[p--] = longer[right];
	}

	//把兩個字符串相加
	int res;
	for (; left != (size_t)-1; --left)
	{//
		res = str1[left] - '0' + str2[left] - '0' + carry;
		carry = res>9;
		res = carry ? res-10: res;
		out[p--] = res+'0';
	}
	//看看末尾的0
	while (olen != 0 && out[olen-1] == '0')
	{//
		olen--;
	}
	if (olen == 0)
	{//兩個數相等。
		out[olen++] = '0';
	}
	//carry可能是1也可能是0
	return carry;
}

void two_positive_add(const char* str1, const char* str2, char* out)
{
	size_t dot_pos1 = find_dot(str1);
	size_t dot_pos2 = find_dot(str2);
 
	//計算小數部分
	int carry = 0;
	size_t olen_fraction = 0;
	if (dot_pos1 < strlen(str1) || dot_pos2 < strlen(str2))
	{//
		char* fraction = out + (dot_pos1 > dot_pos2 ? dot_pos1+1 : dot_pos2+1);
		fraction[0] = '.';
		fraction++;
		size_t pos1 = dot_pos1 != strlen(str1) ? dot_pos1+1 : dot_pos1;
		size_t pos2 = dot_pos2 != strlen(str2) ? dot_pos2+1 : dot_pos2;
		carry = two_positive_fraction_add(str1+pos1, strlen(str1)-pos1,
			str2+pos2, strlen(str2)-pos2, fraction, olen_fraction);
	}

	//計算整數部分
	size_t olen_integer;
	int shift = two_positive_integer_add(str1, dot_pos1, str2, dot_pos2, 
		out,  olen_integer, carry);

	//左移小數部分
	if (shift > 0)
	{//
		size_t olen = olen_integer + olen_fraction + 1;
		for (size_t p = olen_integer; p < olen; p++)
		{// 
			out[p] = out[p+shift];
		}
	}
	out[olen_fraction + olen_integer + 1] = '\0';
}

//str1-str2
//兩個數全是正數,且str1>str2
int two_positive_integer_minus(const char* str1, size_t len1, 
																const char* str2, size_t len2,
																char* out, size_t& olen, int borrow = 0)
{
	int res; //兩個數相減的結果
	size_t ptr1 = len1-1, ptr2 = len2-1;
	int a,b;//被減數,減數
	olen = len1 > len2 ? len1 : len2;
	size_t p = olen-1;
	for (; ptr2 != (size_t)-1; ptr1--, ptr2--, p--)
	{//
		a = str1[ptr1]-'0' - borrow;
		b = str2[ptr2] - '0';
		borrow = a < b ? 1 : 0;
		res = a + 10*borrow - b;
	
		out[p] = res+'0';
	}

	//把剩餘的位數相減
	for (; ptr1 != (size_t)-1; ptr1--, p--)
	{//
		a = str1[ptr1]-'0' - borrow;
		borrow = a < 0 ? 1 : 0;
		res = a + 10*borrow;

		out[p] = res+'0';
	}
	//刪除開頭的0
	size_t zeros = 0;
	for (p = 0; p < olen; p++)
	{//
		if (out[p] != '0')
		{//
			break;
		}
		zeros++;
	}
	if (zeros > 0)
	{//
		if (zeros == olen)
		{//
			olen = 1;
			out[0] = '0';
			zeros -= 1;
		}
		else
		{
			olen -= zeros;
			for (p = 0; p < olen; p++)
			{//
				out[p] = out[p+zeros];
			}
		}
	}

	return zeros;
}

//小數部分相減str1-str2
//返回整數部分相加時需要的carry
int two_positive_fraction_minus(const char* str1, size_t len1,
															const char* str2, size_t len2,
															char* out, size_t& olen)
{
	olen = 0;
	int borrow = 0;
	size_t left = len1 < len2 ? len1 : len2; //取最短的那個的末尾
	size_t right = len1 > len2 ? len1 : len2; //取最長的那個的末尾
	const char* longer = len1  > len2 ? str1 : str2;
	olen = right;
	size_t p = olen-1;
	int a, b, res;

	if (longer == str2)
	{//短-長
		for (--left; --right != left;)
		{//
			a = 0 - borrow;
			b = longer[right] - '0';
			borrow = a < b;
			res = a+10*borrow - b;
			out[p--] = res + '0';
		}
	}
	else
	{//長-短
		for (--left; --right != left;)
		{//
			out[p--] = longer[right];
		}
	}

	for (; left != (size_t)-1; left--)
	{//
		a = str1[left] - '0' - borrow;
		b = str2[left] - '0';
		borrow = a < b;
		res = a+10*borrow - b;
		out[p--] = res + '0';
	}

	//把最後的0去掉
	p = olen-1;
	for (; p != (size_t)-1; p--)
	{//
		if (out[p] != '0')
		{//
			break;
		}
	}
	olen = p == (size_t)-1 ? 1 : p+1;
	return borrow;
}

//str1 > str2
void two_positive_minus(const char* str1, const char* str2, char* out)
{
	size_t dot_pos1 = find_dot(str1);
	size_t dot_pos2 = find_dot(str2);

	//計算小數部分
	int borrow = 0;
	size_t olen_fraction = 0;
	if (dot_pos1 < strlen(str1) || dot_pos2 < strlen(str2))
	{//
		char* fraction = out + dot_pos1;
		fraction[0] = '.';
		fraction++;
		size_t pos1 = dot_pos1 != strlen(str1) ? dot_pos1+1 : dot_pos1;
		size_t pos2 = dot_pos2 != strlen(str2) ? dot_pos2+1 : dot_pos2;
		borrow = two_positive_fraction_minus(str1+pos1, strlen(str1)-pos1,
			str2+pos2, strlen(str2)-pos2, fraction, olen_fraction);
	}

	//計算整數部分
	size_t olen_integer;
	int shift = two_positive_integer_minus(str1, dot_pos1, str2, dot_pos2, 
		out,  olen_integer, borrow);

	//左移小數部分
	if (shift > 0)
	{//
		size_t olen = olen_integer + olen_fraction + 1;
		for (size_t p = olen_integer; p < olen; p++)
		{// 
			out[p] = out[p+shift];
		}
	}
	out[olen_fraction + olen_integer + 1] = '\0';
}


//str1 > str2 ?
//str1和str2都是正數
const bool two_positive_is_larger(const char* str1, const char* str2)
{
	size_t dot_pos1 = find_dot(str1);
	size_t dot_pos2 = find_dot(str2);

	if (dot_pos1 > dot_pos2)
	{//12345 > 1234
		return true;
	}
	if (dot_pos1 < dot_pos2)
	{//123 < 3456
		return false;
	}

	//整數部分等長
	for (size_t ptr = 0; ptr != dot_pos1; ptr++)
	{//
		if (str1[ptr] != str2[ptr])
		{//
			if (str1[ptr] > str2[ptr])
			{//123456 > 122456
				return true;
			}
			//123456 < 124456
			return false;
		}
	}

	//整數部分相同,那麼比較小數部分
	size_t len1 = strlen(str1), len2 = strlen(str2);
	dot_pos1++, dot_pos2++;
	for (; dot_pos1 < len1 && dot_pos2 < len2; dot_pos1++, dot_pos2++)
	{//
		if (str1[dot_pos1] != str2[dot_pos2])
		{//
			if (str1[dot_pos1] > str2[dot_pos2])
			{//
				return true;
			}
			//
			return false;
		}
	}
	
	//前面的相等
	if (dot_pos2 < len1)
	{//str1的長度比較長,所以返回str1
		return false;
	}

	return true;
}

//假設str1和str2的輸入都符合要求,out有足夠的空間存儲
//str如果爲正,那麼開頭無符號,若爲負,則開頭需要有-號
void minu(const char* str1, const char* str2, char* out)
{
	bool neg = false;
	if (*str1 == '-' && *str2 == '-')
	{//|str2|-|str1|
		if (two_positive_is_larger(str1+1, str2+1))
		{//|str1|>|str2|,那麼由於是|str2|-|str1|,結果爲負
			two_positive_minus(str1+1, str2+1, out);
		}
		else
		{
			two_positive_minus(str2+1, str1+1, out);
		}
		return;
	}

	if (*str1 != '-' && *str2 != '-')
	{//|str1|-|str2|
		if (two_positive_is_larger(str1, str2))
		{//|str1|>|str2|,那麼由於是str1-str2,結果爲正
			two_positive_minus(str1, str2, out);
		}
		else
		{
			two_positive_minus(str2, str1, out);
		}
		return;
	}

	if (*str1 == '-' && *str2 != '-')
	{//-(|str1| + |str2|)
		two_positive_add(str1+1, str2, out);
		return;
	}

	if (*str1 != '-' && *str2 == '-')
	{//|str1| + |str2|
		two_positive_add(str1, str2+1, out);
		return;
	}
}

//假設str1和str2的輸入都符合要求,out有足夠的空間存儲
//str如果爲正,那麼開頭無符號,若爲負,則開頭需要有-號
void ad(const char* str1, const char* str2, char* out)
{
	bool neg = false;
	if (*str1 == '-' && *str2 != '-')
	{//|str2|-|str1|
		if (two_positive_is_larger(str1+1, str2))
		{//|str1|>|str2|,那麼由於是|str2|-|str1|,結果爲負
			two_positive_minus(str1+1, str2, out);
		}
		else
		{
			two_positive_minus(str2, str1+1, out);
		}

		return;
	}

	if (*str1 != '-' && *str2 == '-')
	{//|str1|-|str2|
		if (two_positive_is_larger(str1, str2+1))
		{//|str1|>|str2|,那麼由於是str1-str2,結果爲正
			two_positive_minus(str1, str2+1, out);
		}
		else
		{
			two_positive_minus(str2+1, str1, out);
		}
		return;
	}

	if (*str1 == '-' && *str2 == '-')
	{//-(|str1| + |str2|)
		two_positive_add(str1+1, str2+1, out);
		return;
	}

	if (*str1 != '-' && *str2 != '-')
	{//|str1| + |str2|
		two_positive_add(str1, str2, out);
		return;
	}
}

#endif


 

調用函數爲ad和minu,假設輸入都正確。

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