@@ -8656,3 +8656,355 @@ mpd_qimport_u32(mpd_t *result,
86568656 mpd_qresize (result , result -> len , status );
86578657 mpd_qfinalize (result , ctx , status );
86588658}
8659+
8660+
8661+ /******************************************************************************/
8662+ /* From triple */
8663+ /******************************************************************************/
8664+
8665+ #if defined(CONFIG_64 ) && defined(__SIZEOF_INT128__ )
8666+ static mpd_ssize_t
8667+ _set_coeff (uint64_t data [3 ], uint64_t hi , uint64_t lo )
8668+ {
8669+ __uint128_t d = ((__uint128_t )hi << 64 ) + lo ;
8670+ __uint128_t q , r ;
8671+
8672+ q = d / MPD_RADIX ;
8673+ r = d % MPD_RADIX ;
8674+ data [0 ] = (uint64_t )r ;
8675+ d = q ;
8676+
8677+ q = d / MPD_RADIX ;
8678+ r = d % MPD_RADIX ;
8679+ data [1 ] = (uint64_t )r ;
8680+ d = q ;
8681+
8682+ q = d / MPD_RADIX ;
8683+ r = d % MPD_RADIX ;
8684+ data [2 ] = (uint64_t )r ;
8685+
8686+ if (q != 0 ) {
8687+ abort (); /* GCOV_NOT_REACHED */
8688+ }
8689+
8690+ return data [2 ] != 0 ? 3 : (data [1 ] != 0 ? 2 : 1 );
8691+ }
8692+ #else
8693+ static size_t
8694+ _uint_from_u16 (mpd_uint_t * w , mpd_ssize_t wlen , const uint16_t * u , size_t ulen )
8695+ {
8696+ const mpd_uint_t ubase = 1U <<16 ;
8697+ mpd_ssize_t n = 0 ;
8698+ mpd_uint_t carry ;
8699+
8700+ assert (wlen > 0 && ulen > 0 );
8701+
8702+ w [n ++ ] = u [-- ulen ];
8703+ while (-- ulen != SIZE_MAX ) {
8704+ carry = _mpd_shortmul_c (w , w , n , ubase );
8705+ if (carry ) {
8706+ if (n >= wlen ) {
8707+ abort (); /* GCOV_NOT_REACHED */
8708+ }
8709+ w [n ++ ] = carry ;
8710+ }
8711+ carry = _mpd_shortadd (w , n , u [ulen ]);
8712+ if (carry ) {
8713+ if (n >= wlen ) {
8714+ abort (); /* GCOV_NOT_REACHED */
8715+ }
8716+ w [n ++ ] = carry ;
8717+ }
8718+ }
8719+
8720+ return n ;
8721+ }
8722+
8723+ static mpd_ssize_t
8724+ _set_coeff (mpd_uint_t * data , mpd_ssize_t len , uint64_t hi , uint64_t lo )
8725+ {
8726+ uint16_t u16 [8 ] = {0 };
8727+
8728+ u16 [7 ] = (uint16_t )((hi & 0xFFFF000000000000ULL ) >> 48 );
8729+ u16 [6 ] = (uint16_t )((hi & 0x0000FFFF00000000ULL ) >> 32 );
8730+ u16 [5 ] = (uint16_t )((hi & 0x00000000FFFF0000ULL ) >> 16 );
8731+ u16 [4 ] = (uint16_t ) (hi & 0x000000000000FFFFULL );
8732+
8733+ u16 [3 ] = (uint16_t )((lo & 0xFFFF000000000000ULL ) >> 48 );
8734+ u16 [2 ] = (uint16_t )((lo & 0x0000FFFF00000000ULL ) >> 32 );
8735+ u16 [1 ] = (uint16_t )((lo & 0x00000000FFFF0000ULL ) >> 16 );
8736+ u16 [0 ] = (uint16_t ) (lo & 0x000000000000FFFFULL );
8737+
8738+ return (mpd_ssize_t )_uint_from_u16 (data , len , u16 , 8 );
8739+ }
8740+ #endif
8741+
8742+ static int
8743+ _set_uint128_coeff_exp (mpd_t * result , uint64_t hi , uint64_t lo , mpd_ssize_t exp )
8744+ {
8745+ mpd_uint_t data [5 ] = {0 };
8746+ uint32_t status = 0 ;
8747+ mpd_ssize_t len ;
8748+
8749+ #if defined(CONFIG_64 ) && defined(__SIZEOF_INT128__ )
8750+ len = _set_coeff (data , hi , lo );
8751+ #else
8752+ len = _set_coeff (data , 5 , hi , lo );
8753+ #endif
8754+
8755+ if (!mpd_qresize (result , len , & status )) {
8756+ return -1 ;
8757+ }
8758+
8759+ for (mpd_ssize_t i = 0 ; i < len ; i ++ ) {
8760+ result -> data [i ] = data [i ];
8761+ }
8762+
8763+ result -> exp = exp ;
8764+ result -> len = len ;
8765+ mpd_setdigits (result );
8766+
8767+ return 0 ;
8768+ }
8769+
8770+ int
8771+ mpd_from_uint128_triple (mpd_t * result , const mpd_uint128_triple_t * triple , uint32_t * status )
8772+ {
8773+ static const mpd_context_t maxcontext = {
8774+ .prec = MPD_MAX_PREC ,
8775+ .emax = MPD_MAX_EMAX ,
8776+ .emin = MPD_MIN_EMIN ,
8777+ .round = MPD_ROUND_HALF_EVEN ,
8778+ .traps = MPD_Traps ,
8779+ .status = 0 ,
8780+ .newtrap = 0 ,
8781+ .clamp = 0 ,
8782+ .allcr = 1 ,
8783+ };
8784+ const enum mpd_triple_class tag = triple -> tag ;
8785+ const uint8_t sign = triple -> sign ;
8786+ const uint64_t hi = triple -> hi ;
8787+ const uint64_t lo = triple -> lo ;
8788+ mpd_ssize_t exp ;
8789+
8790+ #ifdef CONFIG_32
8791+ if (triple -> exp < MPD_SSIZE_MIN || triple -> exp > MPD_SSIZE_MAX ) {
8792+ goto conversion_error ;
8793+ }
8794+ #endif
8795+ exp = (mpd_ssize_t )triple -> exp ;
8796+
8797+ switch (tag ) {
8798+ case MPD_TRIPLE_QNAN : case MPD_TRIPLE_SNAN : {
8799+ if (sign > 1 || exp != 0 ) {
8800+ goto conversion_error ;
8801+ }
8802+
8803+ const uint8_t flags = tag == MPD_TRIPLE_QNAN ? MPD_NAN : MPD_SNAN ;
8804+ mpd_setspecial (result , sign , flags );
8805+
8806+ if (hi == 0 && lo == 0 ) { /* no payload */
8807+ return 0 ;
8808+ }
8809+
8810+ if (_set_uint128_coeff_exp (result , hi , lo , exp ) < 0 ) {
8811+ goto malloc_error ;
8812+ }
8813+
8814+ return 0 ;
8815+ }
8816+
8817+ case MPD_TRIPLE_INF : {
8818+ if (sign > 1 || hi != 0 || lo != 0 || exp != 0 ) {
8819+ goto conversion_error ;
8820+ }
8821+
8822+ mpd_setspecial (result , sign , MPD_INF );
8823+
8824+ return 0 ;
8825+ }
8826+
8827+ case MPD_TRIPLE_NORMAL : {
8828+ if (sign > 1 ) {
8829+ goto conversion_error ;
8830+ }
8831+
8832+ const uint8_t flags = sign ? MPD_NEG : MPD_POS ;
8833+ mpd_set_flags (result , flags );
8834+
8835+ if (exp > MPD_EXP_INF ) {
8836+ exp = MPD_EXP_INF ;
8837+ }
8838+ if (exp == MPD_SSIZE_MIN ) {
8839+ exp = MPD_SSIZE_MIN + 1 ;
8840+ }
8841+
8842+ if (_set_uint128_coeff_exp (result , hi , lo , exp ) < 0 ) {
8843+ goto malloc_error ;
8844+ }
8845+
8846+ uint32_t workstatus = 0 ;
8847+ mpd_qfinalize (result , & maxcontext , & workstatus );
8848+ if (workstatus & (MPD_Inexact |MPD_Rounded |MPD_Clamped )) {
8849+ goto conversion_error ;
8850+ }
8851+
8852+ return 0 ;
8853+ }
8854+
8855+ default :
8856+ goto conversion_error ;
8857+ }
8858+
8859+ conversion_error :
8860+ mpd_seterror (result , MPD_Conversion_syntax , status );
8861+ return -1 ;
8862+
8863+ malloc_error :
8864+ mpd_seterror (result , MPD_Malloc_error , status );
8865+ return -1 ;
8866+ }
8867+
8868+
8869+ /******************************************************************************/
8870+ /* As triple */
8871+ /******************************************************************************/
8872+
8873+ #if defined(CONFIG_64 ) && defined(__SIZEOF_INT128__ )
8874+ static void
8875+ _get_coeff (uint64_t * hi , uint64_t * lo , const mpd_t * a )
8876+ {
8877+ __uint128_t u128 = 0 ;
8878+
8879+ switch (a -> len ) {
8880+ case 3 :
8881+ u128 = a -> data [2 ]; /* fall through */
8882+ case 2 :
8883+ u128 = u128 * MPD_RADIX + a -> data [1 ]; /* fall through */
8884+ case 1 :
8885+ u128 = u128 * MPD_RADIX + a -> data [0 ];
8886+ break ;
8887+ default :
8888+ abort (); /* GCOV_NOT_REACHED */
8889+ }
8890+
8891+ * hi = u128 >> 64 ;
8892+ * lo = (uint64_t )u128 ;
8893+ }
8894+ #else
8895+ static size_t
8896+ _uint_to_u16 (uint16_t w [8 ], mpd_uint_t * u , mpd_ssize_t ulen )
8897+ {
8898+ const mpd_uint_t wbase = 1U <<16 ;
8899+ size_t n = 0 ;
8900+
8901+ assert (ulen > 0 );
8902+
8903+ do {
8904+ if (n >= 8 ) {
8905+ abort (); /* GCOV_NOT_REACHED */
8906+ }
8907+ w [n ++ ] = (uint16_t )_mpd_shortdiv (u , u , ulen , wbase );
8908+ /* ulen is at least 1. u[ulen-1] can only be zero if ulen == 1. */
8909+ ulen = _mpd_real_size (u , ulen );
8910+
8911+ } while (u [ulen - 1 ] != 0 );
8912+
8913+ return n ;
8914+ }
8915+
8916+ static void
8917+ _get_coeff (uint64_t * hi , uint64_t * lo , const mpd_t * a )
8918+ {
8919+ uint16_t u16 [8 ] = {0 };
8920+ mpd_uint_t data [5 ] = {0 };
8921+
8922+ switch (a -> len ) {
8923+ case 5 :
8924+ data [4 ] = a -> data [4 ]; /* fall through */
8925+ case 4 :
8926+ data [3 ] = a -> data [3 ]; /* fall through */
8927+ case 3 :
8928+ data [2 ] = a -> data [2 ]; /* fall through */
8929+ case 2 :
8930+ data [1 ] = a -> data [1 ]; /* fall through */
8931+ case 1 :
8932+ data [0 ] = a -> data [0 ];
8933+ break ;
8934+ default :
8935+ abort (); /* GCOV_NOT_REACHED */
8936+ }
8937+
8938+ _uint_to_u16 (u16 , data , a -> len );
8939+
8940+ * hi = (uint64_t )u16 [7 ] << 48 ;
8941+ * hi |= (uint64_t )u16 [6 ] << 32 ;
8942+ * hi |= (uint64_t )u16 [5 ] << 16 ;
8943+ * hi |= (uint64_t )u16 [4 ];
8944+
8945+ * lo = (uint64_t )u16 [3 ] << 48 ;
8946+ * lo |= (uint64_t )u16 [2 ] << 32 ;
8947+ * lo |= (uint64_t )u16 [1 ] << 16 ;
8948+ * lo |= (uint64_t )u16 [0 ];
8949+ }
8950+ #endif
8951+
8952+ static enum mpd_triple_class
8953+ _coeff_as_uint128 (uint64_t * hi , uint64_t * lo , const mpd_t * a )
8954+ {
8955+ #ifdef CONFIG_64
8956+ static mpd_uint_t uint128_max_data [3 ] = { 3374607431768211455ULL , 4028236692093846346ULL , 3ULL };
8957+ static const mpd_t uint128_max = { MPD_STATIC |MPD_CONST_DATA , 0 , 39 , 3 , 3 , uint128_max_data };
8958+ #else
8959+ static mpd_uint_t uint128_max_data [5 ] = { 768211455U , 374607431U , 938463463U , 282366920U , 340U };
8960+ static const mpd_t uint128_max = { MPD_STATIC |MPD_CONST_DATA , 0 , 39 , 5 , 5 , uint128_max_data };
8961+ #endif
8962+ enum mpd_triple_class ret = MPD_TRIPLE_NORMAL ;
8963+ uint32_t status = 0 ;
8964+ mpd_t coeff ;
8965+
8966+ * hi = * lo = 0ULL ;
8967+
8968+ if (mpd_isspecial (a )) {
8969+ if (mpd_isinfinite (a )) {
8970+ return MPD_TRIPLE_INF ;
8971+ }
8972+
8973+ ret = mpd_isqnan (a ) ? MPD_TRIPLE_QNAN : MPD_TRIPLE_SNAN ;
8974+ if (a -> len == 0 ) { /* no payload */
8975+ return ret ;
8976+ }
8977+ }
8978+ else if (mpd_iszero (a )) {
8979+ return ret ;
8980+ }
8981+
8982+ _mpd_copy_shared (& coeff , a );
8983+ mpd_set_flags (& coeff , 0 );
8984+ coeff .exp = 0 ;
8985+
8986+ if (mpd_qcmp (& coeff , & uint128_max , & status ) > 0 ) {
8987+ return MPD_TRIPLE_ERROR ;
8988+ }
8989+
8990+ _get_coeff (hi , lo , & coeff );
8991+ return ret ;
8992+ }
8993+
8994+ mpd_uint128_triple_t
8995+ mpd_as_uint128_triple (const mpd_t * a )
8996+ {
8997+ mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR , 0 , 0 , 0 , 0 };
8998+
8999+ triple .tag = _coeff_as_uint128 (& triple .hi , & triple .lo , a );
9000+ if (triple .tag == MPD_TRIPLE_ERROR ) {
9001+ return triple ;
9002+ }
9003+
9004+ triple .sign = !!mpd_isnegative (a );
9005+ if (triple .tag == MPD_TRIPLE_NORMAL ) {
9006+ triple .exp = a -> exp ;
9007+ }
9008+
9009+ return triple ;
9010+ }
0 commit comments