这学期在学计组,这里将用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;
}
输出: