Advertisement
homer512

Mandelbrot

Apr 22nd, 2017
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.48 KB | None | 0 0
  1. /**
  2.  * Author: F. Philipp
  3.  *
  4.  * Translation of
  5.  * https://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=rust&id=4
  6.  * with minor changes
  7.  *
  8.  * Contains a bug resulting in slightly different results
  9.  */
  10.  
  11. #include <array>
  12. // using std::array
  13. #include <vector>
  14. // using std::vector
  15. #include <tuple>
  16. // using std::tuple
  17. #include <string>
  18. // using std::stoi
  19. #include <iostream>
  20. // using std::cout
  21. #include <algorithm>
  22. // using std::transform, std::all_of
  23. #include <functional>
  24. // using std::bind, std::placeholders, std::multiplies, std::plus, std::minus
  25. #include <climits>
  26. // using CHAR_BIT
  27.  
  28.  
  29. namespace {
  30.  
  31.   constexpr int MAX_ITER = 50;
  32.   constexpr int VLEN = CHAR_BIT;
  33.   typedef double double_t;
  34.  
  35.   struct Vecf64
  36.   {
  37.     using array_type = std::array<double_t, VLEN>;
  38.     array_type array;
  39.  
  40.     Vecf64() = default;
  41.  
  42.     explicit Vecf64(double_t s) noexcept
  43.     { array.fill(s); }
  44.  
  45.     Vecf64& operator=(const Vecf64&) = default;
  46.  
  47.     Vecf64& operator=(double_t s) noexcept
  48.     {
  49.       array.fill(s);
  50.       return *this;
  51.     }
  52.     double_t& operator[](int idx) noexcept
  53.     { return array[idx]; }
  54.  
  55.     double_t operator[](int idx) const noexcept
  56.     { return array[idx]; }
  57.  
  58.     template<class BinaryFunctor>
  59.     Vecf64& inplace_transform(const Vecf64& o, BinaryFunctor f)
  60.     {
  61.       array_type::iterator first = array.begin();
  62.       std::transform(first, array.end(), o.array.begin(), first, f);
  63.       return *this;
  64.     }
  65.     template<class BinaryFunctor>
  66.     Vecf64 transform(const Vecf64& o, BinaryFunctor f) const
  67.     {
  68.       Vecf64 rtrn;
  69.       std::transform(array.begin(), array.end(), o.array.begin(),
  70.                      rtrn.array.begin(), f);
  71.       return rtrn;
  72.     }
  73.     template<class UnaryFunctor>
  74.     Vecf64& inplace_transform(UnaryFunctor f)
  75.     {
  76.       array_type::iterator first = array.begin();
  77.       std::transform(first, array.end(), first, f);
  78.       return *this;
  79.     }
  80.     template<class UnaryFunctor>
  81.     Vecf64 transform(UnaryFunctor f) const
  82.     {
  83.       Vecf64 rtrn;
  84.       std::transform(array.begin(), array.end(), rtrn.array.begin(), f);
  85.       return rtrn;
  86.     }
  87.  
  88.     Vecf64& operator*=(const Vecf64& o) noexcept
  89.     { return inplace_transform(o, std::multiplies<double_t>{}); }
  90.  
  91.     Vecf64 operator*(const Vecf64& o) const noexcept
  92.     { return transform(o, std::multiplies<double_t>{}); }
  93.  
  94.     Vecf64& operator*=(double_t s) noexcept
  95.     {
  96.       return inplace_transform(std::bind(std::multiplies<double_t>{},
  97.                                          std::placeholders::_1, s));
  98.     }
  99.     Vecf64 operator*(double_t s) const noexcept
  100.     {
  101.       return transform(std::bind(std::multiplies<double_t>{},
  102.                                  std::placeholders::_1, s));
  103.     }
  104.     friend Vecf64 operator*(double_t left, const Vecf64& right) noexcept
  105.     { return right * left; }
  106.  
  107.     Vecf64& operator+=(const Vecf64& o) noexcept
  108.     { return inplace_transform(o, std::plus<double_t>{}); }
  109.  
  110.     Vecf64 operator+(const Vecf64& o) const noexcept
  111.     { return transform(o, std::plus<double_t>{}); }
  112.  
  113.     Vecf64& operator+=(double_t s) noexcept
  114.     {
  115.       return inplace_transform(std::bind(std::plus<double_t>{},
  116.                                          std::placeholders::_1, s));
  117.     }
  118.     Vecf64 operator+(double_t s) const noexcept
  119.     {
  120.       return transform(std::bind(std::plus<double_t>{},
  121.                                  std::placeholders::_1, s));
  122.     }
  123.     friend Vecf64 operator+(double_t left, const Vecf64& right) noexcept
  124.     { return right + left; }
  125.  
  126.     Vecf64& operator-=(const Vecf64& o) noexcept
  127.     { return inplace_transform(o, std::minus<double_t>{}); }
  128.  
  129.     Vecf64 operator-(const Vecf64& o) const noexcept
  130.     { return transform(o, std::minus<double_t>{}); }
  131.  
  132.     Vecf64& operator-=(double_t s) noexcept
  133.     {
  134.       return inplace_transform(std::bind(std::minus<double_t>{},
  135.                                          std::placeholders::_1, s));
  136.     }
  137.     Vecf64 operator-(double_t s) const noexcept
  138.     {
  139.       return transform(std::bind(std::minus<double_t>{},
  140.                                  std::placeholders::_1, s));
  141.     }
  142.     friend Vecf64 operator-(double_t left, const Vecf64& right) noexcept
  143.     {
  144.       return right.transform(std::bind(std::minus<double_t>{},
  145.                                        left, std::placeholders::_1));
  146.     }
  147.     Vecf64& inplace_square() noexcept
  148.     {
  149.       return inplace_transform(std::bind(std::multiplies<double_t>{},
  150.                                          std::placeholders::_1,
  151.                                          std::placeholders::_1));
  152.     }
  153.     Vecf64 square() const noexcept
  154.     {
  155.       return transform(std::bind(std::multiplies<double_t>{},
  156.                                  std::placeholders::_1,
  157.                                  std::placeholders::_1));
  158.     }
  159.     template<class Predicate>
  160.     bool all(Predicate p) const
  161.     { return std::all_of(array.begin(), array.end(), p); }
  162.   };
  163.  
  164.   struct CrCr2Chunk
  165.   {
  166.     Vecf64 cr, cr2;
  167.   };
  168.  
  169.   class Mandelbrot8
  170.   {
  171.     Vecf64 zr, zi, tr, ti, cr;
  172.     double_t ci, ci2;
  173.  
  174.     void advance(int iterations) noexcept
  175.     {
  176.       for(int i = 0; i < iterations; ++i) {
  177.         zi = 2. * zr * zi + ci;
  178.         zr = tr - ti + cr;
  179.         tr = zr.square();
  180.         ti = zi.square();
  181.       }
  182.     }
  183.     bool all_diverged() const noexcept
  184.     {
  185.       auto diverged = std::bind(std::greater<double_t>{},
  186.                                 std::placeholders::_1,
  187.                                 4.);
  188.       return (tr + ti).all(diverged);
  189.     }
  190.     unsigned char to_byte() const noexcept
  191.     {
  192.       const Vecf64 trti = tr + ti;
  193.       unsigned char accu = 0;
  194.       for(int i = 0; i < VLEN; ++i) {
  195.         if(trti[i] <= 4.)
  196.           accu |= 0x80 >> i;
  197.       }
  198.       return accu;
  199.     }
  200.   public:
  201.     explicit Mandelbrot8(double_t ci) noexcept
  202.       : ci(ci),
  203.         ci2(ci * ci)
  204.     {}
  205.     unsigned char operator()(const CrCr2Chunk& col_invariant) noexcept
  206.     {
  207.       zr = col_invariant.cr;
  208.       zi = ci;
  209.       tr = col_invariant.cr2;
  210.       ti = ci2;
  211.       cr = col_invariant.cr;
  212.       advance(4);
  213.       constexpr int n = MAX_ITER / 5 - 1;
  214.       for(int i = 0; i < n; ++i) {
  215.         if(all_diverged())
  216.           return 0;
  217.         advance(4);
  218.       }
  219.       return to_byte();
  220.     }
  221.   };
  222.  
  223.   std::vector<CrCr2Chunk> make_column_invariant(int bytes_per_line)
  224.   {
  225.     const int pixels_per_line = bytes_per_line * VLEN;
  226.     const double_t inv = 2. / pixels_per_line;
  227.     std::vector<CrCr2Chunk> rtrn(bytes_per_line);
  228. #   pragma omp parallel for
  229.     for(int col_byte = 0; col_byte < bytes_per_line; ++col_byte) {
  230.       CrCr2Chunk& chunk = rtrn[col_byte];
  231.       for(int bit = 0; bit < VLEN; ++bit) {
  232.         const int col = col_byte * VLEN + bit;
  233.         chunk.cr[bit] = col * inv - 1.5;
  234.       }
  235.       chunk.cr2 = chunk.cr.square();
  236.     }
  237.     return rtrn;
  238.   }
  239.  
  240.   std::vector<unsigned char>
  241.   make_bitmap(const std::vector<CrCr2Chunk>& column_invariants)
  242.   {
  243.     const int bytes_per_line = static_cast<int>(column_invariants.size());
  244.     const int pixels_per_line = bytes_per_line * VLEN;
  245.     const double_t inv = 2. / pixels_per_line;
  246.     std::vector<unsigned char> bitmap(pixels_per_line * bytes_per_line);
  247. #   pragma omp parallel for
  248.     for(int row = 0; row < pixels_per_line; ++row) {
  249.       const int start = row * bytes_per_line;
  250.       const double_t ci = row * inv - 1.;
  251.       std::transform(column_invariants.begin(), column_invariants.end(),
  252.                      bitmap.begin() + start,
  253.                      Mandelbrot8(ci));
  254.     }
  255.     return bitmap;
  256.   }
  257.   void print_pbm(const std::vector<unsigned char>& bitmap,
  258.                  int pixels_per_line,
  259.                  std::ostream& binary_output)
  260.   {
  261.     binary_output << "P4\n" << pixels_per_line
  262.                   << ' ' << pixels_per_line
  263.                   << '\n';
  264.     binary_output.write(reinterpret_cast<const char*>(bitmap.data()),
  265.                         bitmap.size());
  266.     binary_output.flush();
  267.   }
  268. }
  269.  
  270. int main(int argc, char** argv)
  271. {
  272.   /* number of pixels in each dimension */
  273.   int pixels_per_line = 200;
  274.   if(argc > 1)
  275.     pixels_per_line = std::stoi(argv[1]);
  276.   const int bytes_per_line = pixels_per_line / VLEN;
  277.   pixels_per_line = bytes_per_line * VLEN;
  278.   const std::vector<CrCr2Chunk> column_invariants =
  279.     make_column_invariant(bytes_per_line);
  280.   const std::vector<unsigned char> bitmap = make_bitmap(column_invariants);
  281.   print_pbm(bitmap, pixels_per_line, std::cout);
  282. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement