// sqrt(). // General includes. #include "cl_sysdep.h" // Specification. #include "cln/dfloat.h" // Implementation. #include "cl_DF.h" #include "cl_F.h" #include "cl_low.h" #include "cl_DS.h" namespace cln { const cl_DF sqrt (const cl_DF& x) { // Methode: // x = 0.0 -> Ergebnis 0.0 // Ergebnis-Vorzeichen := positiv, // Ergebnis-Exponent := ceiling(e/2), // Ergebnis-Mantisse: // Bilde aus [1,m51,...,m0,(55 Nullbits)] bei geradem e, // aus [0,1,m51,...,m0,(54 Nullbits)] bei ungeradem e // die Ganzzahl-Wurzel, eine 54-Bit-Zahl mit einer führenden 1. // Runde das letzte Bit weg: // Bit 0 = 0 -> abrunden, // Bit 0 = 1 und Wurzel exakt -> round-to-even, // Bit 0 = 1 und Rest >0 -> aufrunden. // Dabei um ein Bit nach rechts schieben. // Bei Aufrundung auf 2^53 (rounding overflow) Mantisse um 1 Bit nach rechts // schieben und Exponent incrementieren. #if (cl_word_size==64) // x entpacken: var sintL exp; var uint64 mantx; DF_decode(x, { return x; }, ,exp=,mantx=); // Um die 128-Bit-Ganzzahl-Wurzel ausnutzen zu können, fügen wir beim // Radikanden 74 bzw. 75 statt 54 bzw. 55 Nullbits an. if (exp & bit(0)) // e ungerade { mantx = mantx << (63-(DF_mant_len+1)); exp = exp+1; } else // e gerade { mantx = mantx << (64-(DF_mant_len+1)); } exp = exp >> 1; // exp := exp/2 var uintD mant [128/intDsize]; #if (intDsize==64) arrayLSref(mant,128/intDsize,1) = mantx; arrayLSref(mant,128/intDsize,0) = 0; #else // (intDsize<=32) set_32_Dptr(arrayMSDptr(mant,128/intDsize),(uint32)(mantx>>32)); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 32/intDsize,(uint32)mantx); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 2*32/intDsize,0); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 3*32/intDsize,0); #endif {CL_ALLOCA_STACK; var DS wurzel; var cl_boolean exactp; UDS_sqrt(arrayMSDptr(mant,128/intDsize),128/intDsize,arrayLSDptr(mant,128/intDsize), &wurzel, exactp=); // wurzel = isqrt(2^74_75 * mant), eine 64-Bit-Zahl. mantx = get_64_Dptr(wurzel.MSDptr); // Die hinteren 63-DF_mant_len Bits wegrunden: if ( ((mantx & bit(62-DF_mant_len)) ==0) // Bit 10 =0 -> abrunden || ( ((mantx & (bit(62-DF_mant_len)-1)) ==0) // Bit 10 =1 und Bits 9..0 >0 -> aufrunden && exactp // Bit 10 =1 und Bits 9..0 =0, aber Rest -> aufrunden // round-to-even, je nach Bit 11 : && ((mantx & bit(63-DF_mant_len)) ==0) ) ) // abrunden { mantx = mantx >> (63-DF_mant_len); } else // aufrunden { mantx = mantx >> (63-DF_mant_len); mantx += 1; if (mantx >= bit(DF_mant_len+1)) // rounding overflow? { mantx = mantx>>1; exp = exp+1; } } } return encode_DF(0,exp,mantx); #else // x entpacken: var sintL exp; var uint32 manthi; var uint32 mantlo; DF_decode2(x, { return x; }, ,exp=,manthi=,mantlo=); // Um die 128-Bit-Ganzzahl-Wurzel ausnutzen zu können, fügen wir beim // Radikanden 74 bzw. 75 statt 54 bzw. 55 Nullbits an. if (exp & bit(0)) // e ungerade { manthi = (manthi << (63-(DF_mant_len+1))) | (mantlo >> ((DF_mant_len+1)-31)); mantlo = mantlo << (63-(DF_mant_len+1)); exp = exp+1; } else // e gerade { manthi = (manthi << (64-(DF_mant_len+1))) | (mantlo >> ((DF_mant_len+1)-32)); mantlo = mantlo << (64-(DF_mant_len+1)); } exp = exp >> 1; // exp := exp/2 var uintD mant [128/intDsize]; #if (intDsize==32) || (intDsize==16) || (intDsize==8) set_32_Dptr(arrayMSDptr(mant,128/intDsize),manthi); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 32/intDsize,mantlo); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 2*32/intDsize,0); set_32_Dptr(arrayMSDptr(mant,128/intDsize) mspop 3*32/intDsize,0); #else {var uintD* ptr; ptr = arrayLSDptr(mant,128/intDsize); doconsttimes(64/intDsize, { lsprefnext(ptr) = 0; } ); doconsttimes(32/intDsize, { lsprefnext(ptr) = (uintD)mantlo; mantlo = mantlo>>intDsize; } ); doconsttimes(32/intDsize, { lsprefnext(ptr) = (uintD)manthi; manthi = manthi>>intDsize; } ); } #endif {CL_ALLOCA_STACK; var DS wurzel; var cl_boolean exactp; UDS_sqrt(arrayMSDptr(mant,128/intDsize),128/intDsize,arrayLSDptr(mant,128/intDsize), &wurzel, exactp=); // wurzel = isqrt(2^74_75 * mant), eine 64-Bit-Zahl. {var uintD* ptr = wurzel.MSDptr; manthi = get_32_Dptr(ptr); mantlo = get_32_Dptr(ptr mspop 32/intDsize); } // Die hinteren 63-DF_mant_len Bits wegrunden: if ( ((mantlo & bit(62-DF_mant_len)) ==0) // Bit 10 =0 -> abrunden || ( ((mantlo & (bit(62-DF_mant_len)-1)) ==0) // Bit 10 =1 und Bits 9..0 >0 -> aufrunden && exactp // Bit 10 =1 und Bits 9..0 =0, aber Rest -> aufrunden // round-to-even, je nach Bit 11 : && ((mantlo & bit(63-DF_mant_len)) ==0) ) ) // abrunden { mantlo = (mantlo >> (63-DF_mant_len)) | (manthi << (DF_mant_len-32+1)); manthi = manthi >> (63-DF_mant_len); } else // aufrunden { mantlo = (mantlo >> (63-DF_mant_len)) | (manthi << (DF_mant_len-32+1)); manthi = manthi >> (63-DF_mant_len); mantlo += 1; if (mantlo==0) { manthi += 1; if (manthi >= bit(DF_mant_len-32+1)) // rounding overflow? { manthi = manthi>>1; exp = exp+1; } } } } return encode_DF(0,exp,manthi,mantlo); #endif } } // namespace cln