github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/math/internal/math_template.h (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  #pragma once
    21  #include "common/common.h"
    22  #include "common/math/softfloat.hpp"
    23  #include <functional>
    24  
    25  #define MATH_MIN 1e-5
    26  
    27  namespace neb {
    28  namespace math {
    29  
    30  namespace internal {
    31  
    32  template <typename T> T __get_pi() {
    33    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
    34    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
    35    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
    36    T four = softfloat_cast<uint32_t, typename T::value_type>(4);
    37  
    38    T ret = zero;
    39    T i = one;
    40    bool odd = true;
    41  
    42    while (true) {
    43      T tmp;
    44      auto x = four / i;
    45      if (odd) {
    46        tmp = ret + x;
    47      } else {
    48        tmp = ret - x;
    49      }
    50      if (tmp - ret < MATH_MIN && ret - tmp < MATH_MIN) {
    51        break;
    52      }
    53      ret = tmp;
    54      i += two;
    55      odd = !odd;
    56    }
    57    return ret;
    58  }
    59  
    60  template <typename T> T __fast_get_pi() {
    61    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
    62    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
    63    T four = softfloat_cast<uint32_t, typename T::value_type>(4);
    64  
    65    T ret = one + two;
    66    T i = two;
    67    bool odd = true;
    68    while (true) {
    69      T tmp;
    70      auto tail = four / (i * (i + one) * (i + two));
    71      if (odd) {
    72        tmp = ret + tail;
    73      } else {
    74        tmp = ret - tail;
    75      }
    76      if (tmp - ret < MATH_MIN && ret - tmp < MATH_MIN) {
    77        break;
    78      }
    79      ret = tmp;
    80      i += two;
    81      odd = !odd;
    82    }
    83    return ret;
    84  }
    85  
    86  template <typename T> T __get_e() {
    87    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
    88    T ret = one;
    89  
    90    T i = one;
    91    T prev = one;
    92  
    93    while (true) {
    94      T tmp;
    95  
    96      tmp = ret + one / prev;
    97      if (tmp - ret < MATH_MIN && ret - tmp < MATH_MIN) {
    98        break;
    99      }
   100      ret = tmp;
   101      i += one;
   102      prev = prev * i;
   103    }
   104  
   105    return ret;
   106  }
   107  
   108  template <typename T> T __get_ln2() {
   109    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
   110    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   111  
   112    T ret = zero;
   113    T i = one;
   114    bool odd = true;
   115  
   116    while (true) {
   117      T tmp;
   118      if (odd) {
   119        tmp = ret + one / i;
   120      } else {
   121        tmp = ret - one / i;
   122      }
   123  
   124      if (tmp - ret < MATH_MIN && ret - tmp < MATH_MIN) {
   125        break;
   126      }
   127      ret = tmp;
   128      i += one;
   129      odd = !odd;
   130    }
   131    return ret;
   132  }
   133  
   134  template <typename T> T __fast_get_ln2() {
   135    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
   136    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   137    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
   138  
   139    auto func = [&](T x) {
   140      T ret = zero;
   141      T s = two * x;
   142      T i = one;
   143      T x2 = x * x;
   144  
   145      while (true) {
   146        T tmp;
   147  
   148        tmp = ret + s / i;
   149        if (tmp - ret < MATH_MIN && ret - tmp < MATH_MIN) {
   150          break;
   151        }
   152  
   153        ret = tmp;
   154        i += two;
   155        s = s * x2;
   156      }
   157      return ret;
   158    };
   159  
   160    return func((two - one) / (two + one));
   161  }
   162  
   163  } // namespace internal
   164  
   165  template <typename T> class constants {
   166  public:
   167    static T pi() {
   168      std::call_once(s_init_once, std::bind(constants<T>::init));
   169      return s_pi;
   170    }
   171    static T ln2() {
   172      std::call_once(s_init_once, std::bind(constants<T>::init));
   173      return s_ln2;
   174    }
   175    static T e() {
   176      std::call_once(s_init_once, std::bind(constants<T>::init));
   177      return s_e;
   178    }
   179  
   180  protected:
   181    static void init() {
   182      s_pi = internal::__fast_get_pi<T>();
   183      s_ln2 = internal::__fast_get_ln2<T>();
   184      s_e = internal::__get_e<T>();
   185    }
   186    static T s_pi;
   187    static T s_ln2;
   188    static T s_e;
   189    static std::once_flag s_init_once;
   190  };
   191  
   192  template <typename T> T constants<T>::s_pi;
   193  template <typename T> T constants<T>::s_ln2;
   194  template <typename T> T constants<T>::s_e;
   195  template <typename T> std::once_flag constants<T>::s_init_once;
   196  } // namespace math
   197  } // namespace neb