Advertisement
Guest User

Untitled

a guest
Jun 11th, 2018
418
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.62 KB | None | 0 0
  1. /*
  2.   det_noise64.hh
  3.  
  4.   Copyright (c) 2018 Ryan P. Nicholl, "Exaeta", <exaeta@protonmail.com>
  5.  
  6.     https://github.com/Exaeta/det_noise64
  7.    
  8.     The following code implements a deterministic N-dimensional smooth
  9.     64-bit integer noise function. This function hasn't been tested extensively.
  10.    
  11.     Also the "det_point_noise64" function should probably be improved or
  12.     replaced with something faster.
  13.    
  14.     It doesn't rely on any third party libraries except boost::multiprecision,
  15.     which can be substituited for any library that provides a 128-bit
  16.     unsigned integer.
  17.    
  18.     Any donations would be appreciated. :)
  19.  
  20.   Permission is hereby granted, free of charge, to any person obtaining a copy
  21.   of this software and associated documentation files (the "Software"), to deal
  22.   in the Software without restriction, including without limitation the rights
  23.   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  24.   copies of the Software, and to permit persons to whom the Software is
  25.   furnished to do so, subject to the following conditions:
  26.  
  27.   The above copyright notice and this permission notice shall be included in all
  28.   copies or substantial portions of the Software.
  29.  
  30.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  31.   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  32.   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  33.   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  34.   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  35.   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  36.   SOFTWARE.
  37.  
  38. */
  39.  
  40. #ifndef RPNX_G_NOISE_HH
  41. #define RPNX_G_NOISE_HH
  42.  
  43.  
  44.  
  45. #include <array>
  46. #include <cinttypes>
  47. #include <boost/multiprecision/cpp_int.hpp>
  48.  
  49. namespace ioncraft
  50. {
  51.  
  52.   using uint64_t = std::uint64_t;
  53.   using uint128_t = boost::multiprecision::uint128_t;
  54.  
  55.   /*
  56.     This function is probably not cryptographically secure.
  57.     For insecure functions only.
  58.   */
  59.   template <std::size_t N>
  60.   std::uint64_t det_point_noise64(std::array<std::uint64_t, N> inputs, std::size_t c = 9)
  61.   {
  62.     std::uint64_t output = 0xFAFAFAFAFAFAFAFAull;
  63.     for (std::size_t k = 0; k < c; k++)
  64.     {
  65.       for (std::size_t i = 0; i < N; i++)
  66.       {
  67.         output = (output >> 17) | (output  << (64 - 17));
  68.         output += inputs[i];
  69.         output = (output >> ((k+inputs[i]) &0x0F)) | (output  << (64 - ((k+inputs[i]) &0x0F)));
  70.         output ^= 7;
  71.         output ^= ((output & (0xbeull << 31)) >> 21);
  72.         output += 1;
  73.        
  74.       }
  75.     }
  76.     output = (output >> 17) | (output  << (64 - 17));
  77.    
  78.     return output;
  79.   }
  80.  
  81.   template <std::size_t N>
  82.   bool det_point_noise1(std::array<std::uint64_t, N> inputs)
  83.   {
  84.    
  85.     std::uint64_t output = 0xFAFAFAFAFAFAFAFAull;
  86.     for (std::size_t k = 0; k < 4; k++)
  87.     {
  88.       for (std::size_t i = 0; i < N; i++)
  89.       {
  90.         output = (output >> 17) | (output  << (64 - 17));
  91.         output += inputs[i];      
  92.         output ^= 7;
  93.         output ^= ((output & (0xbeull << 31)) >> 21);
  94.         output += k;
  95.       }
  96.     }
  97.     output = (output >> 17) | (output  << (64 - 17));
  98.    
  99.     return 1 & ( (output >> 7) ^ (output >> 3) ^ (output >> 5) ^
  100.     (output >> 2) ^ (output >> 11) ^ (output >> 17) ^ (output >> 13) );
  101.   }
  102.  
  103.   template <std::size_t C = 32, std::size_t N = 1>
  104.   std::uint64_t det_field_noise64(std::array<std::uint64_t, N> inputs, std::size_t c = 9)
  105.   {
  106.    
  107.     std::array<std::uint64_t, (1 << N)> field_corners;
  108.     // 2 ^ N dimensions
  109.     // gathers the values in each corner.
  110.    
  111.     std::uint8_t r = 0; // used later;
  112.    
  113.    
  114.     for (std::size_t i = 0; i < field_corners.size(); i++)
  115.     {
  116.       std::array<std::uint64_t, N> field_inputs = inputs;
  117.       // Each dimension has a set of inputs
  118.      
  119.      
  120.       for (std::size_t k = 0; k < field_inputs.size(); k++)
  121.       {
  122.         field_inputs[k] >>= C;
  123.         // only the first N-C bits are significant to the field
  124.       }
  125.      
  126.      
  127.       for (std::size_t k = 0; k < N; k++)
  128.       {
  129.         if (i & (1 << k)) field_inputs[k]++;
  130.         // We must adjust the field inputs depending on which "corners"
  131.         // we are in.
  132.       }
  133.      
  134.       field_corners[i] = det_point_noise64(field_inputs, c);
  135.       // calculate the corner values
  136.      
  137.       r += field_corners[i] & 0xFF;
  138.       // extra randomness to replace randomness lost later
  139.     }  
  140.    
  141.     std::array<std::uint64_t, N> sigvals;
  142.     for (std::size_t i = 0; i < N; i++)
  143.     {
  144.       sigvals[i] = inputs[i] & ((std::uint64_t(1) << C) - 1);
  145.     }
  146.     // We need to know the dimensional significance of dimension in
  147.     // order to interpolate the values correctly.
  148.    
  149.    
  150.     // The following code interpolates the N-dimensional structure
  151.     // in N log N time by collapsing each dimension one at a time
  152.     // until the structure is 0-dimensional and has only 1 value
  153.    
  154.     std::size_t q = N;
  155.     // q here is to avoid taking logs later
  156.    
  157.     for (std::size_t m = field_corners.size() >> 1
  158.      /* The initial value of m here is half the number of corners,
  159.         because the collapsing inner
  160.         loop assumes that i|m is valid.
  161.         The number of corners will always be a power of two, so this works.
  162.      */;
  163.      m != 0;
  164.      m >>= 1
  165.      /*
  166.       When a round finishes, we can collapse the next dimension, which
  167.       is represented by a power of two.
  168.      */)
  169.     {
  170.       q--;
  171.       r += q;
  172.       // reduce by one before the loop (so sigvals[q] is valid because
  173.       // q < N
  174.      
  175.       for (std::size_t i = 0; i < m; i++)
  176.       {
  177.         /* There are two corners involved in each inner loop of the
  178.            collapse, e.g. (0, x, y, z) and (1, x, y, z) where x, y, and
  179.            z are 0 or 1 and i = 0b[wxyz]
  180.            so (w << 3) | (x << 2) | (y << 1) | (z << 0) etc. but for
  181.            N-dimensions.
  182.            */
  183.            
  184.         std::uint64_t a = field_corners[i];
  185.         // a is the first corner
  186.         std::uint64_t b = field_corners[i | m];
  187.         // and b is the second
  188.        
  189.         std::uint64_t v = sigvals[q];
  190.         // a is the "low" value is a low value for v should indicate a high contribution for a
  191.         // b is the high value so a high value of v should be a high contribution from b
  192.         uint128_t o = uint128_t(a) * ((uint128_t(1) << C) - v) + v * uint128_t(b);
  193.        
  194.         r += static_cast<std::uint8_t>(v & 0xFF);
  195.         // update: use boost's 128-bit number to get around precision loss.
  196.         // It's unfortunate that precision is lost here... maybe there is a better way to do this
  197.        
  198.         field_corners[i] = static_cast<std::uint64_t> ((o >> (C-2)) & ((uint128_t(1) << 64)-1));
  199.         field_corners[i] ^= r ^ (r >> 3) ^ (r >> 5) ^ (r >> 7);
  200.       }
  201.     }
  202.    
  203.     std::uint64_t out = field_corners[0];
  204.     if (out & (std::uint64_t(1) << 63))
  205.     {
  206.       out = ((~out ^ 1) << 1) | 1;
  207.     }
  208.     else out = out << 1;
  209.     /* The transformation above is supposed to redistribute the "out"
  210.     value such that values near 0 are "similar" so there aren't abrupt
  211.     transitions due to modular arithmetic wrapping from 1 to 0.
  212.     */
  213.    
  214.     out ^= 1 & (r ^ (r >> 3) ^ (r >> 5));
  215.     /*
  216.       An unfortunate result of the above transformation is that although
  217.       it's uniform over the 64-bit space, the last bit only changes when
  218.       the sign flips and thus effectively only 63 bits are adequately
  219.       random. To fix that some random bits are used.
  220.     */
  221.    
  222.    
  223.     return out;
  224.    
  225.    
  226.   }
  227. }
  228.  
  229. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement