github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/math/internal/math_extension.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/math/internal/math_template.h"
    22  
    23  namespace neb {
    24  namespace math {
    25  
    26  template <typename T> T min(const T &x, const T &y) { return x < y ? x : y; }
    27  template <typename T> T max(const T &x, const T &y) { return x > y ? x : y; }
    28  
    29  template <typename T> T abs(const T &x, const T &y) {
    30    T delta = x - y;
    31    return delta > 0 ? delta : 0 - delta;
    32  }
    33  
    34  template <typename T> std::string to_string(const T &val) {
    35    std::stringstream ss;
    36    ss << val;
    37    return ss.str();
    38  }
    39  template <typename T> T from_string(const std::string &str) {
    40    std::stringstream ss(str);
    41    T val;
    42    ss >> val;
    43    return val;
    44  }
    45  
    46  template <typename T> bool exit_cond(const T &x, const T &y) {
    47    if (x - y < MATH_MIN && y - x < MATH_MIN) {
    48      return true;
    49    }
    50    if (to_string(x) == std::string("inf") &&
    51        to_string(y) == std::string("inf")) {
    52      return true;
    53    }
    54    if (to_string(x) == std::string("-nan") &&
    55        to_string(y) == std::string("-nan")) {
    56      return true;
    57    }
    58    return false;
    59  }
    60  
    61  template <typename T> T exp(const T &x) {
    62    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
    63    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
    64  
    65    if (x < zero) {
    66      return one / exp(-x);
    67    }
    68  
    69    T ret = one;
    70    T i = one;
    71    T tail = x;
    72  
    73    while (true) {
    74      T tmp;
    75  
    76      tmp = ret + tail;
    77      if (exit_cond(tmp, ret)) {
    78        break;
    79      }
    80  
    81      ret = tmp;
    82      i += one;
    83      tail *= x / i;
    84    }
    85  
    86    return ret;
    87  }
    88  
    89  template <typename T> T arctan(const T &x) {
    90    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
    91    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
    92    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
    93    T half_pi = constants<T>::pi() / two;
    94  
    95    if (x > one) {
    96      return half_pi - arctan(one / x);
    97    } else if (x < zero - one) {
    98      return zero - half_pi - arctan(one / x);
    99    }
   100  
   101    T x2 = x * x;
   102    T ret = zero;
   103    T i = one;
   104    T s = x;
   105    bool odd = false;
   106  
   107    while (true) {
   108      T tmp;
   109      if (odd) {
   110        tmp = ret - s / i;
   111      } else {
   112        tmp = ret + s / i;
   113      }
   114      if (exit_cond(tmp, ret)) {
   115        break;
   116      }
   117      ret = tmp;
   118      odd = !odd;
   119      i += two;
   120      s = s * x2;
   121    }
   122    return ret;
   123  }
   124  
   125  template <typename T> T sin(const T &x) {
   126    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
   127    if (x < zero) {
   128      return zero - sin(zero - x);
   129    }
   130  
   131    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   132    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
   133    T double_pi = two * constants<T>::pi();
   134    if (x > double_pi) {
   135      T tmp = (x / double_pi).integer_val();
   136      return sin(x - tmp * double_pi);
   137    }
   138  
   139    T x2 = x * x;
   140    T ret = zero;
   141    T i = one;
   142    T tail = x;
   143    bool odd = false;
   144  
   145    while (true) {
   146      T tmp;
   147      if (odd) {
   148        tmp = ret - tail;
   149      } else {
   150        tmp = ret + tail;
   151      }
   152      if (exit_cond(tmp, ret)) {
   153        break;
   154      }
   155      ret = tmp;
   156      odd = !odd;
   157      tail *= (x2 / ((i + one) * (i + two)));
   158      i += two;
   159    }
   160    return ret;
   161  }
   162  
   163  template <typename T> T ln(const T &x) {
   164    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
   165    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   166    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
   167  
   168    auto func = [&](T x) {
   169      T ret = zero;
   170      bool odd = true;
   171  
   172      T s = x;
   173      T i = one;
   174  
   175      while (true) {
   176        T tmp;
   177  
   178        if (odd) {
   179          tmp = ret + s / i;
   180        } else {
   181          tmp = ret - s / i;
   182        }
   183        if (exit_cond(tmp, ret)) {
   184          break;
   185        }
   186  
   187        ret = tmp;
   188        odd = !odd;
   189        i += one;
   190        s = s * x;
   191      }
   192      return ret;
   193    };
   194  
   195    if (x > two) {
   196      return zero - func(one / x - one);
   197    }
   198    return func(x - one);
   199  }
   200  
   201  template <typename T> T fast_ln(const T &x) {
   202    T zero = softfloat_cast<uint32_t, typename T::value_type>(0);
   203    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   204    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
   205  
   206    auto func = [&](T x) {
   207      T ret = zero;
   208      T s = two * x;
   209      T i = one;
   210      T x2 = x * x;
   211  
   212      while (true) {
   213        T tmp;
   214  
   215        tmp = ret + s / i;
   216        if (exit_cond(tmp, ret)) {
   217          break;
   218        }
   219  
   220        ret = tmp;
   221        i += two;
   222        s = s * x2;
   223      }
   224      return ret;
   225    };
   226  
   227    return func((x - one) / (x + one));
   228  }
   229  
   230  namespace internal {
   231  union float16_detail_t {
   232    float16_t v;
   233    struct {
   234      uint64_t ey : 10;
   235      uint16_t exponent : 5;
   236      uint8_t sign : 1;
   237    } detail;
   238  };
   239  union float32_detail_t {
   240    float32_t v;
   241    struct {
   242      uint64_t fraction : 23;
   243      uint16_t exponent : 8;
   244      uint8_t sign : 1;
   245    } detail;
   246  };
   247  union float64_detail_t {
   248    float64_t v;
   249    struct {
   250      uint64_t fraction : 52;
   251      uint16_t exponent : 11;
   252      uint8_t sign : 1;
   253    } detail;
   254  };
   255  union float128_detail_t {
   256    float128_t v;
   257    struct {
   258      uint64_t fraction0 : 48;
   259      uint64_t fraction1 : 64;
   260      uint16_t exponent : 15;
   261      uint8_t sign : 1;
   262    } detail;
   263  };
   264  
   265  template <typename T> struct float_detail {};
   266  template <> struct float_detail<float16> {
   267    typedef float16_detail_t value_type;
   268    constexpr static uint16_t bias = 15;
   269  };
   270  template <> struct float_detail<float32> {
   271    typedef float32_detail_t value_type;
   272    constexpr static uint16_t bias = 127;
   273  };
   274  template <> struct float_detail<float64> {
   275    typedef float64_detail_t value_type;
   276    constexpr static uint16_t bias = 1023;
   277  };
   278  template <> struct float_detail<float128> {
   279    typedef float128_detail_t value_type;
   280    constexpr static uint16_t bias = 16383;
   281  };
   282  
   283  template <typename T> struct float_math_helper {
   284    typedef typename T::value_type value_type;
   285    typedef typename float_detail<T>::value_type detail_type;
   286  
   287    static T get_exponent(const T &x) {
   288      detail_type dt;
   289      dt.v = (T)x;
   290      detail_type ret;
   291      ret.detail.sign = dt.detail.sign;
   292      ret.detail.exponent = dt.detail.exponent;
   293      return T(ret.v);
   294    }
   295    static T get_one_plus_fraction(const T &x) {
   296      detail_type dt;
   297      dt.v = (T)x;
   298      detail_type ret;
   299      ret.v = dt.v;
   300      ret.detail.exponent = detail_type::bias;
   301      return T(ret.v);
   302    }
   303  };
   304  } // namespace internal
   305  
   306  template <typename T> T log2(const T &x) { return ln(x) / constants<T>::ln2(); }
   307  
   308  //! return x^y
   309  template <typename T> T pow(const T &x, const T &y) {
   310    return exp(y * fast_ln(x));
   311  }
   312  
   313  template <typename T> T pow(const T &x, const int64_t &y) {
   314    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   315    if (y == 0) {
   316      return one;
   317    }
   318  
   319    T ret = one;
   320    T tmp_x = x;
   321    uint64_t tmp_y = y > 0 ? y : -y;
   322  
   323    while (tmp_y) {
   324      if ((tmp_y & 0x1) == 1) {
   325        ret *= tmp_x;
   326      }
   327      tmp_x *= tmp_x;
   328      tmp_y >>= 1;
   329    }
   330    return y > 0 ? ret : one / ret;
   331  }
   332  
   333  // only applicable for float16 and float32
   334  template <typename T> T sqrt(const T &x) {
   335    T one = softfloat_cast<uint32_t, typename T::value_type>(1);
   336    T two = softfloat_cast<uint32_t, typename T::value_type>(2);
   337    T one_and_half = one + one / two;
   338    T half_x = x / two;
   339  
   340    typename T::value_type tmp_x = typename T::value_type(x);
   341    uint32_t i = *reinterpret_cast<uint32_t *>(&tmp_x);
   342    i = 0x5f3759df - (i >> 1);
   343    tmp_x = *reinterpret_cast<typename T::value_type *>(&i);
   344    T sqrt_x(tmp_x);
   345    sqrt_x = sqrt_x * (one_and_half - half_x * sqrt_x * sqrt_x);
   346    sqrt_x = sqrt_x * (one_and_half - half_x * sqrt_x * sqrt_x);
   347    sqrt_x = sqrt_x * (one_and_half - half_x * sqrt_x * sqrt_x);
   348    return one / sqrt_x;
   349  }
   350  } // namespace math
   351  
   352  } // namespace neb