PageRenderTime 43ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/cln-1.3.2/src/float/lfloat/elem/cl_LF_from_RA.cc

#
C++ | 146 lines | 75 code | 9 blank | 62 comment | 14 complexity | 36877b7cb8e08260ad566710f4b42117 MD5 | raw file
Possible License(s): GPL-2.0
  1. // cl_RA_to_LF().
  2. // General includes.
  3. #include "base/cl_sysdep.h"
  4. // Specification.
  5. #include "float/lfloat/cl_LF.h"
  6. // Implementation.
  7. #include "float/lfloat/cl_LF_impl.h"
  8. #include "rational/cl_RA.h"
  9. #include "cln/integer.h"
  10. #include "integer/cl_I.h"
  11. #include "float/cl_F.h"
  12. namespace cln {
  13. const cl_LF cl_RA_to_LF (const cl_RA& x, uintC len)
  14. {
  15. // Methode:
  16. // x ganz -> klar.
  17. // x = +/- a/b mit Integers a,b>0:
  18. // Sei k,m so gewählt, daß
  19. // 2^(k-1) <= a < 2^k, 2^(m-1) <= b < 2^m.
  20. // Dann ist 2^(k-m-1) < a/b < 2^(k-m+1).
  21. // Ergebnis-Vorzeichen := Vorzeichen von x.
  22. // Berechne k=(integer-length a) und m=(integer-length b).
  23. // Ergebnis-Exponent := k-m.
  24. // Ergebnis-Mantisse:
  25. // Berechne floor(2^(-k+m+16n+1)*a/b) :
  26. // Bei k-m>=16n+1 dividiere a durch (ash b (k-m-16n-1)),
  27. // bei k-m<16n+1 dividiere (ash a (-k+m+16n+1)) durch b.
  28. // Der erste Wert ist >=2^16n, <2^(16n+2).
  29. // Falls er >=2^(16n+1) ist, erhöhe Exponent um 1,
  30. // runde 2 Bits weg und schiebe dabei um 2 Bits nach rechts;
  31. // falls er <2^(16n+1) ist,
  32. // runde 1 Bit weg und schiebe dabei um 1 Bit nach rechts.
  33. // NB: Wenn a und b länger sind als len, ist dieser Algorithmus weniger
  34. // effizient, als cl_float(a,len)/cl_float(b,len) zu berechnen. Aber
  35. // es ist wichtig, dass cl_RA_to_LF nicht mehr als 0.5 ulp Fehler hat,
  36. // deswegen belassen wir es beim ineffizienten aber exakten Algorithmus.
  37. // Wenn es auf Rundungsfehler nicht ankommt, muss der Aufrufer im Fall
  38. // ceiling(integer_length(a),intDsize) >= len
  39. // && ceiling(integer_length(b),intDsize) >= len
  40. // einen anderen Algorithmus wählen.
  41. if (integerp(x)) {
  42. DeclareType(cl_I,x);
  43. return cl_I_to_LF(x,len);
  44. }
  45. { // x Ratio
  46. DeclareType(cl_RT,x);
  47. var cl_I a = numerator(x); // +/- a
  48. var const cl_I& b = denominator(x); // b
  49. var cl_signean sign = -(cl_signean)minusp(a); // Vorzeichen
  50. if (!(sign==0)) { a = -a; } // Betrag nehmen, liefert a
  51. var sintC lendiff = (sintC)integer_length(a) // (integer-length a)
  52. - (sintC)integer_length(b); // (integer-length b)
  53. // |lendiff| < intDsize*2^intCsize. Da für LF-Exponenten ein sintL zur
  54. // Verfügung steht, braucht man keinen Test auf Overflow oder Underflow.
  55. var uintC difflimit = intDsize*len + 1; // 16n+1
  56. var cl_I zaehler;
  57. var cl_I nenner;
  58. if (lendiff > (sintC)difflimit)
  59. // 0 <= k-m-16n-1 < k < intDsize*2^intCsize
  60. { nenner = ash(b,(uintC)(lendiff - difflimit));
  61. zaehler = a;
  62. }
  63. else
  64. // 0 < -k+m+16n+1 <= m+1 + 16n < intDsize*2^intCsize + intDsize*2^intCsize
  65. { zaehler = ash(a,(uintC)(difflimit - lendiff)); // (ash a -k+m+16n+1)
  66. nenner = b; // b
  67. }
  68. // Division zaehler/nenner durchführen:
  69. var cl_I_div_t q_r = cl_divide(zaehler,nenner);
  70. var cl_I& q = q_r.quotient;
  71. var cl_I& r = q_r.remainder;
  72. // 2^16n <= q < 2^(16n+2), also ist q Bignum mit n+1 Digits.
  73. var Lfloat y = allocate_lfloat(len,lendiff+LF_exp_mid,sign); // neues Long-Float
  74. var uintD* y_mantMSDptr = arrayMSDptr(TheLfloat(y)->data,len);
  75. {var uintD* q_MSDptr = arrayMSDptr(TheBignum(q)->data,len+1);
  76. if (mspref(q_MSDptr,0) == 1) // erstes Digit =1 oder =2,3 ?
  77. // 2^16n <= q < 2^(16n+1), also 2^(k-m-1) < a/b < 2^(k-m).
  78. { // Mantisse mit einer Schiebeschleife um 1 Bit nach rechts füllen:
  79. var uintD rounding_bit =
  80. shiftrightcopy_loop_msp(q_MSDptr mspop 1,y_mantMSDptr,len,1,1);
  81. if ( (rounding_bit == 0) // herausgeschobenes Bit =0 -> abrunden
  82. || ( eq(r,0) // =1 und Rest r > 0 -> aufrunden
  83. // round-to-even
  84. && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
  85. ) )
  86. goto ab; // abrunden
  87. else
  88. goto auf; // aufrunden
  89. }
  90. else
  91. // 2^(16n+1) <= q < 2^(16n+2), also 2^(k-m) < a/b < 2^(k-m+1).
  92. { // Mantisse mit einer Schiebeschleife um 2 Bit nach rechts füllen:
  93. var uintD rounding_bits =
  94. shiftrightcopy_loop_msp(q_MSDptr mspop 1,y_mantMSDptr,len,2,mspref(q_MSDptr,0));
  95. (TheLfloat(y)->expo)++; // Exponenten incrementieren auf k-m+1
  96. if ( ((sintD)rounding_bits >= 0) // herausgeschobenes Bit =0 -> abrunden
  97. || ( ((rounding_bits & bit(intDsize-2)) ==0) // =1 und nächstes Bit =1 oder Rest r > 0 -> aufrunden
  98. && eq(r,0)
  99. // round-to-even
  100. && ((mspref(y_mantMSDptr,len-1) & bit(0)) ==0)
  101. ) )
  102. goto ab; // abrunden
  103. else
  104. goto auf; // aufrunden
  105. }
  106. }
  107. auf: // aufrunden
  108. { if ( inc_loop_lsp(y_mantMSDptr mspop len,len) )
  109. // Übertrag durchs Aufrunden
  110. { mspref(y_mantMSDptr,0) = bit(intDsize-1); // Mantisse := 10...0
  111. (TheLfloat(y)->expo)++; // Exponenten incrementieren
  112. } }
  113. ab: // abrunden
  114. return y;
  115. }}
  116. // Timings on an i486 33 MHz, running Linux, in 0.01 sec.
  117. // First timing: cl_I_to_LF(numerator,len)/cl_I_to_LF(denominator,len)
  118. // Second timing: cl_RA_to_LF(x,len)
  119. // with len = 100.
  120. // num_length 50 70 100 200 500
  121. // den_length
  122. //
  123. // 50 1.86 0.97 1.84 0.97 1.85 0.96 1.86 1.86 1.85 7.14
  124. //
  125. // 70 1.86 1.33 1.85 1.31 1.85 1.32 1.84 1.84 1.85 7.13
  126. //
  127. // 100 1.85 1.85 1.86 1.85 1.85 1.84 1.84 1.84 1.86 7.13
  128. //
  129. // 200 1.85 3.61 1.84 3.61 1.85 3.59 1.85 3.59 1.87 7.12
  130. //
  131. // 500 1.84 7.44 1.84 7.55 1.85 7.56 1.84 7.66 1.86 7.63
  132. //
  133. // We see that cl_RA_to_LF is faster only if
  134. // num_length < 2*len && den_length < len
  135. // whereas cl_I_to_LF(numerator,len)/cl_I_to_LF(denominator,len) is faster if
  136. // num_length > 2*len || den_length > len
  137. } // namespace cln