@@ -8656,3 +8656,355 @@ mpd_qimport_u32(mpd_t *result,
8656
8656
mpd_qresize (result , result -> len , status );
8657
8657
mpd_qfinalize (result , ctx , status );
8658
8658
}
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