@@ -849,8 +849,84 @@ inline std::string to_triple(const dd& v, int precision = 17) {
849
849
return s.str ();
850
850
}
851
851
852
- inline std::string to_binary (const dd& number, bool bNibbleMarker = false ) {
852
+ inline std::string to_binary (const dd& number, bool nibbleMarker = false ) {
853
853
std::stringstream s;
854
+
855
+ double_decoder decoder;
856
+ decoder.d = number.high ();
857
+ int highExponent = static_cast <int >(decoder.parts .exponent ) - ieee754_parameter<double >::bias;
858
+
859
+ s << " 0b" ;
860
+ // print sign bit
861
+ s << (decoder.parts .sign ? ' 1' : ' 0' ) << ' .' ;
862
+
863
+ // print exponent bits
864
+ {
865
+ uint64_t mask = 0x400ull ;
866
+ for (int bit = 10 ; bit >= 0 ; --bit) {
867
+ s << ((decoder.parts .exponent & mask) ? ' 1' : ' 0' );
868
+ if (nibbleMarker && bit != 0 && (bit % 4 ) == 0 ) s << ' \' ' ;
869
+ mask >>= 1 ;
870
+ }
871
+ }
872
+
873
+ s << ' .' ;
874
+
875
+ // print hi fraction bits
876
+ uint64_t mask = (1ull << 51 );
877
+ for (int bit = 51 ; bit >= 0 ; --bit) {
878
+ s << ((decoder.parts .fraction & mask) ? ' 1' : ' 0' );
879
+ if (nibbleMarker && bit != 0 && ((bit+1 ) % 4 ) == 0 ) s << ' \' ' ;
880
+ mask >>= 1 ;
881
+ }
882
+
883
+ // print lo fraction bits
884
+ decoder.d = number.low ();
885
+ // high limb low limb
886
+ // 52 51 ..... 3210 52 51 ...... 3210
887
+ // h. ffff ffff ...... ffff ffff h. ffff ffff ...... ffff ffff
888
+ // 105 104 53 52 51 ...... 3210 dd_bit
889
+ // | <--- exponent is exp(hi) - 53
890
+ // h. ffff ffff ...... ffff ffff 0. 0000 000h. ffff ffff ...... ffff ffff
891
+ // | <----- exponent would be exp(hi) - 61
892
+ // h. ffff ffff ...... ffff ffff 0. 0000 0000 ...... 000h. ffff ffff ...... ffff ffff
893
+ // | <----- exponent would be exp(hi) - 102
894
+ // h. ffff ffff ...... ffff ffff 0. 0000 0000 ...... 0000 000h. ffff ffff ...... ffff ffff
895
+ // | <----- exponent would be exp(hi) - 106
896
+ // the low segment is always in normal form
897
+ int lowExponent = static_cast <int >(decoder.parts .exponent ) - ieee754_parameter<double >::bias;
898
+
899
+ assert (highExponent >= lowExponent + 53 && " exponent of lower limb is not-aligned" );
900
+
901
+ // enumerate in the bit offset space of the double-double
902
+ // that means, the first bit of the second limb is bit (105 - 53) == 52 and it cycles down to 0
903
+ // representing 2^-53 through 2^-106 relative to the MSB of the high limb
904
+ int offset = highExponent - 53 - lowExponent - 1 ;
905
+ mask = (1ull << 51 );
906
+ s << ' |' ; // visual delineation between the two limbs
907
+ for (int ddbit = 52 ; ddbit >= 0 ; --ddbit) {
908
+ if (offset == 0 ) {
909
+ s << (decoder.d == 0.0 ? ' 0' : ' 1' ); // show hidden bit when not-zero
910
+ }
911
+ else if (offset > 0 ) {
912
+ // we have to introduce a leading zero as the hidden bit is positioned at a lower ddbit offset
913
+ s << ' 0' ;
914
+ }
915
+ else {
916
+ // we have reached the fraction bits
917
+ s << ((decoder.parts .fraction & mask) ? ' 1' : ' 0' );
918
+ mask >>= 1 ;
919
+ }
920
+ if (nibbleMarker && ddbit != 0 && (ddbit % 4 ) == 0 ) s << ' \' ' ;
921
+ --offset;
922
+ }
923
+
924
+ return s.str ();
925
+ }
926
+
927
+ inline std::string to_components (const dd& number, bool nibbleMarker = false ) {
928
+ std::stringstream s;
929
+ s << std::setprecision (16 );
854
930
constexpr int nrLimbs = 2 ;
855
931
for (int i = 0 ; i < nrLimbs; ++i) {
856
932
double_decoder decoder;
@@ -862,27 +938,27 @@ inline std::string to_binary(const dd& number, bool bNibbleMarker = false) {
862
938
// print sign bit
863
939
s << (decoder.parts .sign ? ' 1' : ' 0' ) << ' .' ;
864
940
865
- // print exponent bits
941
+ // print the segment's exponent bits
866
942
{
867
943
uint64_t mask = 0x400 ;
868
944
for (int bit = 10 ; bit >= 0 ; --bit) {
869
945
s << ((decoder.parts .exponent & mask) ? ' 1' : ' 0' );
870
- if (bNibbleMarker && bit != 0 && (bit % 4 ) == 0 ) s << ' \' ' ;
946
+ if (nibbleMarker && bit != 0 && (bit % 4 ) == 0 ) s << ' \' ' ;
871
947
mask >>= 1 ;
872
948
}
873
949
}
874
950
875
951
s << ' .' ;
876
952
877
- // print hi fraction bits
953
+ // print the segment's fraction bits
878
954
uint64_t mask = (uint64_t (1 ) << 51 );
879
955
for (int bit = 51 ; bit >= 0 ; --bit) {
880
956
s << ((decoder.parts .fraction & mask) ? ' 1' : ' 0' );
881
- if (bNibbleMarker && bit != 0 && (bit % 4 ) == 0 ) s << ' \' ' ;
957
+ if (nibbleMarker && bit != 0 && (bit % 4 ) == 0 ) s << ' \' ' ;
882
958
mask >>= 1 ;
883
959
}
884
960
885
- if (i < 1 ) s << ' \n ' ;
961
+ s << " : " << number[i] << " : binary scale " << scale (number[i]) << ' \n ' ;
886
962
}
887
963
888
964
return s.str ();
@@ -896,9 +972,11 @@ inline dd ulp(const dd& a) {
896
972
double nlo;
897
973
if (lo == 0.0 ) {
898
974
nlo = std::numeric_limits<double >::epsilon () / 2.0 ;
975
+ int binaryExponent = scale (hi) - 53 ;
976
+ nlo /= std::pow (2.0 , -binaryExponent);
899
977
}
900
978
else {
901
- nlo = std::nextafter (lo, INFINITY);
979
+ nlo = (hi < 0.0 ? std::nextafter (lo, - INFINITY) : std::nextafter (lo, +INFINITY) );
902
980
}
903
981
dd n (hi, nlo);
904
982
0 commit comments