W3Schools



什么是计算实体对数的最有效方法?是否有实现它的库或内置函数?

solidity
6个回答
5

虽然目前还没有实施(我也看不到一个DAPP斌 either), you could implement your own using a 泰勒系列, as suggested by Vitalik in 这个 old Reddit thread.

对于线程中的示例,它实际上归结为如下所示:

 x = msg.data[0]
 LOG = 0
 while x >= 1500000:
     LOG = LOG + 405465
     x = x * 2 / 3
 x = x - 1000000
 y = x
 i = 1
 while i < 10:
      LOG = LOG + (y / i)
      i = i + 1
      y = y * x / 1000000
      LOG = LOG - (y / i)
      i = i + 1
      y = y * x / 1000000
return(LOG)

请记住步骤数和相关的天然气成本......


0

我对2log感兴趣: 所以第一个确实做了与上面几乎相同的事情。 但是另一个在[0,256]中的对数值中进行二分搜索。 后者的燃气成本非常稳定。第一个的燃气成本似乎与产量非常线性。 最好的方法是进行二次搜索,达到一定的精度,然后用简单的搜索完成。

    function findLogSimple(uint b) returns (uint){
        for(uint i=0;2**i<=b;i++){}
        return i-1;
    }
    function findLogBinarySearch(uint b) returns (uint){
        uint up = 256;
        uint down = 0;
        uint attempt = (up+down)/2;
        while (up>down+1){
            if(b>=(2**attempt)){
                down=attempt;
            }else{
                up=attempt;
            }
            attempt=(up+down)/2;
        }
        return attempt;
    }

甚至更好的是两者的混合:

function findLogMix(uint b) returns (uint){
    //if(b==0){return 0;}
    uint up = 256;
    uint down = 0;
    uint attempt = (up+down)/2;
    while (up>down+4){
        if(b>=(2**attempt)){
            down=attempt;
        }else{
            up=attempt;
        }
        attempt=(up+down)/2;
    }
uint temp = 2**down;
while(temp<=b){
    down++;
    temp=temp*2;
}
return down;
}

7

这是一种非常有效(<700气体)的方法来计算log_2的上限:

function log2(uint x) returns (uint y){
   assembly {
        let arg := x
        x := sub(x,1)
        x := or(x, div(x, 0x02))
        x := or(x, div(x, 0x04))
        x := or(x, div(x, 0x10))
        x := or(x, div(x, 0x100))
        x := or(x, div(x, 0x10000))
        x := or(x, div(x, 0x100000000))
        x := or(x, div(x, 0x10000000000000000))
        x := or(x, div(x, 0x100000000000000000000000000000000))
        x := add(x, 1)
        let m := mload(0x40)
        mstore(m,           0xf8f9cbfae6cc78fbefe7cdc3a1793dfcf4f0e8bbd8cec470b6a28a7a5a3e1efd)
        mstore(add(m,0x20), 0xf5ecf1b3e9debc68e1d9cfabc5997135bfb7a7a3938b7b606b5b4b3f2f1f0ffe)
        mstore(add(m,0x40), 0xf6e4ed9ff2d6b458eadcdf97bd91692de2d4da8fd2d0ac50c6ae9a8272523616)
        mstore(add(m,0x60), 0xc8c0b887b0a8a4489c948c7f847c6125746c645c544c444038302820181008ff)
        mstore(add(m,0x80), 0xf7cae577eec2a03cf3bad76fb589591debb2dd67e0aa9834bea6925f6a4a2e0e)
        mstore(add(m,0xa0), 0xe39ed557db96902cd38ed14fad815115c786af479b7e83247363534337271707)
        mstore(add(m,0xc0), 0xc976c13bb96e881cb166a933a55e490d9d56952b8d4e801485467d2362422606)
        mstore(add(m,0xe0), 0x753a6d1b65325d0c552a4d1345224105391a310b29122104190a110309020100)
        mstore(0x40, add(m, 0x100))
        let magic := 0x818283848586878898a8b8c8d8e8f929395969799a9b9d9e9faaeb6bedeeff
        let shift := 0x100000000000000000000000000000000000000000000000000000000000000
        let a := div(mul(x, magic), shift)
        y := div(mload(add(m,sub(255,a))), shift)
        y := add(y, mul(256, gt(arg, 0x8000000000000000000000000000000000000000000000000000000000000000)))
    }  
}

4

这是128.128定点数的高精度ln(x)实现:

/**
 * 2^127.
 */
uint128 private constant TWO127 = 0x80000000000000000000000000000000;

/**
 * 2^128 - 1.
 */
uint128 private constant TWO128_1 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

/**
 * ln(2) * 2^128.
 */
uint128 private constant LN2 = 0xb17217f7d1cf79abc9e3b39803f2f6af;

/**
 * Return index of most significant non-zero bit in given non-zero 256-bit
 * unsigned integer value.
 *
 * @param x value to get index of most significant non-zero bit in
 * @return index of most significant non-zero bit in given number
 */
function mostSignificantBit (uint256 x) pure internal returns (uint8) {
  require (x > 0);

  uint8 l = 0;
  uint8 h = 255;

  while (h > l) {
    uint8 m = uint8 ((uint16 (l) + uint16 (h)) >> 1);
    uint256 t = x >> m;
    if (t == 0) h = m - 1;
    else if (t > 1) l = m + 1;
    else return m;
  }

  return h;
}

/**
 * Calculate log_2 (x / 2^128) * 2^128.
 *
 * @param x parameter value
 * @return log_2 (x / 2^128) * 2^128
 */
function log_2 (uint256 x) pure internal returns (int256) {
  require (x > 0);

  uint8 msb = mostSignificantBit (x);

  if (msb > 128) x >>= msb - 128;
  else if (msb < 128) x <<= 128 - msb;

  x &= TWO128_1;

  int256 result = (int256 (msb) - 128) << 128; // Integer part of log_2

  int256 bit = TWO127;
  for (uint8 i = 0; i < 128 && x > 0; i++) {
    x = (x << 1) + ((x * x + TWO127) >> 128);
    if (x > TWO128_1) {
      result |= bit;
      x = (x >> 1) - TWO127;
    }
    bit >>= 1;
  }

  return result;
}

/**
 * Calculate ln (x / 2^128) * 2^128.
 *
 * @param x parameter value
 * @return ln (x / 2^128) * 2^128
 */
function ln (uint256 x) pure internal returns (int256) {
  require (x > 0);

  int256 l2 = log_2 (x);
  if (l2 == 0) return 0;
  else {
    uint256 al2 = uint256 (l2 > 0 ? l2 : -l2);
    uint8 msb = mostSignificantBit (al2);
    if (msb > 127) al2 >>= msb - 127;
    al2 = (al2 * LN2 + TWO127) >> 128;
    if (msb > 127) al2 <<= msb - 127;

    return int256 (l2 >= 0 ? al2 : -al2);
  }
}

0

一种快速且无分支的实现,用于计算log2的上限。翻译自HTTPS://stack overflow.com/questions/3272424/compute-fast-log-巴塞-2-ceiling

pragma solidity ^0.4.23;


library MathUtil {
  function ceilLog2(uint _x) pure internal returns(uint) {
    require(_x > 0);

    uint x = _x;
    uint y = (((x & (x - 1)) == 0) ? 0 : 1);
    uint j = 128;
    uint k = 0;

    k = (((x & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0xFFFFFFFFFFFFFFFF0000000000000000) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0xFFFFFFFF00000000) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0x00000000FFFF0000) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0x000000000000FF00) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0x00000000000000F0) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0x000000000000000C) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    k = (((x & 0x0000000000000002) == 0) ? 0 : j);
    y += k;
    x >>= k;
    j >>= 1;

    return y;
  }
}