CCCPaste

Some Decimal128 DPD test code...

/*
Written 2025-11-07 by Brendan G Bohannon.

Do whatever with this, just assume Public Domain or MIT-0 or CC0 or whatever.
I take no responsibility for anything that may result from using this code.
*/

/*
Decimal128 DPD test stuff...
*/


#include 
#include 
#include 
#include 
#include 
#include 


#ifndef BTIC2F_BYTE
#define BTIC2F_BYTE
typedef unsigned char			byte;
typedef unsigned short		u16;
typedef unsigned int			u32;
typedef unsigned long long	u64;

typedef signed char			sbyte;
typedef signed short			s16;
typedef signed int			s32;
typedef signed long long		s64;
#endif

#define TKD128_MASK30	0x3FFFFFFFU
#define TKD128_MASK20	0x000FFFFFU
#define TKD128_MASK46	0x00003FFFFFFFFFFFULL

// #define TKD128_BIAS		6176
#define TKD128_BIAS		6143

typedef struct TKD128_Packed128_s TKD128_Packed128;
typedef struct TKD128_Unpacked4x30_s TKD128_Unpacked4x30;
typedef struct TKD128_Unpacked8x30_s TKD128_Unpacked8x30;

struct TKD128_Packed128_s {
u64 lo;
u64 hi;
};

struct TKD128_Unpacked4x30_s {
u32 m[4];
s16 exp;
byte sgn;
};

struct TKD128_Unpacked8x30_s {
u32 m[8];
s16 exp;
byte sgn;
};

char *TKD128_OprDumpAsString(
	TKD128_Unpacked4x30 val);

u16 tkd128_unpackdpd[1024];
u16 tkd128_packdpd[1024];

int TKD128_InitDPD()
{
	int d0, d1, d2;
	int i, j, k;
	
	if(tkd128_packdpd[999])
		return(0);
	
	for(i=0; i<1024; i++)
	{
		if(i&8)
		{
			if(((i>>1)&3)==0)
			{
				d0=(i>>7)&7;
				d1=(i>>4)&7;
				d2=8+(i&1);
			}else
				if(((i>>1)&3)==1)
			{
				d0=(i>>7)&7;
				d1=8+((i>>4)&1);
				d2=((i>>4)&6)|(i&1);
			}else
				if(((i>>1)&3)==2)
			{
				d0=8+((i>>7)&1);
				d1=(i>>4)&7;
				d2=((i>>7)&6)|(i&1);
			}else
			{
				if(((i>>5)&3)==0)
				{
					d0=8+((i>>7)&1);
					d1=8+((i>>4)&1);
					d2=((i>>7)&6)|(i&1);
				}else
					if(((i>>5)&3)==1)
				{
					d0=8+((i>>7)&1);
					d1=((i>>7)&6)+((i>>4)&1);
					d2=8+((i>>0)&1);
				}else
					if(((i>>5)&3)==2)
				{
					d0=((i>>7)&6)+((i>>7)&1);
					d1=8+((i>>4)&1);
					d2=8+((i>>0)&1);
				}else
				{
					d0=8+((i>>7)&1);
					d1=8+((i>>4)&1);
					d2=8+((i>>0)&1);
				}
			}
		}else
		{
			d0=(i>>7)&7;
			d1=(i>>4)&7;
			d2=(i>>0)&7;
		}
		
		j=d0*100+d1*10+d2;
		
		tkd128_unpackdpd[i]=j;
		if(!tkd128_packdpd[j])
			tkd128_packdpd[j]=i;
	}

	return(1);
}

TKD128_Unpacked4x30 TKD128_UnpackValueX30(TKD128_Packed128 val)
{
	TKD128_Unpacked4x30 tmp;
	int mc, mcd, ex;
	
	tmp.m[0]=(val.lo>> 0)&TKD128_MASK30;
	tmp.m[1]=(val.lo>>30)&TKD128_MASK30;
	tmp.m[2]=((val.hi<< 4)|(val.lo>>60))&TKD128_MASK30;
	tmp.m[3]=(val.hi>>26)&TKD128_MASK20;

	mc=(val.hi>>46)&0x1FFFF;
	if((mc>>15)==3)
		{ mcd=8+(mc>>12)&1; ex=(mc&0xFFF)|(((mc>>13)&3)<<12); }
	else
		{ mcd=(mc>>12)&7; ex=(mc&0xFFF)|(((mc>>15)&3)<<12); }
	tmp.m[3]+=mcd*1000000;

	tmp.exp=ex;
	tmp.sgn=val.hi>>63;

	return(tmp);
}

TKD128_Packed128 TKD128_PackValueX30(TKD128_Unpacked4x30 val)
{
	TKD128_Packed128 tmp;
	int m3n, mcd, mc, ex;
	
	m3n=val.m[3]%1000000000;
	mcd=val.m[3]/1000000000;
	
	ex=val.exp;
	if(mcd>=8)
		{ mc=0x18000|(ex&0xFFF)|((mcd&1)<<12)|(((ex>>12)&3)<<13); }
	else
		{ mc=(ex&0xFFF)|((mcd&7)<<12)|(((ex>>12)&3)<<15); }
	
	tmp.lo=val.m[0]|(((u64)(val.m[1]))<<30)|(((u64)(val.m[2]))<<60);
	tmp.hi=(val.m[2]>>4)|(((u64)m3n)<<26)|
		(((u64)mcd)<<46)|(((u64)val.sgn)<<63);
	
	return(tmp);
}


#if 1
void TKD128_UnpackValueX30R(
	TKD128_Unpacked4x30 *rtmp, TKD128_Packed128 *rval)
{
//	TKD128_Unpacked4x30 tmp;
	u64 lo, hi;
	int mc, mcd, ex;
	
	lo=rval->lo;
	hi=rval->hi;
	rtmp->m[0]=(lo>> 0)&TKD128_MASK30;
	rtmp->m[1]=(lo>>30)&TKD128_MASK30;
	rtmp->m[2]=((hi<< 4)|(lo>>60))&TKD128_MASK30;
	rtmp->m[3]=(hi>>26)&TKD128_MASK20;

	mc=(hi>>46)&0x1FFFF;
	if((mc>>15)==3)
	{
		mcd=8+(mc>>12)&1;
		ex=(mc&0xFFF)|(((mc>>13)&3)<<12);
	}else
	{
		mcd=(mc>>12)&7;
		ex=(mc&0xFFF)|(((mc>>15)&3)<<12);
	}
	rtmp->m[3]+=mcd*1000000;

	rtmp->exp=ex;
	rtmp->sgn=hi>>63;
}

void TKD128_PackValueX30R(
	TKD128_Unpacked4x30 *rval, TKD128_Packed128 *rtmp)
{
	u32 m0, m1, m2, m3;
	int m3n, mcd, mc, ex, sgn;
	
	m0=rval->m[0];
	m1=rval->m[1];
	m2=rval->m[2];
	m3=rval->m[3];
	
	m3n=m3%1000000000;
	mcd=m3/1000000000;
	sgn=rval->sgn;
	
	ex=rval->exp;
	if(mcd>=8)
		{ mc=0x18000|(ex&0xFFF)|((mcd&1)<<12)|(((ex>>12)&3)<<13); }
	else
		{ mc=(ex&0xFFF)|((mcd&7)<<12)|(((ex>>12)&3)<<15); }

	rtmp->lo=m0|(((u64)(m1))<<30)|(((u64)(m2))<<60);
	rtmp->hi=(m2>>4)|(((u64)m3n)<<26)|
		(((u64)mcd)<<46)|(((u64)sgn)<<63);
}
#endif


u32 TKD128_UnpackBitsDPD30(u32 val)
{
	u32 v0, v1, v2, v;
	v0=tkd128_unpackdpd[(val>> 0)&1023];
	v1=tkd128_unpackdpd[(val>>10)&1023];
	v2=tkd128_unpackdpd[(val>>20)&1023];
	v=v0+(v1*1000)+(v2*1000000);
	return(v);
}

u32 TKD128_PackBitsDPD30(u32 val)
{
	u32 v0, v1, v2, v;
	v=val;
	v1=v/1000;
	v0=v-(v1*1000);
	v2=v1/1000;
	v1=v1-(v2*1000);
	v0=tkd128_packdpd[v0];
	v1=tkd128_packdpd[v1];
	v2=tkd128_packdpd[v2];
	v=v0|(v1<<10)|(v2<<20);
	return(v);
}

TKD128_Unpacked4x30 TKD128_UnpackValueDPD(TKD128_Packed128 val)
{
	TKD128_Unpacked4x30 tmp;
	int mc, mcd, ex;
	
	tmp.m[0]=TKD128_UnpackBitsDPD30((val.lo>> 0)&TKD128_MASK30);
	tmp.m[1]=TKD128_UnpackBitsDPD30((val.lo>>30)&TKD128_MASK30);
	tmp.m[2]=TKD128_UnpackBitsDPD30(((val.hi<< 4)|(val.lo>>60))&TKD128_MASK30);
	tmp.m[3]=TKD128_UnpackBitsDPD30((val.hi>>26)&TKD128_MASK20);

	mc=(val.hi>>46)&0x1FFFF;
	if((mc>>15)==3)
	{
		mcd=8+(mc>>12)&1;
		ex=(mc&0xFFF)|(((mc>>13)&3)<<12);
	}else
	{
		mcd=(mc>>12)&7;
		ex=(mc&0xFFF)|(((mc>>15)&3)<<12);
	}
	tmp.m[3]+=mcd*1000000;

	tmp.exp=ex;
	tmp.sgn=val.hi>>63;

	return(tmp);
}

TKD128_Packed128 TKD128_PackValueDPD(TKD128_Unpacked4x30 val)
{
	TKD128_Packed128 tmp;
	u32 m0, m1, m2, m3;
	int m3n, mcd, mc, ex;
	
	mcd=val.m[3]/1000000;
	m3n=val.m[3]%1000000;
	
	ex=val.exp;
	if(mcd>=8)
		{ mc=0x18000|(ex&0xFFF)|((mcd&1)<<12)|(((ex>>12)&3)<<13); }
	else
		{ mc=(ex&0xFFF)|((mcd&7)<<12)|(((ex>>12)&3)<<15); }

	m0=TKD128_PackBitsDPD30(val.m[0]);
	m1=TKD128_PackBitsDPD30(val.m[1]);
	m2=TKD128_PackBitsDPD30(val.m[2]);
	m3=TKD128_PackBitsDPD30(m3n);
	tmp.lo=m0|(((u64)m1)<<30)|(((u64)m2)<<60);
	tmp.hi=(m2>>4)|(((u64)m3)<<26)|
		(((u64)mc)<<46)|(((u64)val.sgn)<<63);
	
	return(tmp);
}


int TKD128_ScaleLeftArray8(u32 *arr, int shl)
{
	int sh;

	sh=shl;

	while(sh>=9)
	{
		sh-=9;
		arr[7]=arr[6];
		arr[6]=arr[5];
		arr[5]=arr[4];
		arr[4]=arr[3];
		arr[3]=arr[2];
		arr[2]=arr[1];
		arr[1]=arr[0];
		arr[0]=0;
	}

	while(sh>=3)
	{
		sh-=3;
		arr[7]=((arr[7]%1000000)*1000)+(arr[6]/1000000);
		arr[6]=((arr[6]%1000000)*1000)+(arr[5]/1000000);
		arr[5]=((arr[5]%1000000)*1000)+(arr[4]/1000000);
		arr[4]=((arr[4]%1000000)*1000)+(arr[3]/1000000);
		arr[3]=((arr[3]%1000000)*1000)+(arr[2]/1000000);
		arr[2]=((arr[2]%1000000)*1000)+(arr[1]/1000000);
		arr[1]=((arr[1]%1000000)*1000)+(arr[0]/1000000);
		arr[0]=((arr[0]%1000000)*1000);
	}

	while(sh>=1)
	{
		sh--;
		arr[7]=((arr[7]%100000000)*10)+(arr[6]/100000000);
		arr[6]=((arr[6]%100000000)*10)+(arr[5]/100000000);
		arr[5]=((arr[5]%100000000)*10)+(arr[4]/100000000);
		arr[4]=((arr[4]%100000000)*10)+(arr[3]/100000000);
		arr[3]=((arr[3]%100000000)*10)+(arr[2]/100000000);
		arr[2]=((arr[2]%100000000)*10)+(arr[1]/100000000);
		arr[1]=((arr[1]%100000000)*10)+(arr[0]/100000000);
		arr[0]=((arr[0]%100000000)*10);
	}
	return(0);
}


int TKD128_ScaleRightArray8(u32 *arr, int shl)
{
	int sh;

	sh=shl;

	while(sh>=9)
	{
		sh-=9;
		arr[0]=arr[1];
		arr[1]=arr[2];
		arr[2]=arr[3];
		arr[3]=arr[4];
		arr[4]=arr[5];
		arr[5]=arr[6];
		arr[6]=arr[7];
		arr[7]=0;
	}

	while(sh>=3)
	{
		sh-=3;
		arr[0]=((arr[1]%1000)*1000000)+(arr[0]/1000);
		arr[1]=((arr[2]%1000)*1000000)+(arr[1]/1000);
		arr[2]=((arr[3]%1000)*1000000)+(arr[2]/1000);
		arr[3]=((arr[4]%1000)*1000000)+(arr[3]/1000);
		arr[4]=((arr[5]%1000)*1000000)+(arr[4]/1000);
		arr[5]=((arr[6]%1000)*1000000)+(arr[5]/1000);
		arr[6]=((arr[7]%1000)*1000000)+(arr[6]/1000);
		arr[7]=(arr[7]/1000);
	}

	while(sh>=1)
	{
		sh--;
		arr[0]=((arr[1]%10)*100000000)+(arr[0]/10);
		arr[1]=((arr[2]%10)*100000000)+(arr[1]/10);
		arr[2]=((arr[3]%10)*100000000)+(arr[2]/10);
		arr[3]=((arr[4]%10)*100000000)+(arr[3]/10);
		arr[4]=((arr[5]%10)*100000000)+(arr[4]/10);
		arr[5]=((arr[6]%10)*100000000)+(arr[5]/10);
		arr[6]=((arr[7]%10)*100000000)+(arr[6]/10);
		arr[7]=(arr[7]/10);
	}
	return(0);
}

int TKD128_AddArray8(u32 *arr_a, u32 *arr_b, u32 *arr_c)
{
	u32 v, c;
	int i;
	
	c=0;
	for(i=0; i<8; i++)
	{
		v=arr_a[i]+arr_b[i]+c;
		c=0;
		if(v>=1000000000U)
			{ c=1; v-=1000000000U; }
		arr_c[i]=v;
	}
	return(0);
}

int TKD128_SubArray8(u32 *arr_a, u32 *arr_b, u32 *arr_c)
{
	u32 v, c;
	int i;
	
	c=0;
	for(i=0; i<8; i++)
	{
		v=arr_a[i]-arr_b[i]-c;
		c=0;
		if(v>=1000000000U)
			{ c=1; v+=1000000000U; }
		arr_c[i]=v;
	}
	return(0);
}

TKD128_Unpacked8x30 TKD128_Conv4to8x30(
	TKD128_Unpacked4x30 val)
{
	TKD128_Unpacked8x30 tmp;
	tmp.sgn=val.sgn;
	tmp.exp=val.exp;
	tmp.m[7]=val.m[3];
	tmp.m[6]=val.m[2];
	tmp.m[5]=val.m[1];
	tmp.m[4]=val.m[0];
	tmp.m[3]=0;
	tmp.m[2]=0;
	tmp.m[1]=0;
	tmp.m[0]=0;
	return(tmp);
}

TKD128_Unpacked4x30 TKD128_OprNormalize8to4x30(TKD128_Unpacked8x30 valc0)
{
	TKD128_Unpacked4x30 valc;
	u32 m0, m1, m2, m3;

	if(valc0.m[7]>=10000000)
		{ valc0.exp++; TKD128_ScaleRightArray8(valc0.m, 1); }
	while(!valc0.m[7] && !valc0.m[6] && (valc0.exp>=9))
		{ valc0.exp-=9; TKD128_ScaleLeftArray8(valc0.m, 9); }
	while(!valc0.m[7] && (valc0.exp>=6))
		{ valc0.exp-=6; TKD128_ScaleLeftArray8(valc0.m, 6); }
	while((valc0.m[7]<=1000) && (valc0.exp>=3))
		{ valc0.exp-=3; TKD128_ScaleLeftArray8(valc0.m, 3); }
	while((valc0.m[7]<1000000) && (valc0.exp>=1))
		{ valc0.exp--; TKD128_ScaleLeftArray8(valc0.m, 1); }
	
	m0=valc0.m[4];
	m1=valc0.m[5];
	m2=valc0.m[6];
	m3=valc0.m[7];

	m0+=(valc0.m[3]>500000000);

	if(m0>=1000000000)
		{ m1++; m0-=1000000000; }
	if(m1>=1000000000)
		{ m2++; m1-=1000000000; }
	if(m2>=1000000000)
		{ m3++; m2-=1000000000; }
	
	valc.sgn=valc0.sgn;
	valc.exp=valc0.exp;
	valc.m[0]=m0;	valc.m[1]=m1;
	valc.m[2]=m2;	valc.m[3]=m3;
	
	return(valc);
}

TKD128_Unpacked4x30 TKD128_OprAdd(
	TKD128_Unpacked4x30 vala,
	TKD128_Unpacked4x30 valb)
{
	TKD128_Unpacked8x30 vala0, valb0, valc0;
	TKD128_Unpacked4x30 valc;
	int maxexp, flip;
	
	vala0=TKD128_Conv4to8x30(vala);
	valb0=TKD128_Conv4to8x30(valb);
	maxexp=vala0.exp;
	flip=0;
	if(valb0.exp>maxexp)
	{
		maxexp=valb0.exp;
		flip=1;
	}else
		if(vala0.exp==valb0.exp)
	{
		if(valb0.m[7]>vala0.m[7])
			{ flip=1; }
		else if(valb0.m[7]==vala0.m[7])
		{	if(valb0.m[6]>vala0.m[6])
				{ flip=1; }
			else if(valb0.m[6]==vala0.m[6])
			{	if(valb0.m[5]>vala0.m[5])
					{ flip=1; }
				else if(valb0.m[5]==vala0.m[5])
				{	if(valb0.m[4]>vala0.m[4])
						{ flip=1; }
				}
			}
		}
	}
	
	if(flip)
	{
		valc0=vala0;
		vala0=valb0;
		valb0=valc0;
	}

	TKD128_ScaleRightArray8(vala0.m, maxexp-vala0.exp);
	TKD128_ScaleRightArray8(valb0.m, maxexp-valb0.exp);
	vala0.exp=maxexp;
	valb0.exp=maxexp;
	valc0.exp=maxexp;
	valc0.sgn=vala0.sgn;
	
	if(vala0.sgn==valb0.sgn)
		{ TKD128_AddArray8(vala0.m, valb0.m, valc0.m); }
	else
		{ TKD128_SubArray8(vala0.m, valb0.m, valc0.m); }

	valc=TKD128_OprNormalize8to4x30(valc0);
	return(valc);
}

TKD128_Unpacked4x30 TKD128_OprSub(
	TKD128_Unpacked4x30 vala,
	TKD128_Unpacked4x30 valb)
{
	TKD128_Unpacked4x30 valb1;
	valb1=valb;
	valb1.sgn=!valb.sgn;
	return(TKD128_OprAdd(vala, valb1));
}

TKD128_Unpacked4x30 TKD128_OprMul(
	TKD128_Unpacked4x30 vala,
	TKD128_Unpacked4x30 valb)
{
	TKD128_Unpacked8x30 valc0;
	TKD128_Unpacked4x30 valc;
	u64 m0_aa, m0_ab, m0_ac, m0_ad;
	u64 m0_ba, m0_bb, m0_bc, m0_bd;
	u64 m0_ca, m0_cb, m0_cc, m0_cd;
	u64 m0_da, m0_db, m0_dc, m0_dd;
	u64 m1a, m1b, m1c, m1d;
	
	valc0.exp=vala.exp+valb.exp-TKD128_BIAS;
	valc0.sgn=vala.sgn^valb.sgn;
	
	m0_aa=((u64)vala.m[3])*((u64)valb.m[3]);
	m0_ab=((u64)vala.m[3])*((u64)valb.m[2]);
	m0_ac=((u64)vala.m[3])*((u64)valb.m[1]);
	m0_ad=((u64)vala.m[3])*((u64)valb.m[0]);
	m0_ba=((u64)vala.m[2])*((u64)valb.m[3]);
	m0_bb=((u64)vala.m[2])*((u64)valb.m[2]);
	m0_bc=((u64)vala.m[2])*((u64)valb.m[1]);
	m0_bd=((u64)vala.m[2])*((u64)valb.m[0]);
	m0_ca=((u64)vala.m[1])*((u64)valb.m[3]);
	m0_cb=((u64)vala.m[1])*((u64)valb.m[2]);
	m0_cc=((u64)vala.m[1])*((u64)valb.m[1]);
	m0_cd=((u64)vala.m[1])*((u64)valb.m[0]);
	m0_da=((u64)vala.m[0])*((u64)valb.m[3]);
	m0_db=((u64)vala.m[0])*((u64)valb.m[2]);
	m0_dc=((u64)vala.m[0])*((u64)valb.m[1]);
	m0_dd=((u64)vala.m[0])*((u64)valb.m[0]);

/*
 * AA
 *  AB
 *  BA
 *   BB
 *   AC
 *   CA
 *    AD
 *    DA
 *    BC
 *    CB
 *     CC
 *     BD
 *     DB
 *      CD
 *      DC
 *       DD
 */

	m1a=m0_aa+
		(m0_ba/1000000000ULL) +
		(m0_ab/1000000000ULL) ;
	m1b=m0_bb+
		m0_ac+
		m0_ca+
		(m0_cb/1000000000ULL) +
		(m0_bc/1000000000ULL) +
		(m0_ad/1000000000ULL) +
		(m0_da/1000000000ULL) +
		((m0_ba%1000000000ULL)*1000000000ULL) +
		((m0_ab%1000000000ULL)*1000000000ULL) ;
	m1c=m0_cc+
		m0_bd+
		m0_db+
		(m0_dc/1000000000ULL) +
		(m0_cd/1000000000ULL) +
		((m0_ad%1000000000ULL)*1000000000ULL) +
		((m0_da%1000000000ULL)*1000000000ULL) +
		((m0_cb%1000000000ULL)*1000000000ULL) +
		((m0_bc%1000000000ULL)*1000000000ULL) ;
	
	m1d=m0_dd+
		((m0_dc%1000000000ULL)*1000000000ULL) +
		((m0_cd%1000000000ULL)*1000000000ULL) ;

	while(m1d>=1000000000000000000ULL)
		{ m1d-=1000000000000000000ULL; m1c++; }
	while(m1c>=1000000000000000000ULL)
		{ m1c-=1000000000000000000ULL; m1b++; }
	while(m1b>=1000000000000000000ULL)
		{ m1b-=1000000000000000000ULL; m1a++; }

	valc0.m[7]=m1a/1000000000ULL;
	valc0.m[6]=m1a%1000000000ULL;
	valc0.m[5]=m1b/1000000000ULL;
	valc0.m[4]=m1b%1000000000ULL;
	valc0.m[3]=m1c/1000000000ULL;
	valc0.m[2]=m1c%1000000000ULL;
	valc0.m[1]=m1d/1000000000ULL;
	valc0.m[0]=m1d%1000000000ULL;
	
	TKD128_ScaleLeftArray8(valc0.m, 3);

	valc=TKD128_OprNormalize8to4x30(valc0);
	return(valc);
}

TKD128_Unpacked4x30 TKD128_OprRecipApx(
	TKD128_Unpacked4x30 val)
{
	TKD128_Unpacked4x30 valc;
	
	valc.sgn=val.sgn;
	valc.exp=(2*TKD128_BIAS-1)-val.exp;
	valc.m[3]=1000000000-val.m[3];
	valc.m[2]=1000000000-val.m[2];
	valc.m[1]=1000000000-val.m[1];
	valc.m[0]=1000000000-val.m[0];
	return(valc);
}

int TKD128_OprCompare(
	TKD128_Unpacked4x30 vala,
	TKD128_Unpacked4x30 valb)
{
	if(vala.sgn!=valb.sgn)
	{
		if(!vala.sgn)
			return(1);
		return(-1);
	}

	if(vala.exp!=valb.exp)
	{
		if(vala.exp>valb.exp)
			return(1);
		return(-1);
	}
	if(vala.m[3]!=valb.m[3])
	{
		if(vala.m[3]>valb.m[3])
			return(1);
		return(-1);
	}
	if(vala.m[2]!=valb.m[2])
	{
		if(vala.m[2]>valb.m[2])
			return(1);
		return(-1);
	}
	if(vala.m[1]!=valb.m[1])
	{
		if(vala.m[1]>valb.m[1])
			return(1);
		return(-1);
	}
	if(vala.m[0]!=valb.m[0])
	{
		if(vala.m[0]>valb.m[0])
			return(1);
		return(-1);
	}
	return(0);
}

TKD128_Unpacked4x30 TKD128_OprRecip(
	TKD128_Unpacked4x30 val)
{
	static TKD128_Unpacked4x30 cnst_0p5 ={{0,0,0, 500000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_2p0 ={{0,0,0,2000000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_1p0 ={{0,0,0,1000000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_3p0 ={{0,0,0,3000000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_0p75={{0,0,0, 750000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_1p25={{0,0,0,1250000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_0p875={{0,0,0, 875000}, TKD128_BIAS, 0};
	static TKD128_Unpacked4x30 cnst_1p125={{0,0,0,1125000}, TKD128_BIAS, 0};

	TKD128_Unpacked4x30 valc, valb, valt;
	int d0, d1, d2, d3, de;
	int i;
	
	valc=TKD128_OprRecipApx(val);

//	printf("Rcp Apx-0:\n  %s\n  %s\n",
//		TKD128_OprDumpAsString(val),
//		TKD128_OprDumpAsString(valc));

	for(i=0; i<32; i++)
	{
		valb=TKD128_OprMul(val, valc);
		de=valb.exp-TKD128_BIAS;
		if(de>0)
			{ valc=TKD128_OprMul(valc, cnst_0p5); continue; }
		if(de<0)
			{ valc=TKD128_OprMul(valc, cnst_2p0); continue; }

		if(valb.m[3]>=2000000)
			{ valc=TKD128_OprMul(valc, cnst_0p5); continue; }
		if(valb.m[3]<= 500000)
			{ valc=TKD128_OprMul(valc, cnst_2p0); continue; }

		if(valb.m[3]>=1500000)
			{ valc=TKD128_OprMul(valc, cnst_0p75); continue; }
		if(valb.m[3]<= 750000)
			{ valc=TKD128_OprMul(valc, cnst_1p25); continue; }

		if(valb.m[3]>=1250000)
			{ valc=TKD128_OprMul(valc, cnst_0p875); continue; }
		if(valb.m[3]<= 875000)
			{ valc=TKD128_OprMul(valc, cnst_1p125); continue; }

		break;
	}

//	printf("Rcp Apx-1:\n  %s\n  %s\n",
//		TKD128_OprDumpAsString(val),
//		TKD128_OprDumpAsString(valc));

	for(i=0; i<32; i++)
	{
		valb=TKD128_OprMul(val, valc);

		valt=TKD128_OprSub(cnst_2p0, valb);
		
		de=TKD128_OprCompare(valt, cnst_1p0);
		if(!de)
			break;

//		valt=TKD128_OprSub(cnst_3p0, valb);
//		valt=TKD128_OprMul(valt, cnst_0p5);

//		printf("Rcp Apx-I:\n  %s\n  %s\n",
//			TKD128_OprDumpAsString(valb),
//			TKD128_OprDumpAsString(valt));

		valc=TKD128_OprMul(valc, valt);
	}
	
//	printf("Rcp Apx-2:\n  %s\n  %s\n",
//		TKD128_OprDumpAsString(val),
//		TKD128_OprDumpAsString(valc));
	return(valc);
}

TKD128_Unpacked4x30 TKD128_OprDiv(
	TKD128_Unpacked4x30 vala,
	TKD128_Unpacked4x30 valb)
{
	TKD128_Unpacked4x30 valb1;
	valb1=TKD128_OprRecip(valb);
	return(TKD128_OprMul(vala, valb1));
}



int TKD128_OprDump30ToString(char *ct, u32 v)
{
	u32 v0, v1, vt;
	int i;
	
	vt=v;
	for(i=0; i<9; i++)
	{
		v1=vt/10;
		v0=vt-(v1*10);
		vt=v1;
		ct[8-i]='0'+v0;
	}
	return(0);
}

char *TKD128_RAlloc(int sz)
{
	static char buf[4096];
	static u16 pos;
	char *ct;
	
	if((pos+sz)>=4096)
		pos=0;
	ct=buf+pos;
	pos+=sz;
	return(ct);
}

char *TKD128_RStrDup(char *str)
{
	char *ct;
	ct=TKD128_RAlloc(strlen(str)+1);
	strcpy(ct, str);
	return(ct);
}

char *TKD128_OprDumpAsString(
	TKD128_Unpacked4x30 val)
{
	static char tbuf[256], tb1[48];
	char *ct, *cs;
	int i, j, k, ex, exn;

	if((val.exp==0) && !val.m[3] && !val.m[2] && !val.m[1] && !val.m[0])
	{
		if(val.sgn)
			return("-0.0");
		return("0.0");
	}

	TKD128_OprDump30ToString(tb1+ 0, val.m[3]);
	TKD128_OprDump30ToString(tb1+ 9, val.m[2]);
	TKD128_OprDump30ToString(tb1+18, val.m[1]);
	TKD128_OprDump30ToString(tb1+27, val.m[0]);
	tb1[36]=0;
	
	ex=val.exp-TKD128_BIAS;
	exn=0;

	if((ex>32) || (ex<(-32)))
		exn=1;

	ct=tbuf;
	if(val.sgn)
		*ct++='-';
	if(exn)
	{
		*ct++='0';
		*ct++='.';
		strcpy(ct, tb1+2);
		ct+=strlen(ct);
		*ct++='E';
		sprintf(ct, "%+d", ex);
	}else
		if(ex<0)
	{
		k=(-ex)-1;
		*ct++='0';
		*ct++='.';
		while(k--)
			*ct++='0';
		strcpy(ct, tb1+2);
	}else
	{
		k=ex+1;
		cs=tb1+2;

		while(k && *cs=='0')
			{ *cs++; k--; }

		while(k && *cs)
			{ *ct++=*cs++; k--; }
		if(*cs)
		{
			*ct++='.';
			strcpy(ct, cs);
		}else
		{
			while(k--)
				*ct++='0';
			*ct++='.';
			*ct++='0';
			*ct=0;
		}
	}
	
	return(TKD128_RStrDup(tbuf));
}

u32 TKD128_OprParse30ToString(char *str)
{
	u32 v;
	int i;
	
	v=0;
	for(i=0; i<9; i++)
		{ v=(v*10)+(str[i]-'0'); }
	return(v);
}

TKD128_Unpacked4x30 TKD128_OprParseFromString(char *str)
{
	TKD128_Unpacked4x30 val;
	char tb[64];
	char *cs, *ct;
	int exh, exn, exsz, ex, exadj, sgn;
	
	cs=str;
	ct=tb;

	sgn=0;
	if(*cs=='+')
		{ cs++; sgn=0; }
	if(*cs=='-')
		{ cs++; sgn=1; }
	
	while(*cs=='0')
		cs++;
	
	*ct++='0';
	*ct++='0';
	
	exh=0;
	while((*cs>='0') && (*cs<='9') && (exh<34))
		{ *ct++=*cs++; exh++; }
	if(exh>=34)
	{
		while((*cs>='0') && (*cs<='9'))
			{ cs++; exh++; }
	}else
	{
		exn=0;
		exsz=0;
		if(*cs=='.')
		{
			cs++;
			
			if(!exh)
			{
				while(*cs=='0')
					{ cs++; exsz++; }
			}
			
			while((*cs>='0') && (*cs<='9') && ((exh+exn)<34))
				{ *ct++=*cs++; exn++; }
		}
		while((exh+exn)<34)
			{ *ct++='0'; exn++; }

		while((*cs>='0') && (*cs<='9'))
			{ cs++; }
	}
	*ct=0;
	
	exadj=0;
	if((*cs=='e') || (*cs=='E'))
	{
		if(cs[1]=='+')
			{ exadj=atoi(cs+2); }
		else
			{ exadj=atoi(cs+1); }
	}
	
	ex=TKD128_BIAS+exh+exadj-1-exsz;

	val.sgn=sgn;
	val.exp=ex;
	val.m[3]=TKD128_OprParse30ToString(tb+ 0);
	val.m[2]=TKD128_OprParse30ToString(tb+ 9);
	val.m[1]=TKD128_OprParse30ToString(tb+18);
	val.m[0]=TKD128_OprParse30ToString(tb+27);
	return(val);
}

TKD128_Packed128 TKD128_OprAddDPD(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

	vna=TKD128_UnpackValueDPD(vala);
	vnb=TKD128_UnpackValueDPD(valb);
	vnc=TKD128_OprAdd(vna, vnb);
	vpc=TKD128_PackValueDPD(vnc);
	return(vpc);
}

TKD128_Packed128 TKD128_OprMulDPD(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

	vna=TKD128_UnpackValueDPD(vala);
	vnb=TKD128_UnpackValueDPD(valb);
	vnc=TKD128_OprMul(vna, vnb);
	vpc=TKD128_PackValueDPD(vnc);
	return(vpc);
}

TKD128_Packed128 TKD128_OprSubDPD(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

	vna=TKD128_UnpackValueDPD(vala);
	vnb=TKD128_UnpackValueDPD(valb);
	vnc=TKD128_OprSub(vna, vnb);
	vpc=TKD128_PackValueDPD(vnc);
	return(vpc);
}

TKD128_Packed128 TKD128_OprDivDPD(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

	vna=TKD128_UnpackValueDPD(vala);
	vnb=TKD128_UnpackValueDPD(valb);
	vnc=TKD128_OprDiv(vna, vnb);
	vpc=TKD128_PackValueDPD(vnc);
	return(vpc);
}


TKD128_Packed128 TKD128_OprAddX30(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

//	vna=TKD128_UnpackValueX30(vala);
//	vnb=TKD128_UnpackValueX30(valb);
	TKD128_UnpackValueX30R(&vna, &vala);
	TKD128_UnpackValueX30R(&vnb, &valb);
	vnc=TKD128_OprAdd(vna, vnb);
//	vpc=TKD128_PackValueX30(vnc);
	TKD128_PackValueX30R(&vnc, &vpc);
	return(vpc);
}

TKD128_Packed128 TKD128_OprMulX30(
	TKD128_Packed128 vala,
	TKD128_Packed128 valb)
{
	TKD128_Packed128 vpc;
	TKD128_Unpacked4x30 vna, vnb, vnc;

//	vna=TKD128_UnpackValueX30(vala);
//	vnb=TKD128_UnpackValueX30(valb);
	TKD128_UnpackValueX30R(&vna, &vala);
	TKD128_UnpackValueX30R(&vnb, &valb);
	vnc=TKD128_OprMul(vna, vnb);
//	vpc=TKD128_PackValueX30(vnc);
	TKD128_PackValueX30R(&vnc, &vpc);
	return(vpc);
}

char *TKD128_OprDumpAsStringDPD(TKD128_Packed128 val)
{
	return(TKD128_OprDumpAsString(TKD128_UnpackValueDPD(val)));
}

TKD128_Packed128 TKD128_OprParseFromStringDPD(char *str)
{
	return(TKD128_PackValueDPD(TKD128_OprParseFromString(str)));
}

// #define TEST_PI_DPD_HI		0x4329F0D84E95AF97
// #define TEST_PI_DPD_LO		0x7B1E09EE2B4D7F06
// 2F3F 1D4C 5D9C 1E8A
// 5E7F 1A5B 2C3A 5E3A

#define TEST_PI_DPD_HI		0x2200431857ACAD71ULL
#define TEST_PI_DPD_LO		0xF6F1CAC9A334F3DBULL


int main()
{
	TKD128_Packed128 vp0, vp1, vp2;
	TKD128_Unpacked4x30 vn0, vn1, vn2, vn3;
	u32 v0, v1, v2, v3;
	int t0, t1, t2, t0e;
	int i, n;
	
	TKD128_InitDPD();
	
	v0=0x12345678;

	v2=v0&1023;
	if(v2>=1000)	v2-=1000;
	v3=v0%1000;
	
	printf("A %d %d\n", v2, v3);
	
	v1=((((u64)v0)<<10)+(((u64)v0)<<4)+(((u64)v0)<<3))>>20;
	
//	v1=v0>>10;
//	v1=(v0+(v0>>6)+(v0>>7))>>10;
//	v1=v0/1000;
	v2=v0-v1*1000;
	if(v2>1000)
	{
		v1++;
		v2=v0-v1*1000;
	}
	printf("B %d (%X) %d %d\n", v2, v2, v1, v0/1000);
	
#if 1
	vp0.hi=TEST_PI_DPD_HI;
	vp0.lo=TEST_PI_DPD_LO;
	vn0=TKD128_UnpackValueDPD(vp0);
	printf("DPD Test:  %s\n",
		TKD128_OprDumpAsString(vn0));
#endif


	vn0.sgn=0;
	vn1.sgn=0;
	vn0.exp=TKD128_BIAS;
	vn1.exp=TKD128_BIAS;
	vn0.m[3]=  1234567;
	vn0.m[2]=890000000;
	vn0.m[1]=0;
	vn0.m[0]=0;

	vn1.m[3]=  3141592;
	vn1.m[2]=653589793;
	vn1.m[1]=238462643;
	vn1.m[0]=383279500;

	vp0=TKD128_PackValueDPD(vn0);
	vp1=TKD128_PackValueDPD(vn1);

	printf("%016llX %016llX\n", vp1.hi, vp1.lo);
	vn1=TKD128_UnpackValueDPD(vp1);
	
	for(i=0; i<16; i++)
	{
		printf("%02X ", ((byte *)(&vp1))[i]);
	}
	printf("\n");

	vn2=TKD128_OprParseFromString("987.654321");
	printf("Parse Test 1:  %s\n", TKD128_OprDumpAsString(vn2));
	vn2=TKD128_OprParseFromString("0.0707123");
	printf("Parse Test 2:  %s\n", TKD128_OprDumpAsString(vn2));

	t0=clock(); t0e=t0+CLOCKS_PER_SEC;
	t1=t0;	n=0;
	while(t1