128位乘除法怎么算?

xufeng0218 2012-06-29 04:15:43
各位大大好,小弟现在写的是嵌入式程序,我的开发软件最大只支持64位数据(long long int),可是现在计算的量已经超过这个值了,哪位大大能教教小弟怎么算128位的啊?我的开发环境数据位是这样的(char 8位、short 16位、long 32位、long long 64位)。小弟的分不多,还望见谅,先谢过了啊!
我要算的公式是这样的:
Z=a*X+(1-a)Y;a=128/(t+128);t是在10 000到30 000 000之间变化的,运算过程中不用浮点数。
...全文
680 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
libralibra 2012-06-29
  • 打赏
  • 举报
回复
就用大数乘法,1楼那个竖式方法,
我也实现了一个,为了做题acm的,抠出来2个函数给你用

// 也可以用来计算任意长度整数/小数乘法,直接调用 string stringMul(string a, string b) 即可

#include <iostream>
#include <string>
using namespace std;

// 开关,是否显示竖式乘法运算步骤
#define __MYDEBUG__ 1

// 整理字符串,如果有小数点,去除右边多余0,如果没有,去除左边多余0
// 返回小数位数*pos
string cleanUp(string s,int *pos)
{
string result = s;

size_t lpos,rpos,ppos;
ppos = s.find(".");
lpos = s.find_first_not_of("0");
rpos = s.find_last_not_of("0");

// 无小数点
if (ppos==string::npos)
{
*pos = 0;
if (lpos==string::npos) result = "0";
else result = s.substr(lpos);
}
else
{
if (rpos==ppos) // 最右非0位是小数点,无小数位
{
*pos = 0;
if (lpos==ppos) // 如果最左非0也是小数点,是0.0
{
result = "0";
}
else // 否则是01.000类
{
result = s.substr(lpos,ppos-lpos);
}
}
else // 有小数位
{
*pos = rpos-ppos;
if (lpos==ppos) // 最左非0是小数点,截取小数点后部分继续判断最左非0位,0.0100类
{
result = s.substr(ppos+1,rpos-ppos);
lpos = result.find_first_not_of("0");
result = result.substr(lpos,rpos-lpos+1);
}
else // 否则直接拼接小数点左右部分,01.0100类
{
result = s.substr(lpos,ppos-lpos)+s.substr(ppos+1,rpos-ppos);
}
}
}

return result;
}

// 字符串表示的大数相乘
string stringMul(string a, string b)
{
int lena = a.size(); // a长度
int lenb = b.size(); // b长度
int pos = 0; // 错位数

int curmul = 0, // 当前计算结果
carry = 0, // 进位
curnum = 0; // 当前位数字. 关系: 当前计算结果=进位*10+当前位数字

// 最终计算结果结果肯定小于2个字符串长度之和
// 证明:长度为lena和lenb的2个数,最大可表示为10^lena-1和10^lenb-1
// (10^lena-1)*(10^lenb-1) = 10^(lena+lenb)-10^lena-10^lenb+1 < 10^(lena+lenb),证毕.
string result = "";
result.insert(result.begin(),lena+lenb,'0');
string tempresult = "";
string current = "";

#if (__MYDEBUG__)
int wid = 40;
char fm[20];
sprintf(fm,"%%%ds\n",wid);
printf(fm,a.c_str());
sprintf(fm,"* %%%ds\n",wid-2);
printf(fm,b.c_str());
printf("-----------------------------------------\n");
#endif

for (int i=lenb-1;i>=0;i--)
{
current = ""; // 当前字符串
carry = 0; // 进位
curnum = 0; // 要添加的字符

if ((int)(b[i]-'0')==0)
{
#if (__MYDEBUG__)
sprintf(fm,"%%%ds\n",wid-pos);
printf(fm,"0");
#endif
pos++;
continue;
}

for (int j=lena-1;j>=0;j--)
{
curmul = (int)(b[i]-'0')*(int)(a[j]-'0')+carry;
carry = curmul/10;
curnum = curmul%10;
current.insert(current.begin(),1,(char)(curnum+'0'));
}

// 处理最后进位
while (carry>0)
{
current.insert(current.begin(),1,(char)(carry%10+'0'));
carry /= 10;
}

#if (__MYDEBUG__)
sprintf(fm,"%%%ds\n",wid-pos);
printf(fm,current.c_str());
#endif
// 添加给当前结果
if(result.empty())
{
result = current;
}
else // 错位相加
{
tempresult = "";
curmul = 0;
carry = 0;
curnum = 0;
for (int i=(int)current.size()-1,j=(int)result.size()-1-pos;i>=0&&j>=0;i--,j--)
{
curmul = (int)(result[j]-'0')+(int)(current[i]-'0')+carry;
carry = curmul/10;
curnum = curmul%10;
tempresult.insert(tempresult.begin(),1,(char)(curnum+'0'));
}

// 处理剩余的字符
while (carry>0)
{
tempresult.insert(tempresult.begin(),1,(char)(carry%10+'0'));
carry /= 10;
}

// 添加给结果
result.replace((int)result.size()-(int)tempresult.size()-pos,(int)tempresult.size(),tempresult);
}

// 错位+1
pos++;
}

// 清理结果
int dummy = 0;
result = cleanUp(result,&dummy);

#if (__MYDEBUG__)
printf("-----------------------------------------\n");
sprintf(fm,"%%%ds\n",wid);
printf(fm,result.c_str());
#endif

return result;
}


jackyjkchen 2012-06-29
  • 打赏
  • 举报
回复
固定位数,位数不大,且为32或64的整数倍的,不要随便用任意长度大数运算(数组实现的),效率会比较低
jackyjkchen 2012-06-29
  • 打赏
  • 举报
回复
假设A、B、C、D都是64位整数,AB、CD组合成128位整数

AB * CD = (A0 + 0B) * (C0 + 0D)
=A0 * C0 + A0 * 0D + 0B * C0 + 0B * 0D

这里的0代表64位0
A0 * C0大于2^64,舍去
0B * 0D就是一个普通的64位之内的乘法,完全保留
A0 * 0D + 0B * C0的低32位全0,实际上你需要做的就是保留A * D和B * C的低32位,再逻辑左移32位

一个128位乘法,可化为3个64位乘法,2个64位逻辑左移和2个64位加法
阿发你好 2012-06-29
  • 打赏
  • 举报
回复
软浮点支持
酱油党 2012-06-29
  • 打赏
  • 举报
回复
呵呵,用数组表示吧!~
xufeng0218 2012-06-29
  • 打赏
  • 举报
回复
小弟一定仔细学学小学数学,谢谢啦,先看看,研究一下
赵4老师 2012-06-29
  • 打赏
  • 举报
回复
算法参考小学三年级乘除法竖式。(^_^)
仅供参考:
#include <iostream>
#include <string>
using namespace std;
inline int compare(string str1,string str2) {//相等返回0,大于返回1,小于返回-1
if (str1.size()>str2.size()) return 1; //长度长的整数大于长度小的整数
else if (str1.size()<str2.size()) return -1;
else return str1.compare(str2); //若长度相等,则头到尾按位比较
}
string SUB_INT(string str1,string str2);
string ADD_INT(string str1,string str2) {//高精度加法
int sign=1; //sign 为符号位
string str;
if (str1[0]=='-') {
if (str2[0]=='-') {
sign=-1;
str=ADD_INT(str1.erase(0,1),str2.erase(0,1));
} else {
str=SUB_INT(str2,str1.erase(0,1));
}
} else {
if (str2[0]=='-') {
str=SUB_INT(str1,str2.erase(0,1));
} else { //把两个整数对齐,短整数前面加0补齐
string::size_type L1,L2;
int i;
L1=str1.size();
L2=str2.size();
if (L1<L2) {
for (i=1;i<=L2-L1;i++) str1="0"+str1;
} else {
for (i=1;i<=L1-L2;i++) str2="0"+str2;
}
int int1=0,int2=0; //int2 记录进位
for (i=str1.size()-1;i>=0;i--) {
int1=(int(str1[i])-'0'+int(str2[i])-'0'+int2)%10;
int2=(int(str1[i])-'0'+int(str2[i])-'0'+int2)/10;
str=char(int1+'0')+str;
}
if (int2!=0) str=char(int2+'0')+str;
}
}
//运算后处理符号位
if ((sign==-1)&&(str[0]!='0')) str="-"+str;
return str;
}
string SUB_INT(string str1,string str2) {//高精度减法
int sign=1; //sign 为符号位
string str;
int i,j;
if (str2[0]=='-') {
str=ADD_INT(str1,str2.erase(0,1));
} else {
int res=compare(str1,str2);
if (res==0) return "0";
if (res<0) {
sign=-1;
string temp =str1;
str1=str2;
str2=temp;
}
string::size_type tempint;
tempint=str1.size()-str2.size();
for (i=str2.size()-1;i>=0;i--) {
if (str1[i+tempint]<str2[i]) {
j=1;
while (1) {//zhao4zhong1添加
if (str1[i+tempint-j]=='0') {
str1[i+tempint-j]='9';
j++;
} else {
str1[i+tempint-j]=char(int(str1[i+tempint-j])-1);
break;
}
}
str=char(str1[i+tempint]-str2[i]+':')+str;
} else {
str=char(str1[i+tempint]-str2[i]+'0')+str;
}
}
for (i=tempint-1;i>=0;i--) str=str1[i]+str;
}
//去除结果中多余的前导0
str.erase(0,str.find_first_not_of('0'));
if (str.empty()) str="0";
if ((sign==-1) && (str[0]!='0')) str ="-"+str;
return str;
}
string MUL_INT(string str1,string str2) {//高精度乘法
int sign=1; //sign 为符号位
string str;
if (str1[0]=='-') {
sign*=-1;
str1 =str1.erase(0,1);
}
if (str2[0]=='-') {
sign*=-1;
str2 =str2.erase(0,1);
}
int i,j;
string::size_type L1,L2;
L1=str1.size();
L2=str2.size();
for (i=L2-1;i>=0;i--) { //模拟手工乘法竖式
string tempstr;
int int1=0,int2=0,int3=int(str2[i])-'0';
if (int3!=0) {
for (j=1;j<=(int)(L2-1-i);j++) tempstr="0"+tempstr;
for (j=L1-1;j>=0;j--) {
int1=(int3*(int(str1[j])-'0')+int2)%10;
int2=(int3*(int(str1[j])-'0')+int2)/10;
tempstr=char(int1+'0')+tempstr;
}
if (int2!=0) tempstr=char(int2+'0')+tempstr;
}
str=ADD_INT(str,tempstr);
}
//去除结果中的前导0
str.erase(0,str.find_first_not_of('0'));
if (str.empty()) str="0";
if ((sign==-1) && (str[0]!='0')) str="-"+str;
return str;
}
string DIVIDE_INT(string str1,string str2,int flag) {//高精度除法。flag==1时,返回商; flag==0时,返回余数
string quotient,residue; //定义商和余数
int sign1=1,sign2=1;
if (str2 == "0") { //判断除数是否为0
quotient= "ERROR!";
residue = "ERROR!";
if (flag==1) return quotient;
else return residue ;
}
if (str1=="0") { //判断被除数是否为0
quotient="0";
residue ="0";
}
if (str1[0]=='-') {
str1 = str1.erase(0,1);
sign1 *= -1;
sign2 = -1;
}
if (str2[0]=='-') {
str2 = str2.erase(0,1);
sign1 *= -1;
}
int res=compare(str1,str2);
if (res<0) {
quotient="0";
residue =str1;
} else if (res == 0) {
quotient="1";
residue ="0";
} else {
string::size_type L1,L2;
L1=str1.size();
L2=str2.size();
string tempstr;
tempstr.append(str1,0,L2-1);
for (int i=L2-1;i<L1;i++) { //模拟手工除法竖式
tempstr=tempstr+str1[i];
tempstr.erase(0,tempstr.find_first_not_of('0'));//zhao4zhong1添加
if (tempstr.empty()) tempstr="0";//zhao4zhong1添加
for (char ch='9';ch>='0';ch--) { //试商
string str;
str=str+ch;
if (compare(MUL_INT(str2,str),tempstr)<=0) {
quotient=quotient+ch;
tempstr =SUB_INT(tempstr,MUL_INT(str2,str));
break;
}
}
}
residue=tempstr;
}
//去除结果中的前导0
quotient.erase(0,quotient.find_first_not_of('0'));
if (quotient.empty()) quotient="0";
if ((sign1==-1)&&(quotient[0]!='0')) quotient="-"+quotient;
if ((sign2==-1)&&(residue [0]!='0')) residue ="-"+residue ;
if (flag==1) return quotient;
else return residue ;
}
string DIV_INT(string str1,string str2) {//高精度除法,返回商
return DIVIDE_INT(str1,str2,1);
}
string MOD_INT(string str1,string str2) {//高精度除法,返回余数
return DIVIDE_INT(str1,str2,0);
}
int main() {
char ch;
string s1,s2,res;

while (cin>>s1>>ch>>s2) {
switch (ch) {
case '+':res=ADD_INT(s1,s2);break;
case '-':res=SUB_INT(s1,s2);break;
case '*':res=MUL_INT(s1,s2);break;
case '/':res=DIV_INT(s1,s2);break;
case '%':res=MOD_INT(s1,s2);break;
default : break;
}
cout<<res<<endl;
}
return(0);
}

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧