/*
FPU Multiplier
M48 처리하는 새 알고리즘 적용
*/
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
// #define VERBOSE
#define RANDOM
#define ULL unsigned long long
int called = 0;
struct float16{ // 1 5 10
union{
struct{
unsigned short sign : 1;
unsigned short exponent : 5;
unsigned short mantissa : 10;
};
unsigned short total;
};
};
struct float32{ // 1 8 23
union{
struct{
unsigned int mantissa : 23;
unsigned short exponent : 8;
unsigned short sign : 1;
};
float total;
int total_int;
};
};
/* When first call, put depth := 1
*
*/
void print_binary_rec(unsigned long long foo, unsigned long long depth)
{
int ret;
if(foo) {
print_binary_rec((unsigned long long)foo>>1, depth+1);
if(depth%4) printf("%llu",foo&1);
else printf("_%llu",foo&1);
}
}
void print_binary(unsigned long long foo)
{
// printf("foo = %d %f\n", foo.total_int, foo.total);
if(foo == 0)
printf("0");
else
print_binary_rec(foo,1);
}
void float32_printer(struct float32 f32, char* name)
{
printf("%s: %f\n",name, f32.total);
printf("%s.sign: ", name);
print_binary(f32.sign); printf("\n");
printf("%s.exponent(%d): ", name, f32.exponent);
print_binary(f32.exponent); printf("\n");
printf("%s.mantissa: ", name);
print_binary(f32.mantissa); printf("\n");
printf("%s.total(%f): ", name, f32.total);
print_binary(f32.total_int); printf("\n");
}
struct float32 norm;
struct float32 pos_infinity;
struct float32 neg_infinity;
struct float32 pos_not_a_number;
struct float32 neg_not_a_number;
struct float32 pos_zero;
struct float32 neg_zero;
struct float32 f32_arr[9];
void edge_test(int a, int b){
struct float32 tmp;
tmp.total = f32_arr[a].total + f32_arr[b].total;
char name[20];
sprintf(name, "result %d: %d >>> ", a, b);
float32_printer(tmp, name);
printf("\n");
if(b==6){
if(a==6){
return;
}
else
edge_test(a+1,0);
}
else
edge_test(a,b+1);
}
void edge_setting(){
struct float32 f32;
f32.total = 0.75;
float32_printer(f32, "f32");
printf("\n");
f32.exponent = f32.exponent - 1;
float32_printer(f32, "f32");
printf("\n");
pos_infinity.sign = 0;
pos_infinity.exponent = 0b11111111;
pos_infinity.mantissa = 0;
float32_printer(pos_infinity, "pos_infinity");
printf("\n");
neg_infinity.sign = 1;
neg_infinity.exponent = 0b11111111;
neg_infinity.mantissa = 0;
float32_printer(neg_infinity, "neg_infinity");
printf("\n");
pos_not_a_number.sign = 0;
pos_not_a_number.exponent = 0b11111111;
pos_not_a_number.mantissa = 0b1111111111111111111;
float32_printer(pos_not_a_number, "pos_not_a_number");
printf("\n");
neg_not_a_number.sign = 1;
neg_not_a_number.exponent = 0b11111111;
neg_not_a_number.mantissa = 0b1111111111111111111;
float32_printer(neg_not_a_number, "neg_not_a_number");
printf("\n");
pos_zero.sign = 0;
pos_zero.exponent = 0;
pos_zero.mantissa = 0;
float32_printer(pos_zero, "pos_zero");
printf("\n");
neg_zero.sign = 1;
neg_zero.exponent = 0;
neg_zero.mantissa = 0;
float32_printer(neg_zero, "neg_zero");
printf("\n");
norm.total = 0.5;
f32_arr[0] = norm;
f32_arr[1] = pos_infinity;
f32_arr[2] = neg_infinity;
f32_arr[3] = pos_not_a_number;
f32_arr[4] = neg_not_a_number;
f32_arr[5] = pos_zero;
f32_arr[6] = neg_zero;
}
int leading_1_detector(int tmp)
{
if(tmp & 1<<23){
return 0;
}else if(tmp & 1<<22){
return 1;
}else if(tmp & 1<<21){
return 2;
}else if(tmp & 1<<20){
return 3;
}else if(tmp & 0b00000000000010000000000000000000){
return 4;
}else if(tmp & 0b00000000000001000000000000000000){
return 5;
}else if(tmp & 0b00000000000000100000000000000000){
return 6;
}else if(tmp & 0b00000000000000010000000000000000){
return 7;
}else if(tmp & 0b00000000000000001000000000000000){
return 8;
}else if(tmp & 0b00000000000000000100000000000000){
return 9;
}else if(tmp & 0b00000000000000000010000000000000){
return 10;
}else if(tmp & 0b00000000000000000001000000000000){
return 11;
}else if(tmp & 0b00000000000000000000100000000000){
return 12;
}else if(tmp & 0b00000000000000000000010000000000){
return 13;
}else if(tmp & 0b00000000000000000000001000000000){
return 14;
}else if(tmp & 0b00000000000000000000000100000000){
return 15;
}else if(tmp & 0b00000000000000000000000010000000){
return 16;
}else if(tmp & 0b00000000000000000000000001000000){
return 17;
}else if(tmp & 0b00000000000000000000000000100000){
return 18;
}else if(tmp & 0b00000000000000000000000000010000){
return 19;
}else if(tmp & 0b00000000000000000000000000001000){
return 20;
}else if(tmp & 0b00000000000000000000000000000100){
return 21;
}else if(tmp & 0b00000000000000000000000000000010){
return 22;
}else if(tmp & 0b00000000000000000000000000000001){
return 23;
}else{
return 0;
}
}
int leading_1_detector_48bit(unsigned long long tmp){
if(tmp & (unsigned long long)1<<47){
return 47; // "leading 1 is at 47th bit"
}
else if(tmp & (unsigned long long)1<<46){
return 46;
}
else if(tmp & (unsigned long long)1<<45){
return 45;
}
else if(tmp & (unsigned long long)1<<44){
return 44;
}
else if(tmp & (unsigned long long)1<<43){
return 43;
}
else if(tmp & (unsigned long long)1<<42){
return 42;
}
else if(tmp & (unsigned long long)1<<41){
return 41;
}
else if(tmp & (unsigned long long)1<<40){
return 40;
}
else if(tmp & (unsigned long long)1<<39){
return 39;
}
else if(tmp & (unsigned long long)1<<38){
return 38;
}
else if(tmp & (unsigned long long)1<<37){
return 37;
}
else if(tmp & (unsigned long long)1<<36){
return 36;
}
else if(tmp & (unsigned long long)1<<35){
return 35;
}
else if(tmp & (unsigned long long)1<<34){
return 34;
}
else if(tmp & (unsigned long long)1<<33){
return 33;
}
else if(tmp & (unsigned long long)1<<32){
return 32;
}
else if(tmp & (unsigned long long)1<<31){
return 31;
}
else if(tmp & (unsigned long long)1<<30){
return 30;
}
else if(tmp & (unsigned long long)1<<29){
return 29;
}
else if(tmp & (unsigned long long)1<<28){
return 28;
}
else if(tmp & (unsigned long long)1<<27){
return 27;
}
else if(tmp & (unsigned long long)1<<26){
return 26;
}
else if(tmp & (unsigned long long)1<<25){
return 25;
}
else if(tmp & (unsigned long long)1<<24){
return 24;
}
else if(tmp & (unsigned long long)1<<23){
return 23;
}
else if(tmp & (unsigned long long)1<<22){
return 22;
}
else if(tmp & (unsigned long long)1<<21){
return 21;
}
else if(tmp & (unsigned long long)1<<20){
return 20;
}
else if(tmp & (unsigned long long)1<<19){
return 19;
}
else if(tmp & (unsigned long long)1<<18){
return 18;
}
else if(tmp & (unsigned long long)1<<17){
return 17;
}
else if(tmp & (unsigned long long)1<<16){
return 16;
}
else if(tmp & (unsigned long long)1<<15){
return 15;
}
else if(tmp & (unsigned long long)1<<14){
return 14;
}
else if(tmp & (unsigned long long)1<<13){
return 13;
}
else if(tmp & (unsigned long long)1<<12){
return 12;
}
else if(tmp & (unsigned long long)1<<11){
return 11;
}
else if(tmp & (unsigned long long)1<<10){
return 10;
}
else if(tmp & (unsigned long long)1<<9){
return 9;
}
else if(tmp & (unsigned long long)1<<8){
return 8;
}
else if(tmp & (unsigned long long)1<<7){
return 7;
}
else if(tmp & (unsigned long long)1<<6){
return 6;
}
else if(tmp & (unsigned long long)1<<5){
return 5;
}
else if(tmp & (unsigned long long)1<<4){
return 4;
}
else if(tmp & (unsigned long long)1<<3){
return 3;
}
else if(tmp & (unsigned long long)1<<2){
return 2;
}
else if(tmp & (unsigned long long)1<<1){
return 1;
}
else if(tmp & (unsigned long long)1){
return 0;
}
else{
return -1; // NO leading 1
}
}
int my_multiplier(struct float32 alpha, struct float32 bravo)
{
printf("alpha(0x%08llx %f) is ",(ULL)alpha.total_int, alpha.total); print_binary((ULL)alpha.total_int); printf("\n");
printf("bravo(0x%08llx %f) is ",(ULL)bravo.total_int, bravo.total); print_binary((ULL)bravo.total_int); printf("\n");
struct float32 charlie, delta; // charlie: Correct answer
charlie.total = alpha.total * bravo.total;
/**************** Get Larger Exponent ***************/
int EA, EA0, EA1, EB, EB0, EB1, EA_minus_EB, EB_minus_EA;
int Larger_E, Right_Shift;
int E_LeftBig, E_RightBig, E_Equal;
EA = alpha.exponent;
EB = bravo.exponent;
if (EA==0b00000000){
EA0 = 1;
EA1 = 0;
} else if (EA==0b11111111){
EA0 = 0;
EA1 = 1;
}else{
EA0 = 0;
EA1 = 0;
}
if (EB==0b00000000){
EB0 = 1;
EB1 = 0;
} else if (EB==0b11111111){
EB0 = 0;
EB1 = 1;
}else{
EB0 = 0;
EB1 = 0;
}
EA_minus_EB = EA - EB; // 9bit
EB_minus_EA = EB - EA; // 9bit
// E_RightBig = ((EA_minus_EB & 0b100000000) != 0);
// E_LeftBig = ((EB_minus_EA & 0b100000000) != 0);
E_RightBig = (EA < EB); // 일단 대소판별기는 임시로 이렇게 때운다. 만들면 되니까.
E_LeftBig = (EA > EB);
E_Equal = !(E_RightBig | E_LeftBig);
Larger_E = ((E_LeftBig) ? EA : EB);
Right_Shift = ((E_LeftBig) ? EA_minus_EB : EB_minus_EA);
if(EA0 ^ EB0){ // 만약 하나의 E만 전부 0이면
Right_Shift--;
}
/*
이걸 구현하려면 또 Carry Adder 만들어야하니, 앗싸리 EA 또는 EB가 0이면 1로 올려주는 방안을 고려할 필요가 있음.
왜냐하면 어차피 denormalized number 의 E-127에서 E는 0이 아니라 1로 취급됨.
*/
#ifdef VERBOSE
printf(" \
EA = %d \
EA0 = %d \
EA1 = %d \
\n \
EB = %d \
EB0 = %d \
EB1 = %d \
\n \
EA_minus_EB = %d \
EB_minus_EA = %d \
\n \
E_LeftBig = %d \
E_RightBig = %d \
E_Equal = %d \
\n \
Larger_E = %d \
Right_Shift = %d \
\n", EA, EA0, EA1, EB, EB0, EB1,
EA_minus_EB, EB_minus_EA,
E_LeftBig, E_RightBig, E_Equal,
Larger_E, Right_Shift);
#endif
// 순서유의
// 이 때, EA_minus_EB는 후에 다 EA0 봐가면서 보정이 되어있으므로 여기서 바꿔야함. 이보다 앞에서 바꿔버리면 꼬임.
if(EA == 0) EA = 1; // denorm 의 exp는 -126취급.
if(EB == 0) EB = 1;
/*************************** ADD Exponent ***************************/
int EA_plus_EB = EA + EB; // EA and EB is unsigined int
int EA_plus_EB_minus_254 = EA_plus_EB - 254;
#ifdef VERBOSE
printf("ADD EXPONENT\n");
printf("EA_plus_EB is %d\n",EA_plus_EB);
printf("EA_plus_EB_minus_254 is %d\n",EA_plus_EB_minus_254);
#endif
/*************************** Get Sign ***************************/
int SA, SB;
SA = alpha.sign; SB = bravo.sign;
int final_sign = SA ^ SB;
/*********************** Setting up Multiply Mantissa ******************************/
int MA, MB, isDenorm1, isDenorm2, isDenorm3, isDenorm4;
int Denorm1, Denorm2;
int M_RightBig, M_LeftBig, M_Equal, MA0, MB0;
MA = alpha.mantissa; MB = bravo.mantissa;
M_LeftBig = MA > MB;
M_RightBig = MA < MB;
M_Equal = (MA == MB);
MA0 = ((MA==0) ? 1 : 0); MB0 = ((MB==0) ? 1 : 0);
isDenorm1 = ((!EA0)<<23) | MA;
isDenorm2 = MA;
isDenorm3 = ((!EB0)<<23) | MB;
isDenorm4 = MB;
Denorm1 = ((EA0&&(!MA0)) ? isDenorm2 : isDenorm1);
Denorm2 = ((EB0&&(!MB0)) ? isDenorm4 : isDenorm3);
#ifdef VERBOSE
printf(" \
M_LeftBig = %d \
M_RightBig = %d \
M_Equal = %d \
\n"
, M_LeftBig, M_RightBig, M_Equal);
#endif
#ifdef VERBOSE
printf("Denorm1(0x%x) is ",Denorm1); print_binary(Denorm1); printf("\n");
printf("Denorm2(0x%x) is ",Denorm2); print_binary(Denorm2); printf("\n");
#endif
/******************************** Multiply Mantissa ******************************/
unsigned long long M_48_Original = (unsigned long long) Denorm1 * (unsigned long long) Denorm2;
int G, R, S;
int leading_1_position = leading_1_detector_48bit(M_48_Original);
#ifdef VERBOSE
printf("M_48_Original == d1 * d2 = 0x%llx\n", M_48_Original);
printf("leading_1_position %d\n", leading_1_position);
#endif
unsigned long long M_48 = M_48_Original;
/* Dealing with M48 */
int E = EA_plus_EB_minus_254;
int Exp;
int UDFL = 0;
int OVFL = 0;
if(E > -126){
if(leading_1_position == 47){
M_48>>=1;
E++;
}
else if(leading_1_position == 46){
// Do nothing
}
else{
int Until_46th_Filled = 46 - leading_1_position;
M_48 <<= Until_46th_Filled;
E -= Until_46th_Filled;
}
Exp = E + 127;
if(E > 127){
OVFL = 1;
}
}// 둘다 elseif 가 아니라 if임에 유의
leading_1_position = leading_1_detector_48bit(M_48);
if(E < -126){
int Until_126 = -126 - E;
printf("E == %d\n",E);
printf("Until_126 == %d\n",Until_126);
if(Until_126 < 48) M_48>>=Until_126;
else M_48 = 0;
E += Until_126;
printf("E == %d\n",E);
}
leading_1_position = leading_1_detector_48bit(M_48);
if(E == -126){
if(leading_1_position == 47){
M_48>>=1;
E = -125;
Exp = 2;
}
else if(leading_1_position == 46){
E = -126;
Exp = 1;
}
else{
E = -126;
Exp = 0;
}
}
#ifdef VERBOSE
printf("mid(Before Hiding) M_48(0x%llx) is ", M_48); print_binary(M_48); printf("\n");
printf("E is %d\n",E);
printf("Exp is %d\n",Exp);
#endif
// Hide M48's 46th bit
M_48 = M_48 & 0x3FFFFFFFFFFF;
// Get G R S
G = (M_48 & 0x800000) == 0 ? 0 : 1;
R = (M_48 & 0x400000) == 0 ? 0 : 1;
S = (M_48 & 0x3FFFFF) == 0 ? 0 : 1;
// Get M_48[45:23]
M_48 >>= 23;
if((R==1 && S==1) || (G==1 && R==1 && S==0))
M_48++;
// rounding 고려시 추가 normalization 필요하지만, 일단 구현안함
int NAN = 0;
if((EA == 0xFF && MA != 0) || (EB == 0xFF && MB != 0))
NAN = 1;
delta.sign = final_sign;
if(OVFL){ // INF
Exp = 0xFF;
M_48 = 0;
}
if(NAN){
Exp = 0xFF;
M_48 = 0xFFFFFF;
}
delta.exponent = Exp;
delta.mantissa = M_48;
#ifdef VERBOSE
printf("final M_48(0x%llx) is ",M_48); print_binary(M_48); printf("\n");
printf("G: %d\n", G);
printf("R: %d\n", R);
printf("S: %d\n", S);
printf("OVFL: %d\t UDFL: %d\n",OVFL, UDFL);
float32_printer(alpha, "alpha");
float32_printer(bravo, "bravo");
float32_printer(charlie, "charlie");
float32_printer(delta, "delta");
#endif
printf("delta.total(%f) : 0b", delta.total); print_binary(delta.total_int); printf("\n");
printf("charlie.total(%f) : 0b", charlie.total); print_binary(charlie.total_int); printf("\n");
printf("charlie vs delta : %f vs %f\n", charlie.total, delta.total);
if(charlie.total == delta.total) printf("SAME\n");
else printf("ERROR!!!\n");
called++;
printf("my_multiplier: called = %dth\n", called);
printf("*********************** %f * %f END*********************\n", alpha.total, bravo.total);
}
int main()
{
printf("Hello World\n");
// float32_printer(cc, "cc");
struct float32 aa, bb, cc;
// 이하 통과시켜야함
aa.total_int = 89489864; bb.total_int = 817591348; // exp 10 * exp 97 != zero(왜냐하면 생존 mantissa가 있다)
my_multiplier(aa, bb);
aa.total_int = 89489864;
bb.total_int = 817591348; bb.mantissa = 0; bb.exponent = 117; // exp == 0
my_multiplier(aa, bb);
aa.total_int = 0x007fffff; bb.total_int = 0x007fffff; // Maximum denorm mult ^ 2
my_multiplier(aa, bb);
// 이하 해결
// 예시: https://stackoverflow.com/questions/51661257/binary-floating-point-addition-algorithm
aa.total_int = 0b00001000111100110110010010011100;
bb.total_int = 0b00000000000011000111111010000100;
float32_printer(aa, "aa");
float32_printer(bb, "bb");
my_multiplier(aa, bb); // 뒈짓
aa.total_int = 0x800000; bb.total_int = 0x800000; // Min norm ^ 2 == denorm???
my_multiplier(aa, bb); // 뒈짓
aa.total_int = 0x407FFFFF; bb.total_int = 0x407FFFFF; // Make 47th Mantissa 1, and result not INF
my_multiplier(aa, bb);
aa.total_int = 0x7f7fffff; bb.total_int = 0x007fffff; // Maximum norm mult * Maximum denorm mult
my_multiplier(aa, bb);
aa.total_int = 1656830887; bb.total_int = 1386443347;
my_multiplier(aa, bb);
aa.total_int = 1352740975; bb.total_int = 1207161653; // 터짐
float32_printer(aa, "aa");
float32_printer(bb, "bb");
my_multiplier(aa, bb);
aa.total_int = 1173666029; bb.total_int = 1167651708; // 아마 R==1 S==1이라서 mantissa++ 해줘야할듯?
float32_printer(aa, "aa");
float32_printer(bb, "bb");
my_multiplier(aa, bb);
aa.total_int = 977394179; bb.total_int = 961550550;
float32_printer(aa, "aa");
float32_printer(bb, "bb");
my_multiplier(aa, bb);
aa.total = 0.5; bb.total = 0.4375;
my_multiplier(aa, bb);
aa.total = 0.5; bb.total = -0.4375;
my_multiplier(aa, bb);
aa.total = 0.5; bb.total = 0.75;
my_multiplier(aa, bb);
aa.total = -0.5; bb.total = 0.75;
my_multiplier(aa, bb);
aa.total = -0.5; bb.total = -0.75;
my_multiplier(aa, bb);
// cc.total = aa.total + bb.total;
aa.total_int = 551542477; bb.total_int = 1881522032;
my_multiplier(aa, bb);
// 여기까지 전부 통과
/*
// 47th mantissa == 1
aa.total_int = 89489864;
bb.total_int = 817591348; bb.exponent = 118; // exp == -126==1-127 +1(since mantissa 47th)
my_multiplier(aa, bb);
aa.total_int = 89489864;
bb.total_int = 817591348; bb.exponent = 117; // exp == 1 (since mantissa + 1)
my_multiplier(aa, bb);
aa.total_int = 89489864;
bb.total_int = 817591348; bb.exponent = 116; // exp == 0
my_multiplier(aa, bb);
*/
#ifdef RANDOM
srand(time(NULL));
for(int i=0;i<100000;i++){
aa.total_int = rand();
bb.total_int = rand();
printf("aa.total_int: %d\n",aa.total_int);
printf("bb.total_int: %d\n",bb.total_int);
float32_printer(aa, "aa");
float32_printer(bb, "bb");
my_multiplier(aa, bb);
}
#endif
return 0;
}
좀더단순히 할수있긴하다.
우선 저장한다.