#include
#include
#include
#include
#define MAX 100
bool isLittleEndian()
{
int a = 0x01;
char *p = (char *)&a;
if(*p == 1)
{
printf("little endian\n");
return true;
}
else
{
printf("big endian\n");
return false;
}
}
float mul(float x,float y)
{
float result,*r;
double d;
int i;
short p = (short *)&x;
short *q = (short *)&y;
short s;
short s1 = *(p + 1);
short s2 = *(q + 1);
short s3 = ((s1 >> 15) ^ (s2 >> 15)) << 15; //符号位
short e1 = ((s1 << 1) >> 8) + ((s2 << 1) >> 8) - 127; //指数位
int m1 = s1 << 9 >> 9;
int m2 = s2 << 9 >> 9;
int m3; //尾数位
m1 = (m1 << 16) + (*p); //
m2 = (m2 << 16) + (*q);
d = m1 * m2;
p = (short *)&d;
s = ((((p + 3)) << 1 >> 5) - 22) << 4;
*(p + 3) &= 0x800f;
*(p + 3) |= s;
m3 = (int)d;
if(m3 & 1)
m3++;
m3 >>= 1;
// if(m3 >> 23)
// e1++;
e1 <<= 7;
i = e1 | s3;
i <<= 16;
i |= m3;
r = (float *)&i;
result = *r;
return result;
}
void main()
{
float x = 12.5;
float y = 4.4;
printf("result:%f\n",mul(x,y));
}
关键就是一直卡在尾数相乘上。
#include
#include
#include
#include
#define MAX 100
//内存大小端存储的判断
bool isLittleEndian()
{
int a = 0x01;
char *p = (char *)&a;
if(*p == 1)
{
printf("little endian\n");
return true;
}
else
{
printf("big endian\n");
return false;
}
}
//两个23位的二进制数据相乘,结果也为二进制
void binary_multiplication(int a[], int alen, int b[], int blen,int c[])
{
int i,j,t;
int carry = 0; //进位
for(i = blen-1; i >= 0; i--){
for(j = alen-1; j >= 0; j--){
t = c[i+j+1]; //临时变量赋值为c[i+j+1]
c[i+j+1] = (c[i+j+1] + b[i]*a[j] + carry) % 2; //给c[i+j]赋值
carry = (t + b[i]*a[j] + carry) / 2; //存放进位
}
c[i]=carry; //将当前最高位写上上一次加法中最后的进位
carry=0; //进位一定要在这里清零,不要带入到下一次的加法中去
}
}
//思想:根据浮点数在内存中的存储方式(32位:1符号位,8指数位,23尾数位)
//结果的符号位由两数的符号位异或得到,
//指数位由两数的指数位相加得到(为方便计算,浮点数的指数都是在其基础上加上127)
//尾数由两数的尾数相乘后进行舍入和溢出的处理
//double型数据的尾数有52位,需要64位机实现(我的32,so...)
float mul(float x,float y)
{
int a[24],b[24],c[48] = {0};
float result;
int i,j;
short *p = (short *)&x;
short *q = (short *)&y;
short s1 = *(p + 1);
short s2 = *(q + 1);
short s3 = ((s1 >> 15) ^ (s2 >> 15)) << 15; //符号位
short e1 = ((s1 << 1) >> 8) + ((s2 << 1) >> 8) - 127; //指数位
int m1 = s1 << 9 >> 9;
int m2 = s2 << 9 >> 9;
int m3 = 0; //尾数位
m1 = (m1 << 16) + (*p);
m2 = (m2 << 16) + (*q);
for(i = 23;i > 0;i--)
{
a[i] = m1 & 1;
b[i] = m2 & 1;
m1 >>= 1;
m2 >>= 1;
}
for(i = 23;i > 0;i--)
{
if(a[i])
break;
}
for(j = 23;j > 0;j--)
{
if(b[j])
break;
}
a[0] = b[0] = 1;
binary_multiplication(a,i,b,j,c);
if(c[0])
{
e1++;
for(i = 1;i < 24;i++)
m3 += (c[i] << (23 - i));
if(c[i])
m3++;
}
else
{
for(i = 2;i < 25;i++)
m3 += (c[i] << (24 - i));
if(c[i])
m3++;
}
e1 <<= 7;
i = e1 | s3;
i <<= 16;
i |= m3;
result = *((float *)&i);
return result;
}
void main()
{
float x = 8888.8f;
float y = 77777.85f;
printf("my result:%f\n",mul(x,y));
printf("correct result:%f\n",x * y);
}
不过还很是经不住考验,数值大一点,根本就无法使用了,大家可千万别借鉴。
在这里主要还是希望能吸引到哪位大神能帮我更好的实现,,,
期待大神光临。。。
自开自结,再也不来这鬼地方了,,,
#include
#include
#include
#include
#define MAX 100
//内存大小端存储的判断
int isLittleEndian()
{
int a = 0x01;
char *p = (char *)&a;
if(*p == 1)
{
printf("little endian\n");
return 1;
}
else
{
printf("big endian\n");
return 0;
}
}
//两个23位的二进制数据相乘,结果也为二进制
void binary_multiplication(char a[], int alen, char b[], int blen,char c[])
{
int i,j,t;
int carry = 0; //进位
for(i = blen-1; i >= 0; i--)
{
for(j = alen-1; j >= 0; j--)
{
t = c[i+j+1]; //临时变量赋值为c[i+j+1]
c[i+j+1] = (c[i+j+1] + b[i]*a[j] + carry) % 2; //给c[i+j]赋值
carry = (t + b[i]*a[j] + carry) / 2; //存放进位
}
c[i]=carry; //将当前最高位写上上一次加法中最后的进位
carry=0; //进位一定要在这里清零,不要带入到下一次的加法中去
}
}
float mul(float x,float y)
{
char a[24],b[24],c[48] = {0};
float result;
int p = *((int *)&x);
int q = *((int *)&y);
int s = (p >> 31) ^ (q >> 31); //符号位
int e = ((p << 1) >> 24) + ((q << 1) >> 24) - 127; //指数位
int m = 0; //尾数位
int i;
if(x <= 1.0e-6 && x >= -1.0e-6) //如果乘数中有0.0,则返回结果0.0
return 0.0;
if(y <= 1.0e-6 && y >= -1.0e-6)
return 0.0;
for(i = 23;i > 0;i--) //读取23位尾数,下标从1~23分别是尾数从高到低的二进制位
{
a[i] = p & 1;
b[i] = q & 1;
p >>= 1;
q >>= 1;
}
a[0] = b[0] = 1; //加上尾数部分隐含的“1”(1.xxx)
binary_multiplication(a,24,b,24,c);
//尾数乘积溢出和舍入的处理
if(c[0]) //若结果溢出,则将该位作为隐含的“1”
{
e++; //指数加一
for(i = 1;i < 24;i++) //从隐含的“1”后面取23位作为结果的尾数
m += (c[i] << (23 - i));
if(c[i]) //舍入处理
m++;
}
else //若结果为溢出
{ //则c[1]必为1,将该位作为隐含的“1”
for(i = 2;i < 25;i++)
m += (c[i] << (24 - i));
if(c[i])
m++;
}
if(e >= 256)
{
if(e < (256 + 128))
printf("结果上溢( --> ∞)!!!\n");
else
printf("结果下溢( --> 0.0)!!!\n");
return 0.0;
}
i = (e << 23) | (s << 31) | (m); //符号位,指数位,尾数位合并
result = *((float *)&i);
return result;
}
void main()
{
float x = -65711.07f;
float y = 86111.013f;
float z = x * y;
printf("my result:%f\n",mul(x,y));
printf("correct result:x * y = %f\n",x * y);
printf("correct result:z = %f\n",z);
}
呼,,今天差点把最终成果给删了,还是放这里安全,,,
#include
#include
#include
#include
#define MAX 100
double add(double x,double y)
{
double result;
int i;
int64 Int_result;
__int64 p = *((int64 *)&x);
int64 q = *((int64 *)&y);
__int64 s1 = (p >> 63) & 1;
__int64 s2 = (q >> 63) & 1;
__int64 s;
__int64 e1 = (p >> 52) & 0x7ff;
__int64 e2 = (q >> 52) & 0x7ff;
__int64 e;
__int64 m1 = p & 0xfffffffffffff;
__int64 m2 = q & 0xfffffffffffff;
__int64 m;
if(x < 1.0e-6 && x > -1.0e-6)
return y;
if(y < 1.0e-6 && y > -1.0e-6)
return x;
m1 |= 0x10000000000000;
m2 |= 0x10000000000000;
if(e1 > e2) //对阶
{
e = e1;
for(i = 1;i < (e1 - e2);i++)
m2 >>= 1;
if(m2 & 1)
m2++;
m2 >>= 1;
}
else if(e2 > e1)
{
e = e2;
for(i = 1;i < (e2 - e1);i++)
m1 >>= 1;
if(m1 & 1)
m1++;
m1 >>= 1;
}
else
e = e1;
if((s1 ^ s2) == 0) //两数同号则尾数相加
{
s = s1;
m = m1 + m2;
if(m >> 53)
{
e++;
if(m & 1)
m++;
m >>= 1;
}
}
else //两数异号则尾数相减
{
if(m1 >= m2) //确保大数减小数
{
s = s1; //结果的符号位与大数相同
if(m1 == m2)
return 0.0;
else
m = m1 - m2;
}
else
{
s = s2;
m = m2 - m1;
}
while((m >> 52) == 0) //尾数结果规格化
{
e--;
m <<= 1;
}
}
if(e >> 11)
{
if((e >> 10) & 1)
printf("结果上溢( --> ∞)!!!\n");
else
printf("结果下溢( --> 0.0)!!!\n");
return 0.0;
}
m &= 0xfffffffffffff;
Int_result = (s << 63) | (e << 52) | m;
result = *((double *)&Int_result);
return result;
}
//x是被减数
double sub(double x,double y)
{
int64 *q = (int64 *)&y;
*q ^= 0x8000000000000000; //减数符号位取反后两数相加
y = *((double *)q);
return add(x,y);
}
//两个二进制数据相乘,结果也为二进制
void binary_multiplication(char a[], int alen, char b[], int blen,char c[])
{
int i,j,t;
int carry = 0; //进位
for(i = blen-1; i >= 0; i--)
{
for(j = alen-1; j >= 0; j--)
{
t = c[i+j+1];
c[i+j+1] = (c[i+j+1] + b[i]*a[j] + carry) % 2;
carry = (t + b[i]*a[j] + carry) / 2; //存放进位
}
c[i]=carry; //将当前最高位写上上一次加法中最后的进位
carry=0; //进位一定要在这里清零,不要带入到下一次的加法中去
}
}
double mul(double x,double y)
{
int i;
char a[53],b[53],c[106] = {0};
int64 p = *((int64 *)&x);
int64 q = *((int64 *)&y);
__int64 s = ((p >> 63) & 1) ^ ((q >> 63) & 1); //符号位
__int64 e = ((p >> 52) & 0x7ff) + ((q >> 52) & 0x7ff) - 1023; //指数位
__int64 m = 0,m1; //尾数位
__int64 Int_result;
double result;
if(x < 1.0e-6 && x > -1.0e-6) //如果乘数中有0.0,则返回结果0.0
return 0.0;
if(y < 1.0e-6 && y > -1.0e-6)
return 0.0;
for(i = 52;i > 0;i--) //读取52位尾数,下标从1~52分别是尾数从高到低的二进制位
{
a[i] = p & 1;
b[i] = q & 1;
p >>= 1;
q >>= 1;
}
a[0] = b[0] = 1; //加上尾数部分隐含的“1”(1.xxx)
binary_multiplication(a,53,b,53,c);
//尾数乘积溢出和舍入的处理
if(c[0] == 1) //若结果溢出,则将该位作为隐含的“1”
{
e++; //指数加一
for(i = 1;i < 53;i++) //从隐含的“1”后面取52位作为结果的尾数
if(c[i] == 1)
{
m1 = c[i];
m += (m1 << (52 - i));
}
if(c[i] == 1) //舍入处理
m++;
}
else //若结果未溢出
{ //则c[1]必为1,将该位作为隐含的“1”
for(i = 2;i < 54;i++) //从隐含的“1”后面取52位作为结果的尾数
if(c[i] == 1)
{
m1 = c[i];
m += (m1 << (53 - i));
}
if(c[i] == 1) //舍入处理
m++;
}
if(e >> 11)
{
if((e >> 10) & 1)
printf("结果上溢( --> ∞)!!!\n");
else
printf("结果下溢( --> 0.0)!!!\n");
return 0.0;
}
Int_result = (s << 63) | (e << 52) | m;
result = *((double *)&Int_result);
return result;
}
//x是被除数
double division(double x,double y)
{
int i;
int64 p = *((int64 *)&x);
int64 q = *((int64 *)&y);
__int64 s = ((p >> 63) & 1) ^ ((q >> 63) & 1); //符号位
__int64 e = ((p >> 52) & 0x7ff) - ((q >> 52) & 0x7ff) + 1023; //指数位
__int64 m1 = (p & 0xfffffffffffff) | 0x10000000000000;
__int64 m2 = (q & 0xfffffffffffff) | 0x10000000000000;
__int64 m = 0; //尾数位
__int64 Int_result;
double result;
if(x < 1.0e-6 && x > -1.0e-6)
return 0.0;
if(y < 1.0e-6 && y > -1.0e-6)
{
printf("除数为0,无法计算!!!\n");
return 0.0;
}
if(m1 < m2)
{
e--;
m1 <<= 1;
}
m1 -= m2;
for(i = 1;i < 53;) //取52位尾数相除的商
{
if(m1 >= m2) //两数相减可为正
{
m += 1; //则可商1
if(m1 == m2) //若两相减的数相等,则说明可整除,
{
m <<= (52 - i); //商已得出,移到正确的位置
break;
}
m1 -= m2; //取商1后的结果
}
else
{
m1 <<= 1; //否则被除数左移1位
m <<= 1; //商0左移一位
i++;
}
}
//循环正常做完,即取到52位商后,若第53位的商能商1,则结果商再加1舍入第53位的商
if(m1 >= m2)
m++;
if(e >> 11)
{
if((e >> 10) & 1)
printf("结果上溢( --> ∞)!!!\n");
else
printf("结果下溢( --> 0.0)!!!\n");
return 0.0;
}
Int_result = (s << 63) | (e << 52) | m;
result = *((double *)&Int_result);
return result;
}
void main()
{
double x = 132464.3146;
double y = -185543.565;
printf("my result:\tx + y = %f\n",add(x,y));
printf("correct result:\tx + y = %f\n",x + y);
printf("my result:\tx - y = %f\n",sub(x,y));
printf("correct result:\tx - y = %f\n",x - y);
printf("my result:\tx * y = %f\n",mul(x,y));
printf("correct result:\tx * y = %f\n",x * y);
printf("my result:\tx / y = %f\n",division(x,y));
printf("correct result:\tx / y = %f\n",x / y);
}