定点小数原码一位乘(C++实现)

这学期在学计组,这里将用C++实现各种运算方法,其实那些算法应该是用电路硬件实现的,用高级语言来描述一遍也挺有意义。

说明:输入输出的小数均以机器数表示,数值位为4位。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <bitset>
#include <string>
using namespace std;

void RightMove(bitset<6> &a, bitset<4> &b)		// a,b联合右移
{
	b >>= 1;						
	b[3] = a[0];
	a >>= 1;
}

bitset<6> operator+(bitset<6> a, bitset<4> b)	// 求a,b的算术和
{
	unsigned long long sum = a.to_ulong() + b.to_ulong();
	//bitset<6> temp(sum);
	//return temp;
	return sum;	// 调用了构造函数,待深究
}

int main(int argc, char **argv)
{
	string inputStr;
	while (cin >> inputStr)
	{
		const bitset<5> X(inputStr);		// X是被乘数
		const bool x0 = X[4];				// x0是X的符号位
		const bitset<4> B(inputStr, 1, 4);	// B是被乘数的绝对值

		cin >> inputStr;
		const bitset<5> Y(inputStr);		// Y是乘数
		const bool y0 = Y[4];				// y0是Y的符号位
		bitset<4> C(inputStr, 1, 4);		// C是乘数的绝对值

#pragma region 核心算法

		bitset<6> A;						// A存放积(部分积)
		int cd = 4;							// cd是计数器
		while (cd--)
		{
			if (C[0])
			{
				A = A + B;					// 算术加
			}
			RightMove(A, C);				// A,C联合右移
		}
		A[4] = x0 ^ y0;

#pragma endregion 核心算法

		cout << X << " * " << Y << " = "
			<< A.to_string().substr(1)		// 为了不输出A附加的符号位
			<< C << endl;
	}

	return 0;
}

运行结果:

之前用的是C来写,位运算太麻烦了,见下面的程序:

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

void RightMove(int *pHigh, int *pLow)
{
	(*pLow) >>= 1;
	(*pLow) |= (*pHigh & 1) << 3;	// 3为n-1
	// *pLow右移进来的最高位一定是0
	// 将low的高位置为high的低位(0|x)

	(*pHigh) >>= 1;
}

void SetSign(int *num, int a, int b)
{
	if (a ^ b)
	{
		*num |= 1 << 4;
	}
	else
	{
		*num &= ~(1 << 4);
	}
}

void Print(char *XStr, char *YStr, int A, int C)
{
	int i;
	char AStr[10];
	char CStr[10];
	_itoa(A, AStr, 2);
	_itoa(C, CStr, 2);
	printf("%s * %s = ", XStr, YStr);

	for (i = strlen(AStr); i < 5; i++)
	{
		printf("0");
	}
	printf("%s", AStr);

	for (i = strlen(CStr); i < 4; i++)
	{
		printf("0");
	}
	printf("%s\n", CStr);
}

int main(int argc, char **argv)
{
	int X = 0;		// X是被乘数
	int x0 = 0;		// x0是X的符号位
	int B = 0;		// B是被乘数的绝对值

	int Y = 0;		// Y是乘数
	int y0 = 0;		// y0是Y的符号位
	int C = 0;		// C是乘数的绝对值

	int cd = 4;		// cd是计数器
	int A = 0;		// A存放积(部分积)

	char XStr[10];
	char YStr[10];

	while (EOF != scanf("%s", XStr))	// 二进制输入
	{
		X = (int)strtol(XStr, NULL, 2);
		x0 = XStr[0] - '0';
		B = X & (~(1 << cd));			// 取绝对值,即将符号位置为0(x&0)

		scanf("%s", YStr);				// 二进制输入
		Y = (int)strtol(YStr, NULL, 2);
		y0 = YStr[0] - '0';
		C = Y & (~(1 << cd));

#pragma region 核心算法

		A = 0;	// 注意初始化
		cd = 4;
		while (cd--)
		{
			if (C & 1)
			{
				A += B;
			}
			RightMove(&A, &C);	// A、C联合右移
		}
		SetSign(&A, x0, y0);

#pragma endregion 核心算法

		Print(XStr, YStr, A, C);
		//printf("%s * %s = %s%s\n", XStr, YStr, _itoa(A, buffer, 2), _itoa(C, buffer, 2));
		//从后向前压栈,最后算完才一起输出,输出将覆盖
	}

	return 0;
}

而C++的bitset类正好用于位的操作,很方便,在这个过程中,我也发现了bitset的不足,比如VS2010中bitset不能用unsigned long来初始化(没有相应的构造函数)。还有,为什么说复制构造函数、重载赋值运算符、析构函数要么都写,要么都别写呢?因为既然可以用一个对象来复制构造,那当然也适用于赋值操作,这是我的个人理解,甚至我认为把所有的构造函数的参数都最好拿来重载到赋值运算符,这是有需求的。


2012/10/17

把代码的结构方面改进了,更方便阅读。

// 定点小数源码一位乘
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <bitset>
#include <string>
using namespace std;

const int n = 4;	// 数值位位数

void RightMove(bitset<n + 2> &a, bitset<n> &b)		// a,b联合右移
{
	b >>= 1;						
	b[n - 1] = a[0];
	a >>= 1;
}

bitset<n + 2> operator+(bitset<n + 2> a, bitset<n> b)	// 求a,b的算术和
{
	unsigned long long sum = a.to_ulong() + b.to_ulong();
	//bitset<6> temp(sum);
	//return temp;
	return sum;	// 调用了构造函数,待深究
}

bitset<2 * n + 1> TrueformOneMul(const bitset<n + 1> X, const bitset<n + 1> Y)
{
	bitset<n + 2> A;					// A放部分积(最后是积的高位)
	const bool x0 = X[n];				// x0是X的符号位
	const bitset<n> B(X.to_ullong());	//截断符号位,B是被乘数的绝对值,其实也可以是n+2位(高两位始终为0)
	const bool y0 = Y[n];				// y0是Y的符号位
	bitset<n> C = Y.to_ullong();		//截断符号位,C是乘数的绝对值(最后是积的低位)
	int cd = n;							// cd是计数器					

#pragma region 核心算法

	while (cd--)
	{
		if (C[0])
		{
			A = A + B;					// 算术加
		}
		RightMove(A, C);				// A,C联合右移
	}
	A[n] = x0 ^ y0;

#pragma endregion 核心算法

	bitset<2 * n + 1> tmp(A.to_string().substr(1) + C.to_string());
	return tmp;
	// 不能直接return!Shit!没有相应的复制构造函数?
}

bitset<2 * n + 1> DirectMul(const bitset<n + 1> X, const bitset<n + 1> Y)
{
	const bitset<n> x(X.to_ullong());
	const bitset<n> y(Y.to_ullong());
	bitset<2 * n + 1> ans(x.to_ullong() * y.to_ullong());
	ans[2 * n] = X[n] ^ Y[n];
	return ans;
}

int main(int argc, char **argv)
{
	string inputStrX;
	string inputStrY;
	while (cin >> inputStrX >> inputStrY)
	{
		const bitset<n + 1> X(inputStrX);	// X是被乘数
		const bitset<n + 1> Y(inputStrY);	// Y是乘数
		
		cout << "TrueformOneMul:\t" << X << " * " << Y << " = "
			<< TrueformOneMul(X, Y) << endl;
		cout << "DirectMul:\t" << X << " * " << Y << " = "
			<< DirectMul(X, Y) << endl << endl;
	}

	return 0;
}

输出:

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值