bartekltg

mnozenie odporne na przepelnienie

Oct 14th, 2016
145
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.29 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <random>
  5. #include <cmath>
  6. #include <chrono>
  7.  
  8.  
  9. using namespace std;
  10.  
  11. class stoper
  12. {
  13.     chrono::time_point<chrono::high_resolution_clock> a,b;
  14. public:
  15.     void start(){a = chrono::high_resolution_clock::now();}
  16.     void stop() {b = chrono::high_resolution_clock::now();}
  17.     double value()
  18.     {
  19.         chrono::duration<double> elapsed_seconds = b-a;
  20.         return elapsed_seconds.count();
  21.     }
  22. };
  23.  
  24. template <typename F>
  25. void test(F fun)
  26. {
  27.     stoper st;
  28.     st.start();
  29.     fun();
  30.     st.stop();
  31.     cout<<st.value()<< " s"<<endl;
  32. }
  33.  
  34.  
  35. template <typename iter_t >
  36. typename iter_t::value_type stable_mul_1 ( const iter_t first, const iter_t last ){
  37.     using T = typename iter_t::value_type;
  38.     constexpr T one = T(1);
  39.  
  40.     auto big=first;
  41.     auto small = first;
  42.     T result =  one;
  43.  
  44.     while ( abs(*small) >= one && small!=last ) ++small;
  45.     while ( abs(*big)   < one && big  !=last ) ++big;
  46.  
  47.     while ((big!= last) && (small !=last))    {
  48.  
  49.         while( abs(result) >= one && small!=last  ) {
  50.             //cout<<"mul "<< *small<<endl;
  51.             result *= *(small++);
  52.  
  53.             while ( abs(*small) >= one && small!=last ) ++small;
  54.         }
  55.         while( abs(result) < one && big!=last  ) {
  56.           //  cout<<"mul "<< *big<<endl;
  57.             result *= *(big++);
  58.  
  59.             while ( abs(*big)   < one && big  !=last ) ++big;
  60.         }
  61.     }
  62.  
  63.     //ogon
  64.  
  65.     while( small!=last  ) {
  66.         //cout<<"mul "<< *small<<endl;
  67.         result *= *(small++);
  68.         while ( abs(*small) >= one && small!=last ) ++small;
  69.  
  70.     }
  71.  
  72.     while( big!=last  )
  73.     {
  74. //        cout<<"mul "<< *big<<endl;
  75.         result *= *(big++);
  76.         while ( abs(*big)   < one && big  !=last ) ++big;
  77.  
  78.     }
  79.     return result;
  80. }
  81.  
  82. template <typename iter_t >
  83. typename iter_t::value_type stable_mul_partition (const iter_t first, const iter_t last ){
  84.     using T = typename iter_t::value_type;
  85.     constexpr T one = T(1);
  86.  
  87.     auto mid = partition(first, last, [](T x) {return abs(x)>one;} );
  88.  
  89.     auto small = mid;
  90.     auto big = first;
  91.  
  92.     T result =  one;
  93.  
  94.     while ((big!= mid ) && (small !=last))  {
  95.         if (abs( result) >= one)
  96.             result*= *(small++);
  97.         else
  98.             result*= *(big++);
  99.     }
  100.     while (big!= mid )
  101.         result*= *(big++);
  102.     while (small != last )
  103.         result*= *(small++);
  104.    return result;
  105. }
  106.  
  107. template <typename iter_t >
  108. typename iter_t::value_type stable_mul_frexp ( iter_t first, const iter_t last ){
  109.     using T = typename iter_t::value_type;
  110.     constexpr T one = T(1);
  111.  
  112.     T result =  one;
  113.     int_fast64_t ex=0;
  114.     int tex;
  115.  
  116.     for (; first !=last;++first )    {
  117.         result*= *first;
  118.         result=frexp(result,&tex);
  119.         ex+=tex;
  120.     }
  121.    return ldexp(result,ex);
  122. }
  123.  
  124.  
  125. int main()
  126. {
  127.  
  128.     vector<double> tab;
  129.  
  130.     tab.resize(1000000);
  131.  
  132.     random_device rd;
  133.  
  134.     mt19937 gen(rd());
  135.  
  136.  
  137.     lognormal_distribution<double> dist(0.0,50.0);//liczby z roskładu lognormalnego z ogromnego zasięgu
  138.     generate(begin(tab),end(tab),[&]{return dist(gen);});
  139.     for (auto it=tab.rbegin(); it!= prev(tab.rend()); ++it) {
  140.         *it= *it/(*(next(it)));                         // właściwe liczby to ilorazy, gwarantuje to, że wynik mnozenia jest w zakresie
  141.     }
  142.     shuffle(begin(tab),end(tab),gen); // wymieszajmy kolejność, wtedy zwykłe mnożenie najprawdopodobniej wpadnie na +-inf
  143.  
  144.  
  145.     cout<<"probka liczb"<<endl;
  146.     for (int i=0;i<20;i+=2)    {
  147.        cout<<tab[i]<<endl;
  148.     }
  149.     cout<<"koniec probki liczb"<<endl;
  150.  
  151.  
  152.     cout<<"mnozenie standardowe "<<accumulate(begin(tab),end(tab),1.0,std::multiplies<double>() )<<endl;
  153.  
  154.  
  155.    double logacu=0.0;
  156.  
  157.    for (auto it=begin(tab); it!= end(tab);++it)
  158.        logacu+=log(*it);
  159.    cout<<"dodawanie logarytmów "<<exp(logacu)<<endl;
  160.  
  161.     test( [&] {cout<<"podwojny przelot     "<< stable_mul_1(begin(tab),end(tab)) <<" ";});
  162.  
  163.     test( [&] {cout<<"frexp                "<< stable_mul_frexp(begin(tab),end(tab)) <<" ";});
  164.  
  165.     test( [&] {cout<<"partition            "<< stable_mul_partition(begin(tab),end(tab)) <<" ";});
  166.  
  167.     return 0;
  168. }
  169.  
  170.  
  171. /*
  172.  
  173. probka liczb
  174. 1.7583e+33
  175. 1.93469e+44
  176. 4.25265e-75
  177. 1.59875e+27
  178. 2.43612e-19
  179. 4.97215e+39
  180. 2.14228e-19
  181. 2.37518e+29
  182. 3.94031e-62
  183. 3.15255e+81
  184. koniec probki liczb
  185. mnozenie standardowe inf
  186. dodawanie logarytmów 4.11519e-05
  187. podwojny przelot     4.11519e-05 0.0829092 s
  188. frexp                4.11519e-05 0.0293514 s
  189. partition            4.11519e-05 0.080956 s
  190. **************************
  191. probka liczb
  192. 1.63243e+13
  193. 90.8683
  194. 7.364e-11
  195. 6.92679e+10
  196. 5.5909e+83
  197. 1.15735e-06
  198. 2.54212e+56
  199. 4.15332e-49
  200. 193442
  201. 1.75265e-41
  202. koniec probki liczb
  203. mnozenie standardowe inf
  204. dodawanie logarytmów 107.279
  205. podwojny przelot     107.279 0.0825575 s
  206. frexp                107.279 0.0291725 s
  207. partition            107.279 0.0868694 s
  208.  
  209. *****************************
  210. probka liczb
  211. 7.86603e+19
  212. 431585
  213. 3.34872e-56
  214. 9.67111e+29
  215. 1.69078e-08
  216. 1.24735e-26
  217. 2.94383e+21
  218. 1.00652e+52
  219. 1.4806e+16
  220. 3.64962e-07
  221. koniec probki liczb
  222. mnozenie standardowe inf
  223. dodawanie logarytmów 4.06236e-07
  224. podwojny przelot     4.06236e-07 0.0828723 s
  225. frexp                4.06236e-07 0.029212 s
  226. partition            4.06236e-07 0.0832593 s
  227.  
  228.  
  229.  
  230. */
Add Comment
Please, Sign In to add comment