Add ability to extend the closing of withdraw contract

// The contract that allows DTH to withdraw funds that the white hat
// group has managed to retrieve.
//
// There are 2 ways to use the contract:
// 1. withdraw()
// 2. proxyWithdraw()
//
// For a description of each method, take a look at the docstrings.
//
// License: BSD3

contract DAOBalanceSnapShot {
    function balanceOf(address _dth) constant returns(uint);
    function totalSupply() constant returns(uint );
}

contract AuthorizedAddresses {
    function getRepresentedDTH(address _authorizedAddress) constant returns(address _dth);
}

contract Owned {
    /// Prevents methods from perfoming any value transfer
    modifier noEther() {if (msg.value > 0) throw; _}
    /// Allows only the owner to call a function
    modifier onlyOwner { if (msg.sender != owner) throw; _ }

    address owner;

    function Owned() { owner = msg.sender;}

    function changeOwner(address _newOwner) onlyOwner {
        owner = _newOwner;
    }

    function getOwner() noEther constant returns (address) {
        return owner;
    }
}

contract WhitehatWithdraw is Owned {
    uint constant WithdrawType_DIRECT = 1;
    uint constant WithdrawType_PROXY = 2;
    uint constant WithdrawType_PROXY_AUTHORIZED = 3;

    DAOBalanceSnapShot daoBalance;
    AuthorizedAddresses authorizedAddresses;
    mapping (address => uint) paidOut;
    mapping (address => bool) certifiedDepositors;
    mapping (bytes32 => bool) usedSignatures;
    mapping (address => bool) blacklist;
    uint totalFunds;
    uint deployTime;
    uint closingTime;
    address whg_donation;
    address escape;
    address remainingBeneficary;

    event Withdraw(address indexed dth, address indexed beneficiary, uint256  amount, uint256 percentageWHG, uint256 withdrawType);
    event CertifiedDepositorsChanged(address indexed _depositor, bool _allowed);
    event BlacklistChanged(address indexed _dth, bool _blocked);
    event Deposit(uint amount);
    event EscapeCalled(uint amount);
    event RemainingClaimed(uint amount);

    function WhitehatWithdraw(address _whg_donation, address _daoBalanceSnapshotAddress, address _authorizedAddressesAddress, address _escapeAddress, address _remainingBeneficiary) {
        whg_donation = _whg_donation;
        daoBalance = DAOBalanceSnapShot(_daoBalanceSnapshotAddress);
        authorizedAddresses = AuthorizedAddresses(_authorizedAddressesAddress);
        escape = _escapeAddress;
        remainingBeneficary = _remainingBeneficiary;

        totalFunds = msg.value;
        deployTime = now;
        closingTime = 24 weeks;

        // both the owner and the whitehat multisig can perform deposits to this contract
        certifiedDepositors[0x1ac729d2db43103faf213cb9371d6b42ea7a830f] = true;
        certifiedDepositors[msg.sender] = true;
    }

    /// Calculates the remaining funds available for a DTH to withdraw
    ///
    /// @param _dth          The address of the DAO Token Holder for whom
    ///                      to get the funds remaining for withdrawal
    /// @return              The amount of funds remaining for withdrawal
    function calculateWithdraw(address _dth) constant noEther returns(uint) {
        uint tokens = daoBalance.balanceOf(_dth);

        uint acumulatedReward = tokens * totalFunds / daoBalance.totalSupply();
        if (acumulatedReward < paidOut[_dth]) {
            return 0;
        }

        return acumulatedReward - paidOut[_dth];
    }

    /// The core of the withdraw functionality. It is called by all other withdraw functions
    ///
    /// @param _dth           The address of the DAO token holder for whom the
    ///                       withdrawal is going to happen
    /// @param _beneficiary   The address that will receive the _percentage of
    ///                       the funds corresponding to the _dth.
    /// @param _percentageWHG The percentage of the funds that will be donated to the
    ///                       White Hat Group. It should be a number ranging from 0
    ///                       to 100. Anything not claimed by the DTH will be going
    ///                       as a donation to the Whitehat Group.
    /// @param _withdrawType  method used to withdraw (1) Direct (2) Proxy (3) bot (4) owner
    function commonWithdraw(address _dth, address _beneficiary, uint _percentageWHG, uint _withdrawType) internal {

        if (blacklist[_dth]) {
            throw;
        }

        if (_percentageWHG > 100) {
            throw;
        }

        uint toPay = calculateWithdraw(_dth);
        if (toPay == 0) {
            return;
        }

        if (toPay > this.balance) {
            toPay = this.balance;
        }

        uint portionWhg = toPay * _percentageWHG / 100;
        uint portionDth = toPay - portionWhg;
        paidOut[_dth] += toPay;

        // re-entrancy is not possible due to the use of send() which limits
        // the forwarded gas thanks to the gas stipend
        if ( !whg_donation.send(portionWhg) ||  !_beneficiary.send(portionDth) ) {
            throw;
        }

        Withdraw(_dth, _beneficiary,  toPay, _percentageWHG, _withdrawType);
    }

    /// The simple withdraw function, where the message sender is considered as
    /// the DAO token holder whose ratio needs to be retrieved.
    function withdraw(address _beneficiary, uint _percentageWHG ) noEther {
        commonWithdraw(msg.sender, _beneficiary, _percentageWHG, WithdrawType_DIRECT);
    }

    /// The proxy withdraw function. Anyone can call this for someone else as long
    /// as he includes signed data retrieved by using web3.eth.sign(address, hash).
    /// The DAO token holder whose ratio needs to be retrieved is determined by
    /// performing ecrecover on the signed data.
    ///
    /// This function will also allow people to use the ETH chain to give an
    /// approval for withdrawal in the ETC chain without having to sync the
    /// ETC chain. The only requirement is that the account that gives the
    /// approval needs to be an end-user account. Multisig wallets can't do that.
    function proxyWithdraw(address _beneficiary, uint _percentageWHG, uint8 _v, bytes32 _r, bytes32 _s) noEther {
        if (usedSignatures[_r]) {
            throw;
        }
        bytes32 _hash = sha3("Withdraw DAOETC to ", _beneficiary, _percentageWHG);
        address _dth = ecrecover(_hash, _v, _r, _s);
        usedSignatures[_r] = true;
        commonWithdraw(_dth, _beneficiary, _percentageWHG, WithdrawType_PROXY);
        address representedDth = authorizedAddresses.getRepresentedDTH(_dth);
        if (representedDth != 0x0) {
            commonWithdraw(representedDth, _beneficiary, _percentageWHG, WithdrawType_PROXY_AUTHORIZED);
        }
    }

    /// This is the only way to send money to the contract, adding to the total
    /// amount of ETH to be refunded.
    ///
    /// Only people who are considered certified depositors like the whitehat ETC multisig
    /// or addresses owned by exchanges should be able to deposit more ETC for withdrals.
    /// If you need to become a certified depositor please contact Bity SA.
    function deposit() returns (bool) {
        if (!certifiedDepositors[msg.sender]) {
            throw;
        }
        totalFunds += msg.value;
        Deposit(msg.value);
        return true;
    }

    /// Last Resort call, to allow for a reaction if something bad happens to
    /// the contract or if some security issue is uncovered.
    function escapeHatch() noEther onlyOwner returns (bool) {
        uint total = this.balance;
        if (!escape.send(total)) {
            throw;
        }
        EscapeCalled(total);
    }

    /// Allows the claiming of the remaining funds after a given amount of time
    /// Amount is set to 6 months for now but may still change in the future.
    function claimRemaining() noEther returns (bool) {
        if (now < deployTime + closingTime) {
            throw;
        }
        uint total = this.balance;
        if (!remainingBeneficary.send(total)) {
            throw;
        }
        RemainingClaimed(total);
    }

    /// Allows the option to extend (but not shorten!) the closingTime of the
    /// contract to more than 6 months, perhaps even to infinity if that is
    /// deemed as the best choice for the DAO Token holders.
    function extendClosingTime(uint _additionalSeconds) noEther onlyOwner {
        closingTime += _additionalSeconds;
    }

    function () { //no donations
        throw;
    }

    function getPaidOut(address _account) noEther constant returns (uint) {
        return paidOut[_account];
    }

    function getMyBalance(address _account) noEther constant returns (uint) {
        return daoBalance.balanceOf(_account);
    }

    function getTotalFunds() noEther constant returns (uint) {
        return totalFunds;
    }

    function getWHGDonationAddress() noEther constant returns (address) {
        return whg_donation;
    }

    function isCertifiedDepositor(address _depositor) noEther constant returns (bool) {
        return certifiedDepositors[_depositor];
    }

    function changeCertifiedDepositors(address _depositor, bool _allowed) onlyOwner noEther external returns (bool _success) {
        certifiedDepositors[_depositor] = _allowed;
        CertifiedDepositorsChanged(_depositor, _allowed);
        return true;
    }

    function isBlacklisted(address _dth) noEther constant returns (bool) {
        return blacklist[_dth];
    }

    function changeBlacklist(address _dth, bool _blocked) onlyOwner noEther external returns (bool _success) {
        blacklist[_dth] = _blocked;
        BlacklistChanged(_dth, _blocked);
        return true;
    }
}

// The contract that allows DTH to withdraw funds that the white hat
// group has managed to retrieve.
//
// There are 2 ways to use the contract:
// 1. withdraw()
// 2. proxyWithdraw()
//
// For a description of each method, take a look at the docstrings.
//
// License: BSD3

contract DAOBalanceSnapShot {
    function balanceOf(address _dth) constant returns(uint);
    function totalSupply() constant returns(uint );
}

contract AuthorizedAddresses {
    function getRepresentedDTH(address _authorizedAddress) constant returns(address _dth);
}

contract Owned {
    /// Prevents methods from perfoming any value transfer
    modifier noEther() {if (msg.value > 0) throw; _}
    /// Allows only the owner to call a function
    modifier onlyOwner { if (msg.sender != owner) throw; _ }

    address owner;

    function Owned() { owner = msg.sender;}

    function changeOwner(address _newOwner) onlyOwner {
        owner = _newOwner;
    }

    function getOwner() noEther constant returns (address) {
        return owner;
    }
}

contract WhitehatWithdraw is Owned {
    uint constant WithdrawType_DIRECT = 1;
    uint constant WithdrawType_PROXY = 2;
    uint constant WithdrawType_PROXY_AUTHORIZED = 3;

    DAOBalanceSnapShot daoBalance;
    AuthorizedAddresses authorizedAddresses;
    mapping (address => uint) paidOut;
    mapping (address => bool) certifiedDepositors;
    mapping (bytes32 => bool) usedSignatures;
    mapping (address => bool) blacklist;
    uint totalFunds;
    uint deployTime;
    address whg_donation;
    address escape;
    address remainingBeneficary;

    event Withdraw(address indexed dth, address indexed beneficiary, uint256  amount, uint256 percentageWHG, uint256 withdrawType);
    event CertifiedDepositorsChanged(address indexed _depositor, bool _allowed);
    event BlacklistChanged(address indexed _dth, bool _blocked);
    event Deposit(uint amount);
    event EscapeCalled(uint amount);
    event RemainingClaimed(uint amount);

    function WhitehatWithdraw(address _whg_donation, address _daoBalanceSnapshotAddress, address _authorizedAddressesAddress, address _escapeAddress, address _remainingBeneficiary) {
        whg_donation = _whg_donation;
        daoBalance = DAOBalanceSnapShot(_daoBalanceSnapshotAddress);
        authorizedAddresses = AuthorizedAddresses(_authorizedAddressesAddress);
        escape = _escapeAddress;
        remainingBeneficary = _remainingBeneficiary;

        totalFunds = msg.value;
        deployTime = now;

        // both the owner and the whitehat multisig can perform deposits to this contract
        certifiedDepositors[0x1ac729d2db43103faf213cb9371d6b42ea7a830f] = true;
        certifiedDepositors[msg.sender] = true;
    }

    /// Calculates the remaining funds available for a DTH to withdraw
    ///
    /// @param _dth          The address of the DAO Token Holder for whom
    ///                      to get the funds remaining for withdrawal
    /// @return              The amount of funds remaining for withdrawal
    function calculateWithdraw(address _dth) constant noEther returns(uint) {
        uint tokens = daoBalance.balanceOf(_dth);

        uint acumulatedReward = tokens * totalFunds / daoBalance.totalSupply();
        if (acumulatedReward < paidOut[_dth]) {
            return 0;
        }

        return acumulatedReward - paidOut[_dth];
    }

    /// The core of the withdraw functionality. It is called by all other withdraw functions
    ///
    /// @param _dth           The address of the DAO token holder for whom the
    ///                       withdrawal is going to happen
    /// @param _beneficiary   The address that will receive the _percentage of
    ///                       the funds corresponding to the _dth.
    /// @param _percentageWHG The percentage of the funds that will be donated to the
    ///                       White Hat Group. It should be a number ranging from 0
    ///                       to 100. Anything not claimed by the DTH will be going
    ///                       as a donation to the Whitehat Group.
    /// @param _withdrawType  method used to withdraw (1) Direct (2) Proxy (3) bot (4) owner
    function commonWithdraw(address _dth, address _beneficiary, uint _percentageWHG, uint _withdrawType) internal {

        if (blacklist[_dth]) {
            throw;
        }

        if (_percentageWHG > 100) {
            throw;
        }

        uint toPay = calculateWithdraw(_dth);
        if (toPay == 0) {
            return;
        }

        if (toPay > this.balance) {
            toPay = this.balance;
        }

        uint portionWhg = toPay * _percentageWHG / 100;
        uint portionDth = toPay - portionWhg;
        paidOut[_dth] += toPay;

        // re-entrancy is not possible due to the use of send() which limits
        // the forwarded gas thanks to the gas stipend
        if ( !whg_donation.send(portionWhg) ||  !_beneficiary.send(portionDth) ) {
            throw;
        }

        Withdraw(_dth, _beneficiary,  toPay, _percentageWHG, _withdrawType);
    }

    /// The simple withdraw function, where the message sender is considered as
    /// the DAO token holder whose ratio needs to be retrieved.
    function withdraw(address _beneficiary, uint _percentageWHG ) noEther {
        commonWithdraw(msg.sender, _beneficiary, _percentageWHG, WithdrawType_DIRECT);
    }

    /// The proxy withdraw function. Anyone can call this for someone else as long
    /// as he includes signed data retrieved by using web3.eth.sign(address, hash).
    /// The DAO token holder whose ratio needs to be retrieved is determined by
    /// performing ecrecover on the signed data.
    ///
    /// This function will also allow people to use the ETH chain to give an
    /// approval for withdrawal in the ETC chain without having to sync the
    /// ETC chain. The only requirement is that the account that gives the
    /// approval needs to be an end-user account. Multisig wallets can't do that.
    function proxyWithdraw(address _beneficiary, uint _percentageWHG, uint8 _v, bytes32 _r, bytes32 _s) noEther {
        if (usedSignatures[_r]) {
            throw;
        }
        bytes32 _hash = sha3("Withdraw DAOETC to ", _beneficiary, _percentageWHG);
        address _dth = ecrecover(_hash, _v, _r, _s);
        usedSignatures[_r] = true;
        commonWithdraw(_dth, _beneficiary, _percentageWHG, WithdrawType_PROXY);
        address representedDth = authorizedAddresses.getRepresentedDTH(_dth);
        if (representedDth != 0x0) {
            commonWithdraw(representedDth, _beneficiary, _percentageWHG, WithdrawType_PROXY_AUTHORIZED);
        }
    }

    /// This is the only way to send money to the contract, adding to the total
    /// amount of ETH to be refunded.
    ///
    /// Only people who are considered certified depositors like the whitehat ETC multisig
    /// or addresses owned by exchanges should be able to deposit more ETC for withdrals.
    /// If you need to become a certified depositor please contact Bity SA.
    function deposit() returns (bool) {
        if (!certifiedDepositors[msg.sender]) {
            throw;
        }
        totalFunds += msg.value;
        Deposit(msg.value);
        return true;
    }

    /// Last Resort call, to allow for a reaction if something bad happens to
    /// the contract or if some security issue is uncovered.
    function escapeHatch() noEther onlyOwner returns (bool) {
        uint total = this.balance;
        if (!escape.send(total)) {
            throw;
        }
        EscapeCalled(total);
    }

    /// Allows the claiming of the remaining funds after a given amount of time
    /// Amount is set to 6 months for now but may still change in the future.
    function claimRemaining() noEther returns (bool) {
        if (now < deployTime + 24 weeks) {
            throw;
        }
        uint total = this.balance;
        if (!remainingBeneficary.send(total)) {
            throw;
        }
        RemainingClaimed(total);
    }

    function () { //no donations
        throw;
    }

    function getPaidOut(address _account) noEther constant returns (uint) {
        return paidOut[_account];
    }

    function getMyBalance(address _account) noEther constant returns (uint) {
        return daoBalance.balanceOf(_account);
    }

    function getTotalFunds() noEther constant returns (uint) {
        return totalFunds;
    }

    function getWHGDonationAddress() noEther constant returns (address) {
        return whg_donation;
    }

    function isCertifiedDepositor(address _depositor) noEther constant returns (bool) {
        return certifiedDepositors[_depositor];
    }

    function changeCertifiedDepositors(address _depositor, bool _allowed) onlyOwner noEther external returns (bool _success) {
        certifiedDepositors[_depositor] = _allowed;
        CertifiedDepositorsChanged(_depositor, _allowed);
        return true;
    }

    function isBlacklisted(address _dth) noEther constant returns (bool) {
        return blacklist[_dth];
    }

    function changeBlacklist(address _dth, bool _blocked) onlyOwner noEther external returns (bool _success) {
        blacklist[_dth] = _blocked;
        BlacklistChanged(_dth, _blocked);
        return true;
    }
}


Improve accuracy

Improve accuracy

Changes:
1. Use a (global) array which maps every precision between 32 and 95 to the maximum exponent permitted.
2. Initialize this array at construction.
3. Binary-search this array when estimating the highest precision which can be used on the given input.
4. Use this array in order to assert that the exponent is not larger than the maximum permitted before calculating the Taylor series.

In this fix, instead of dynamically approximating the maximum exponent permitted for each precision (by starting from MAX_EXP_32 and multiplying by approximately 1.9 for every precision unit), we initialize an array containing the exact values of the maximum exponent permitted for each precision.
This (also) allows us to use binary-search instead of sequential search.
And we can therefore allow ourselves to check every precision, and not just every even precision.

So the main differences are:
1. Initializing once upon contract-construction instead of calculating dynamically upon every transaction.
2. Using exact max-exponent values instead of approximated max-exponent values.
3. Checking every precision between 32 and 95 instead of every even precision between 32 and 62.

This helps in both:
1. Improving accuracy.
2. Reducing transaction-failure rate (due to an exponent being larger than the maximum value permitted).

Verification made:
- Correctness.
- Accuracy improvement.
- Gas cost on construction.
- Gas cost per transaction.

More extensive tests are required.

pragma solidity ^0.4.11;
import './SafeMath.sol';
import './interfaces/IBancorFormula.sol';

contract BancorFormula is IBancorFormula, SafeMath {

    uint256[128] maxExpArray;
    uint256 constant UINT1 = 1;
    uint256 constant UINT2 = 2;
    uint256 constant UINT3 = 3;
    uint8 constant MIN_PRECISION = 32;
    uint8 constant MAX_PRECISION = 95;
    string public version = '0.2';

    function BancorFormula() {
//      maxExpArray[  0] = 0xc1;
//      maxExpArray[  1] = 0x17a;
//      maxExpArray[  2] = 0x2e5;
//      maxExpArray[  3] = 0x5ab;
//      maxExpArray[  4] = 0xb1b;
//      maxExpArray[  5] = 0x15bf;
//      maxExpArray[  6] = 0x2a0c;
//      maxExpArray[  7] = 0x50a2;
//      maxExpArray[  8] = 0x9aa2;
//      maxExpArray[  9] = 0x1288c;
//      maxExpArray[ 10] = 0x238b2;
//      maxExpArray[ 11] = 0x4429a;
//      maxExpArray[ 12] = 0x82b78;
//      maxExpArray[ 13] = 0xfaadc;
//      maxExpArray[ 14] = 0x1e0bb8;
//      maxExpArray[ 15] = 0x399e96;
//      maxExpArray[ 16] = 0x6e7f88;
//      maxExpArray[ 17] = 0xd3e7a3;
//      maxExpArray[ 18] = 0x1965fea;
//      maxExpArray[ 19] = 0x30b5057;
//      maxExpArray[ 20] = 0x5d681f3;
//      maxExpArray[ 21] = 0xb320d03;
//      maxExpArray[ 22] = 0x15784a40;
//      maxExpArray[ 23] = 0x292c5bdd;
//      maxExpArray[ 24] = 0x4ef57b9b;
//      maxExpArray[ 25] = 0x976bd995;
//      maxExpArray[ 26] = 0x122624e32;
//      maxExpArray[ 27] = 0x22ce03cd5;
//      maxExpArray[ 28] = 0x42beef808;
//      maxExpArray[ 29] = 0x7ffffffff;
//      maxExpArray[ 30] = 0xf577eded5;
//      maxExpArray[ 31] = 0x1d6bd8b2eb;
        maxExpArray[ 32] = 0x386bfdba29;
        maxExpArray[ 33] = 0x6c3390ecc8;
        maxExpArray[ 34] = 0xcf8014760f;
        maxExpArray[ 35] = 0x18ded91f0e7;
        maxExpArray[ 36] = 0x2fb1d8fe082;
        maxExpArray[ 37] = 0x5b771955b36;
        maxExpArray[ 38] = 0xaf67a93bb50;
        maxExpArray[ 39] = 0x15060c256cb2;
        maxExpArray[ 40] = 0x285145f31ae5;
        maxExpArray[ 41] = 0x4d5156639708;
        maxExpArray[ 42] = 0x944620b0e70e;
        maxExpArray[ 43] = 0x11c592761c666;
        maxExpArray[ 44] = 0x2214d10d014ea;
        maxExpArray[ 45] = 0x415bc6d6fb7dd;
        maxExpArray[ 46] = 0x7d56e76777fc5;
        maxExpArray[ 47] = 0xf05dc6b27edad;
        maxExpArray[ 48] = 0x1ccf4b44bb4820;
        maxExpArray[ 49] = 0x373fc456c53bb7;
        maxExpArray[ 50] = 0x69f3d1c921891c;
        maxExpArray[ 51] = 0xcb2ff529eb71e4;
        maxExpArray[ 52] = 0x185a82b87b72e95;
        maxExpArray[ 53] = 0x2eb40f9f620fda6;
        maxExpArray[ 54] = 0x5990681d961a1ea;
        maxExpArray[ 55] = 0xabc25204e02828d;
        maxExpArray[ 56] = 0x14962dee9dc97640;
        maxExpArray[ 57] = 0x277abdcdab07d5a7;
        maxExpArray[ 58] = 0x4bb5ecca963d54ab;
        maxExpArray[ 59] = 0x9131271922eaa606;
        maxExpArray[ 60] = 0x116701e6ab0cd188d;
        maxExpArray[ 61] = 0x215f77c045fbe8856;
        maxExpArray[ 62] = 0x3ffffffffffffffff;
        maxExpArray[ 63] = 0x7abbf6f6abb9d087f;
        maxExpArray[ 64] = 0xeb5ec597592befbf4;
        maxExpArray[ 65] = 0x1c35fedd14b861eb04;
        maxExpArray[ 66] = 0x3619c87664579bc94a;
        maxExpArray[ 67] = 0x67c00a3b07ffc01fd6;
        maxExpArray[ 68] = 0xc6f6c8f8739773a7a4;
        maxExpArray[ 69] = 0x17d8ec7f04136f4e561;
        maxExpArray[ 70] = 0x2dbb8caad9b7097b91a;
        maxExpArray[ 71] = 0x57b3d49dda84556d6f6;
        maxExpArray[ 72] = 0xa830612b6591d9d9e61;
        maxExpArray[ 73] = 0x1428a2f98d728ae223dd;
        maxExpArray[ 74] = 0x26a8ab31cb8464ed99e1;
        maxExpArray[ 75] = 0x4a23105873875bd52dfd;
        maxExpArray[ 76] = 0x8e2c93b0e33355320ead;
        maxExpArray[ 77] = 0x110a688680a7530515f3e;
        maxExpArray[ 78] = 0x20ade36b7dbeeb8d79659;
        maxExpArray[ 79] = 0x3eab73b3bbfe282243ce1;
        maxExpArray[ 80] = 0x782ee3593f6d69831c453;
        maxExpArray[ 81] = 0xe67a5a25da41063de1495;
        maxExpArray[ 82] = 0x1b9fe22b629ddbbcdf8754;
        maxExpArray[ 83] = 0x34f9e8e490c48e67e6ab8b;
        maxExpArray[ 84] = 0x6597fa94f5b8f20ac16666;
        maxExpArray[ 85] = 0xc2d415c3db974ab32a5184;
        maxExpArray[ 86] = 0x175a07cfb107ed35ab61430;
        maxExpArray[ 87] = 0x2cc8340ecb0d0f520a6af58;
        maxExpArray[ 88] = 0x55e129027014146b9e37405;
        maxExpArray[ 89] = 0xa4b16f74ee4bb2040a1ec6c;
        maxExpArray[ 90] = 0x13bd5ee6d583ead3bd636b5c;
        maxExpArray[ 91] = 0x25daf6654b1eaa55fd64df5e;
        maxExpArray[ 92] = 0x4898938c9175530325b9d116;
        maxExpArray[ 93] = 0x8b380f3558668c46c91c49a2;
        maxExpArray[ 94] = 0x10afbbe022fdf442b2a522507;
        maxExpArray[ 95] = 0x1ffffffffffffffffffffffff;
//      maxExpArray[ 96] = 0x3d5dfb7b55dce843f89a7dbcb;
//      maxExpArray[ 97] = 0x75af62cbac95f7dfa3295ec26;
//      maxExpArray[ 98] = 0xe1aff6e8a5c30f58221fbf899;
//      maxExpArray[ 99] = 0x1b0ce43b322bcde4a56e8ada5a;
//      maxExpArray[100] = 0x33e0051d83ffe00feb432b473b;
//      maxExpArray[101] = 0x637b647c39cbb9d3d26c56e949;
//      maxExpArray[102] = 0xbec763f8209b7a72b0afea0d31;
//      maxExpArray[103] = 0x16ddc6556cdb84bdc8d12d22e6f;
//      maxExpArray[104] = 0x2bd9ea4eed422ab6b7b072b029e;
//      maxExpArray[105] = 0x54183095b2c8ececf30dd533d03;
//      maxExpArray[106] = 0xa14517cc6b9457111eed5b8adf1;
//      maxExpArray[107] = 0x13545598e5c23276ccf0ede68034;
//      maxExpArray[108] = 0x2511882c39c3adea96fec2102329;
//      maxExpArray[109] = 0x471649d87199aa990756806903c5;
//      maxExpArray[110] = 0x88534434053a9828af9f37367ee6;
//      maxExpArray[111] = 0x1056f1b5bedf75c6bcb2ce8aed428;
//      maxExpArray[112] = 0x1f55b9d9ddff141121e70ebe0104e;
//      maxExpArray[113] = 0x3c1771ac9fb6b4c18e229803dae82;
//      maxExpArray[114] = 0x733d2d12ed20831ef0a4aead8c66d;
//      maxExpArray[115] = 0xdcff115b14eedde6fc3aa5353f2e4;
//      maxExpArray[116] = 0x1a7cf47248624733f355c5c1f0d1f1;
//      maxExpArray[117] = 0x32cbfd4a7adc790560b3335687b89b;
//      maxExpArray[118] = 0x616a0ae1edcba5599528c20605b3f6;
//      maxExpArray[119] = 0xbad03e7d883f69ad5b0a186184e06b;
//      maxExpArray[120] = 0x16641a07658687a905357ac0ebe198b;
//      maxExpArray[121] = 0x2af09481380a0a35cf1ba02f36c6a56;
//      maxExpArray[122] = 0x5258b7ba7725d902050f6360afddf96;
//      maxExpArray[123] = 0x9deaf736ac1f569deb1b5ae3f36c130;
//      maxExpArray[124] = 0x12ed7b32a58f552afeb26faf21deca06;
//      maxExpArray[125] = 0x244c49c648baa98192dce88b42f53caf;
//      maxExpArray[126] = 0x459c079aac334623648e24d17c74b3dc;
//      maxExpArray[127] = 0x6ae67b5f2f528d5f3189036ee0f27453;
    }

    /**
        @dev given a token supply, reserve, CRR and a deposit amount (in the reserve token), calculates the return for a given change (in the main token)

        Formula:
        Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 100) - 1)

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _depositAmount      deposit amount, in reserve token

        @return purchase return amount
    */
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _depositAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100);

        // special case for 0 deposit amount
        if (_depositAmount == 0)
            return 0;

        uint256 baseN = safeAdd(_depositAmount, _reserveBalance);
        uint256 temp;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp = safeMul(_supply, baseN) / _reserveBalance;
            return safeSub(temp, _supply);
        }

        uint8 precision = calculateBestPrecision(baseN, _reserveBalance, _reserveRatio, 100);
        uint256 resN = power(baseN, _reserveBalance, _reserveRatio, 100, precision);
        temp = safeMul(_supply, resN) >> precision;
        return safeSub(temp, _supply);
     }

    /**
        @dev given a token supply, reserve, CRR and a sell amount (in the main token), calculates the return for a given change (in the reserve token)

        Formula:
        Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1 / (_reserveRatio / 100)))

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _sellAmount         sell amount, in the token itself

        @return sale return amount
    */
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _sellAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100 && _sellAmount <= _supply);

        // special case for 0 sell amount
        if (_sellAmount == 0)
            return 0;

        uint256 baseD = safeSub(_supply, _sellAmount);
        uint256 temp1;
        uint256 temp2;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp1 = safeMul(_reserveBalance, _supply);
            temp2 = safeMul(_reserveBalance, baseD);
            return safeSub(temp1, temp2) / _supply;
        }

        // special case for selling the entire supply
        if (_sellAmount == _supply)
            return _reserveBalance;

        uint8 precision = calculateBestPrecision(_supply, baseD, 100, _reserveRatio);
        uint256 resN = power(_supply, baseD, 100, _reserveRatio, precision);
        temp1 = safeMul(_reserveBalance, resN);
        temp2 = safeMul(_reserveBalance, UINT1 << precision);
        return safeSub(temp1, temp2) / resN;
    }

    /**
        calculateBestPrecision
        Predicts the highest precision which can be used in order to compute "base ^ exp" without exceeding 256 bits in any of the intermediate computations.
        Instead of calculating "base ^ exp", we calculate "e ^ (ln(base) * exp)".
        The value of "ln(base)" is represented with an integer slightly smaller than "ln(base) * 2 ^ precision".
        The larger the precision is, the more accurately this value represents the real value.
        However, function fixedExpUnsafe(x), which calculates "e ^ x", is limited to a maximum value of x.
        The limit depends on the precision - maxExpArray maps each precision between 0 and 127 to the maximum value permitted.
        Hence before calling the 'power' function, we need to estimate an upper-bound for "ln(base) * exp".
        Of course, we should later assert that the value passed to fixedExpUnsafe is not larger than maxExpArray[precision].
        Due to this assertion (made in function fixedExp), functions calculateBestPrecision and fixedExp are tightly coupled.
        Note that the outcome of this function only affects the accuracy of the computation of "base ^ exp".
        Therefore, we do not need to assert that no intermediate result exceeds 256 bits (nor in this function, neither in any of the functions down the calling tree).
    */
    function calculateBestPrecision(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD) constant returns (uint8) {
        uint256 maxVal = lnUpperBound(_baseN, _baseD) * _expN;
		uint8 lo = MIN_PRECISION;
		uint8 hi = MAX_PRECISION;
		while (lo + 1 < hi) {
			uint8 mid = (lo + hi) / 2;
			if ((maxVal << (mid - MIN_PRECISION)) / _expD <= maxExpArray[mid])
				lo = mid;
			else
				hi = mid;
		}
		if ((maxVal << (hi - MIN_PRECISION)) / _expD <= maxExpArray[hi])
			return hi;
		else
			return lo;
    }

    /**
        @dev calculates (_baseN / _baseD) ^ (_expN / _expD)
        Returns result upshifted by precision

        This method is overflow-safe
    */
    function power(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD, uint8 _precision) constant returns (uint256) {
        uint256 logbase = ln(_baseN, _baseD, _precision);
        // Not using safeDiv here, since safeDiv protects against
        // precision loss. It's unavoidable, however
        // Both `ln` and `fixedExp` are overflow-safe.
        return fixedExp(safeMul(logbase, _expN) / _expD, _precision);
    }

    /**
        input range:
            - numerator: [1, uint256_max / 2 ^ precision]
            - denominator: [1, numerator]
            If numerator / denominator < 1 then ln(numerator / denominator) < 0
        output range:
            [0, ln(uint256_max) * 2 ^ precision]

        This method asserts outside of bounds
    */
    function ln(uint256 _numerator, uint256 _denominator, uint8 _precision) public constant returns (uint256) {
        assert(0 < _denominator && _denominator <= _numerator && _numerator < (UINT1 << (256 - _precision)));
        return fixedLoge( (_numerator << _precision) / _denominator, _precision);
    }

    /**
        lnUpperBound
        Takes a rational number "baseN / baseD" as input.
        Returns an integer upper-bound of the natural logarithm of the input scaled by 2 ^ MIN_PRECISION.
        We do this by calculating "Ceiling(log2(baseN / baseD)) * Ceiling(ln(2) * 2 ^ MIN_PRECISION)".
        For small values of "baseN / baseD", this sometimes yields a bad upper-bound approximation.
        We therefore cover these cases (and a few more) manually.
        Complexity is O(log(input bit-length)).
    */
    function lnUpperBound(uint256 _baseN, uint256 _baseD) constant returns (uint256) {
        assert(_baseN > _baseD);

        uint256 scaledBaseN = _baseN << MIN_PRECISION;
        if (scaledBaseN <= _baseD *  0x2b7e15162) // _baseN / _baseD < e^1 (floorLog2 will return 0 if _baseN / _baseD < 2)
            return UINT1 << MIN_PRECISION;
        if (scaledBaseN <= _baseD *  0x763992e35) // _baseN / _baseD < e^2 (floorLog2 will return 1 if _baseN / _baseD < 4)
            return UINT2 << MIN_PRECISION;
        if (scaledBaseN <= _baseD * 0x1415e5bf6f) // _baseN / _baseD < e^3 (floorLog2 will return 2 if _baseN / _baseD < 8)
            return UINT3 << MIN_PRECISION;

        return ceilLog2(_baseN, _baseD) * 0xb17217f8;
    }

    /**
        input range:
            [0x100000000, uint256_max]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

        Since `fixedLog2_min` output range is max `0xdfffffffff`
        (40 bits, or 5 bytes), we can use a very large approximation
        for `ln(2)`. This one is used since it's the max accuracy
        of Python `ln(2)`

        0xb17217f7d1cf78 = ln(2) * (1 << 56)
    */
    function fixedLoge(uint256 _x, uint8 _precision) constant returns (uint256) {
        // cannot represent negative numbers (below 1)
        assert(_x >= UINT1 << _precision);

        uint256 log2 = fixedLog2(_x, _precision);
        return (log2 * 0xb17217f7d1cf78) >> 56;
    }

    /**
        Returns log2(x >> 32) << 32 [1]
        So x is assumed to be already upshifted 32 bits, and
        the result is also upshifted 32 bits.

        [1] The function returns a number which is lower than the
        actual value

        input-range:
            [0x100000000, uint256_max]
        output-range:
            [0,0xdfffffffff]

        This method asserts outside of bounds

    */
    function fixedLog2(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 fixedOne = UINT1 << _precision;
        uint256 fixedTwo = UINT2 << _precision;

        // Numbers below 1 are negative.
        assert( _x >= fixedOne);

        uint256 hi = 0;
        while (_x >= fixedTwo) {
            _x >>= 1;
            hi += fixedOne;
        }

        for (uint8 i = 0; i < _precision; ++i) {
            _x = (_x * _x) / fixedOne;
            if (_x >= fixedTwo) {
                _x >>= 1;
                hi += UINT1 << (_precision - 1 - i);
            }
        }

        return hi;
    }

    /**
        ceilLog2
        Takes a rational number "baseN / baseD" as input.
        Returns the smallest integer larger than or equal to the binary logarithm of the input.
        Complexity is O(log(input bit-length)).
    */
    function ceilLog2(uint256 _baseN, uint256 _baseD) constant returns (uint256) {
        return floorLog2((_baseN - 1) / _baseD) + 1;
    }

    /**
        floorLog2
        Takes a natural number (n) as input.
        Returns the largest integer smaller than or equal to the binary logarithm of the input.
        Complexity is O(log(input bit-length)).
    */
    function floorLog2(uint256 _n) constant returns (uint256) {
        uint8 t = 0;
        for (uint8 s = 128; s > 0; s >>= 1) {
            if (_n >= (UINT1 << s)) {
                _n >>= s;
                t |= s;
            }
        }

        return t;
    }

    /**
        fixedExp is a 'protected' version of `fixedExpUnsafe`, which asserts instead of overflows.
        The maximum value which can be passed to fixedExpUnsafe depends on the precision used.
        The global maxExpArray maps each precision between 0 and 127 to the maximum value permitted.
    */
    function fixedExp(uint256 _x, uint8 _precision) constant returns (uint256) {
        assert(_x <= maxExpArray[_precision]);
        return fixedExpUnsafe(_x, _precision);
    }

    /**
        fixedExp
        Calculates e ^ x according to maclauren summation:

        e^x = 1 + x + x ^ 2 / 2!...+ x ^ n / n!

        and returns e ^ (x >> 32) << 32, that is, upshifted for accuracy

        Input range: the maximum permitted value for _x depends on the value of _precision.
        Read the documentation of function fixedExp for more details.

        This method is is visible for testcases, but not meant for direct use.

        The values in this method been generated via the following python snippet:

        def calculateFactorials():
            """Method to print out the factorials for fixedExp"""

            ni = []
            ni.append(295232799039604140847618609643520000000) # 34!
            ITERATIONS = 34
            for n in range(1, ITERATIONS, 1) :
                ni.append(math.floor(ni[n - 1] / n))
            print( "\n        ".join(["xi = (xi * _x) >> _precision;\n        res += xi * %s;" % hex(int(x)) for x in ni]))

    */
    function fixedExpUnsafe(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 xi = _x;
        uint256 res = uint256(0xde1bc4d19efcac82445da75b00000000) << _precision;

        res += xi * 0xde1bc4d19efcac82445da75b00000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x6f0de268cf7e5641222ed3ad80000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x2504a0cd9a7f7215b60f9be480000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9412833669fdc856d83e6f920000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1d9d4d714865f4de2b3fafea0000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x4ef8ce836bba8cfb1dff2a70000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xb481d807d1aa66d04490610000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x16903b00fa354cda08920c2000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x281cdaac677b334ab9e732000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x402e2aad725eb8778fd85000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x5d5a6c9f31fe2396a2af000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x7c7890d442a82f73839400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9931ed54034526b58e400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaf147cf24ce150cf7e00000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa200000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa20000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xafc441338061b2820000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9c3cabbc0056d790000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x839168328705c30000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x694120286c049c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x50319e98b3d2c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x3a52a1e36b82000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x289286e0fce000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1b0c59eb53400;
        xi = (xi * _x) >> _precision;
        res += xi * 0x114f95b55400;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaa7210d200;
        xi = (xi * _x) >> _precision;
        res += xi * 0x650139600;
        xi = (xi * _x) >> _precision;
        res += xi * 0x39b78e80;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1fd8080;
        xi = (xi * _x) >> _precision;
        res += xi * 0x10fbc0;
        xi = (xi * _x) >> _precision;
        res += xi * 0x8c40;
        xi = (xi * _x) >> _precision;
        res += xi * 0x462;
        xi = (xi * _x) >> _precision;
        res += xi * 0x22;

        return res / 0xde1bc4d19efcac82445da75b00000000;
    }
}

pragma solidity ^0.4.11;
import './SafeMath.sol';
import './interfaces/IBancorFormula.sol';

/*
    Open issues:
    - The formula is not yet super accurate, especially for very small/very high ratios
    - Improve dynamic precision support
*/

contract BancorFormula is IBancorFormula, SafeMath {

    uint256 constant ONE = 1;
    uint256 constant TWO = 2;
    uint256 constant MAX_FIXED_EXP_32 = 0x386bfdba29;
    uint256 constant MAX_FACTOR_64 = 0xeb5ec5975959c565;
    string public version = '0.2';

    function BancorFormula() {
    }

    /**
        @dev given a token supply, reserve, CRR and a deposit amount (in the reserve token), calculates the return for a given change (in the main token)

        Formula:
        Return = _supply * ((1 + _depositAmount / _reserveBalance) ^ (_reserveRatio / 100) - 1)

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _depositAmount      deposit amount, in reserve token

        @return purchase return amount
    */
    function calculatePurchaseReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _depositAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100);

        // special case for 0 deposit amount
        if (_depositAmount == 0)
            return 0;

        uint256 baseN = safeAdd(_depositAmount, _reserveBalance);
        uint256 temp;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp = safeMul(_supply, baseN) / _reserveBalance;
            return safeSub(temp, _supply);
        }

        uint8 precision = calculateBestPrecision(baseN, _reserveBalance, _reserveRatio, 100);
        uint256 resN = power(baseN, _reserveBalance, _reserveRatio, 100, precision);
        temp = safeMul(_supply, resN) >> precision;
        return safeSub(temp, _supply);
     }

    /**
        @dev given a token supply, reserve, CRR and a sell amount (in the main token), calculates the return for a given change (in the reserve token)

        Formula:
        Return = _reserveBalance * (1 - (1 - _sellAmount / _supply) ^ (1 / (_reserveRatio / 100)))

        @param _supply             token total supply
        @param _reserveBalance     total reserve
        @param _reserveRatio       constant reserve ratio, 1-100
        @param _sellAmount         sell amount, in the token itself

        @return sale return amount
    */
    function calculateSaleReturn(uint256 _supply, uint256 _reserveBalance, uint8 _reserveRatio, uint256 _sellAmount) public constant returns (uint256) {
        // validate input
        require(_supply != 0 && _reserveBalance != 0 && _reserveRatio > 0 && _reserveRatio <= 100 && _sellAmount <= _supply);

        // special case for 0 sell amount
        if (_sellAmount == 0)
            return 0;

        uint256 baseD = safeSub(_supply, _sellAmount);
        uint256 temp1;
        uint256 temp2;

        // special case if the CRR = 100
        if (_reserveRatio == 100) {
            temp1 = safeMul(_reserveBalance, _supply);
            temp2 = safeMul(_reserveBalance, baseD);
            return safeSub(temp1, temp2) / _supply;
        }

        // special case for selling the entire supply
        if (_sellAmount == _supply)
            return _reserveBalance;

        uint8 precision = calculateBestPrecision(_supply, baseD, 100, _reserveRatio);
        uint256 resN = power(_supply, baseD, 100, _reserveRatio, precision);
        temp1 = safeMul(_reserveBalance, resN);
        temp2 = safeMul(_reserveBalance, ONE << precision);
        return safeSub(temp1, temp2) / resN;
    }

    /**
        calculateBestPrecision
        Predicts the highest precision which can be used in order to compute "base^exp" without exceeding 256 bits in any of the intermediate computations.
        Instead of calculating "base ^ exp", we calculate "e ^ (ln(base) * exp)".
        The value of ln(base) is represented with an integer slightly smaller than ln(base) * 2 ^ precision.
        The larger the precision is, the more accurately this value represents the real value.
        However, function fixedExpUnsafe(x), which calculates e ^ x, is limited to a maximum value of x.
        The limit depends on the precision (e.g, for precision = 32, the maximum value of x is MAX_FIXED_EXP_32).
        Hence before calling the 'power' function, we need to estimate an upper-bound for ln(base) * exponent.
        Of course, we should later assert that the value passed to fixedExpUnsafe is not larger than MAX_FIXED_EXP(precision).
        Due to this assertion (made in function fixedExp), functions calculateBestPrecision and fixedExp are tightly coupled.
        Note that the outcome of this function only affects the accuracy of the computation of "base ^ exp".
        Therefore, we do not need to assert that no intermediate result exceeds 256 bits (nor in this function, neither in any of the functions down the calling tree).
    */
    function calculateBestPrecision(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD) constant returns (uint8) {
        uint8 precision;
        uint256 maxExp = MAX_FIXED_EXP_32;
        uint256 maxVal = lnUpperBound32(_baseN,_baseD) * _expN;
        for (precision = 0; precision < 32; precision += 2) {
            if (maxExp < (maxVal << precision) / _expD)
                break;
            maxExp = (maxExp * MAX_FACTOR_64) >> (64-2);
        }
        if (precision == 0)
            return 32;
        return precision+32-2;
    }

    /**
        @dev calculates (_baseN / _baseD) ^ (_expN / _expD)
        Returns result upshifted by precision

        This method is overflow-safe
    */
    function power(uint256 _baseN, uint256 _baseD, uint256 _expN, uint256 _expD, uint8 _precision) constant returns (uint256) {
        uint256 logbase = ln(_baseN, _baseD, _precision);
        // Not using safeDiv here, since safeDiv protects against
        // precision loss. It's unavoidable, however
        // Both `ln` and `fixedExp` are overflow-safe.
        return fixedExp(safeMul(logbase, _expN) / _expD, _precision);
    }

    /**
        input range:
            - numerator: [1, uint256_max / 2 ^ precision]
            - denominator: [1, numerator]
            If numerator / denominator < 1 then ln(numerator / denominator) < 0
        output range:
            [0, ln(uint256_max) * 2 ^ precision]

        This method asserts outside of bounds
    */
    function ln(uint256 _numerator, uint256 _denominator, uint8 _precision) public constant returns (uint256) {
        // validate input
        assert(0 < _denominator && _denominator <= _numerator && _numerator < (ONE << (256 - _precision)));

        return fixedLoge( (_numerator << _precision) / _denominator, _precision);
    }

    /**
        lnUpperBound32
        Takes a rational number "baseN / baseD" as input.
        Returns an integer upper-bound of the natural logarithm of the input scaled by 2^32.
        We do this by calculating "Ceiling(log2(baseN / baseD)) * Ceiling(ln(2) * 2^32)".
        For small values of "baseN / baseD", this sometimes yields a bad upper-bound approximation.
        We therefore cover these cases (and a few more) manually.
        Complexity is O(log(input bit-length)).
    */
    function lnUpperBound32(uint256 _baseN, uint256 _baseD) constant returns (uint256) {
        assert(_baseN > _baseD);

        uint256 scaledBaseN = _baseN << 32;
        if (scaledBaseN <= _baseD *  0x2b7e15162) // _baseN / _baseD < e^1 (floorLog2 will return 0 if _baseN / _baseD < 2)
            return uint256(1) << 32;
        if (scaledBaseN <= _baseD *  0x763992e35) // _baseN / _baseD < e^2 (floorLog2 will return 1 if _baseN / _baseD < 4)
            return uint256(2) << 32;
        if (scaledBaseN <= _baseD * 0x1415e5bf6f) // _baseN / _baseD < e^3 (floorLog2 will return 2 if _baseN / _baseD < 8)
            return uint256(3) << 32;

        return ceilLog2(_baseN, _baseD) * 0xb17217f8;
    }

    /**
        input range:
            [0x100000000, uint256_max]
        output range:
            [0, 0x9b43d4f8d6]

        This method asserts outside of bounds

        Since `fixedLog2_min` output range is max `0xdfffffffff`
        (40 bits, or 5 bytes), we can use a very large approximation
        for `ln(2)`. This one is used since it's the max accuracy
        of Python `ln(2)`

        0xb17217f7d1cf78 = ln(2) * (1 << 56)
    */
    function fixedLoge(uint256 _x, uint8 _precision) constant returns (uint256) {
        // cannot represent negative numbers (below 1)
        assert(_x >= ONE << _precision);

        uint256 log2 = fixedLog2(_x, _precision);
        return (log2 * 0xb17217f7d1cf78) >> 56;
    }

    /**
        Returns log2(x >> 32) << 32 [1]
        So x is assumed to be already upshifted 32 bits, and
        the result is also upshifted 32 bits.

        [1] The function returns a number which is lower than the
        actual value

        input-range :
            [0x100000000, uint256_max]
        output-range:
            [0,0xdfffffffff]

        This method asserts outside of bounds

    */
    function fixedLog2(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 fixedOne = ONE << _precision;
        uint256 fixedTwo = TWO << _precision;

        // Numbers below 1 are negative.
        assert( _x >= fixedOne);

        uint256 hi = 0;
        while (_x >= fixedTwo) {
            _x >>= 1;
            hi += fixedOne;
        }

        for (uint8 i = 0; i < _precision; ++i) {
            _x = (_x * _x) / fixedOne;
            if (_x >= fixedTwo) {
                _x >>= 1;
                hi += ONE << (_precision - 1 - i);
            }
        }

        return hi;
    }

    /**
        ceilLog2
        Takes a rational number "baseN / baseD" as input.
        Returns the smallest integer larger than or equal to the binary logarithm of the input.
        Complexity is O(log(input bit-length)).
    */
    function ceilLog2(uint256 _baseN, uint256 _baseD) constant returns (uint256) {
        return floorLog2((_baseN - 1) / _baseD) + 1;
    }

    /**
        floorLog2
        Takes a natural number (n) as input.
        Returns the largest integer smaller than or equal to the binary logarithm of the input.
        Complexity is O(log(input bit-length)).
    */
    function floorLog2(uint256 _n) constant returns (uint256) {
        uint8 t = 0;
        for (uint8 s = 128; s > 0; s >>= 1) {
            if (_n >= (ONE << s)) {
                _n >>= s;
                t |= s;
            }
        }

        return t;
    }

    /**
        fixedExp is a 'protected' version of `fixedExpUnsafe`, which asserts instead of overflows.
        The maximum value which can be passed to fixedExpUnsafe depends on the precision used.
        The following array maps each precision between 0 and 63 to the maximum value permitted:
        maxExpArray = {
            0xc1               ,0x17a              ,0x2e5              ,0x5ab              ,
            0xb1b              ,0x15bf             ,0x2a0c             ,0x50a2             ,
            0x9aa2             ,0x1288c            ,0x238b2            ,0x4429a            ,
            0x82b78            ,0xfaadc            ,0x1e0bb8           ,0x399e96           ,
            0x6e7f88           ,0xd3e7a3           ,0x1965fea          ,0x30b5057          ,
            0x5d681f3          ,0xb320d03          ,0x15784a40         ,0x292c5bdd         ,
            0x4ef57b9b         ,0x976bd995         ,0x122624e32        ,0x22ce03cd5        ,
            0x42beef808        ,0x7ffffffff        ,0xf577eded5        ,0x1d6bd8b2eb       ,
            0x386bfdba29       ,0x6c3390ecc8       ,0xcf8014760f       ,0x18ded91f0e7      ,
            0x2fb1d8fe082      ,0x5b771955b36      ,0xaf67a93bb50      ,0x15060c256cb2     ,
            0x285145f31ae5     ,0x4d5156639708     ,0x944620b0e70e     ,0x11c592761c666    ,
            0x2214d10d014ea    ,0x415bc6d6fb7dd    ,0x7d56e76777fc5    ,0xf05dc6b27edad    ,
            0x1ccf4b44bb4820   ,0x373fc456c53bb7   ,0x69f3d1c921891c   ,0xcb2ff529eb71e4   ,
            0x185a82b87b72e95  ,0x2eb40f9f620fda6  ,0x5990681d961a1ea  ,0xabc25204e02828d  ,
            0x14962dee9dc97640 ,0x277abdcdab07d5a7 ,0x4bb5ecca963d54ab ,0x9131271922eaa606 ,
            0x116701e6ab0cd188d,0x215f77c045fbe8856,0x3ffffffffffffffff,0x7abbf6f6abb9d087f,
        };
        Since we cannot use an array of constants, we need to approximate the maximum value dynamically.
        For a precision of 32, the maximum value permitted is MAX_FIXED_EXP_32.
        For each additional precision unit, the maximum value permitted increases by approximately 1.9.
        So in order to calculate it, we need to multiply MAX_FIXED_EXP_32 by 1.9 for every additional precision unit.
        And in order to optimize for speed, we multiply MAX_FIXED_EXP_32 by 1.9^2 for every 2 additional precision units.
        Hence the general function for mapping a given precision to the maximum value permitted is:
        - precision = [32, 34, 36, ..., 62]
        - MaxFixedExp(precision) = MAX_FIXED_EXP_32 * 3.61 ^ (precision / 2 - 16)
        Since we cannot use non-integers, we do MAX_FIXED_EXP_32 * 361 ^ (precision / 2 - 16) / 100 ^ (precision / 2 - 16).
        But there is a better approximation, because this "1.9" factor in fact extends beyond a single decimal digit.
        So instead, we use 0xeb5ec5975959c565 / 0x4000000000000000, which yields maximum values quite close to the real ones:
        maxExpArray = {
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            -------------------,-------------------,-------------------,-------------------,
            0x386bfdba29       ,-------------------,0xcf8014760e       ,-------------------,
            0x2fb1d8fe07b      ,-------------------,0xaf67a93bb37      ,-------------------,
            0x285145f31a8f     ,-------------------,0x944620b0e5ee     ,-------------------,
            0x2214d10d0112e    ,-------------------,0x7d56e7677738e    ,-------------------,
            0x1ccf4b44bb20d0   ,-------------------,0x69f3d1c9210d27   ,-------------------,
            0x185a82b87b5b294  ,-------------------,0x5990681d95d4371  ,-------------------,
            0x14962dee9dbd672b ,-------------------,0x4bb5ecca961fb9bf ,-------------------,
            0x116701e6ab0967080,-------------------,0x3fffffffffffe6652,-------------------,
        };
    */
    function fixedExp(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 maxExp = MAX_FIXED_EXP_32;
        for (uint8 p = 32; p < _precision; p += 2)
            maxExp = (maxExp * MAX_FACTOR_64) >> (64-2);

        assert(_x <= maxExp);
        return fixedExpUnsafe(_x, _precision);
    }

    /**
        fixedExp
        Calculates e ^ x according to maclauren summation:

        e^x = 1 + x + x ^ 2 / 2!...+ x ^ n / n!

        and returns e ^ (x >> 32) << 32, that is, upshifted for accuracy

        Input range: the maximum permitted value for _x depends on the value of _precision.
        Read the documentation of function fixedExp for more details.

        This method is is visible for testcases, but not meant for direct use.

        The values in this method been generated via the following python snippet:

        def calculateFactorials():
            """Method to print out the factorials for fixedExp"""

            ni = []
            ni.append(295232799039604140847618609643520000000) # 34!
            ITERATIONS = 34
            for n in range(1, ITERATIONS, 1) :
                ni.append(math.floor(ni[n - 1] / n))
            print( "\n        ".join(["xi = (xi * _x) >> _precision;\n        res += xi * %s;" % hex(int(x)) for x in ni]))

    */
    function fixedExpUnsafe(uint256 _x, uint8 _precision) constant returns (uint256) {
        uint256 xi = _x;
        uint256 res = uint256(0xde1bc4d19efcac82445da75b00000000) << _precision;

        res += xi * 0xde1bc4d19efcac82445da75b00000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x6f0de268cf7e5641222ed3ad80000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x2504a0cd9a7f7215b60f9be480000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9412833669fdc856d83e6f920000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1d9d4d714865f4de2b3fafea0000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x4ef8ce836bba8cfb1dff2a70000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xb481d807d1aa66d04490610000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x16903b00fa354cda08920c2000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x281cdaac677b334ab9e732000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x402e2aad725eb8778fd85000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x5d5a6c9f31fe2396a2af000000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x7c7890d442a82f73839400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9931ed54034526b58e400000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaf147cf24ce150cf7e00000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa200000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xbac08546b867cdaa20000;
        xi = (xi * _x) >> _precision;
        res += xi * 0xafc441338061b2820000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x9c3cabbc0056d790000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x839168328705c30000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x694120286c049c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x50319e98b3d2c000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x3a52a1e36b82000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x289286e0fce000;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1b0c59eb53400;
        xi = (xi * _x) >> _precision;
        res += xi * 0x114f95b55400;
        xi = (xi * _x) >> _precision;
        res += xi * 0xaa7210d200;
        xi = (xi * _x) >> _precision;
        res += xi * 0x650139600;
        xi = (xi * _x) >> _precision;
        res += xi * 0x39b78e80;
        xi = (xi * _x) >> _precision;
        res += xi * 0x1fd8080;
        xi = (xi * _x) >> _precision;
        res += xi * 0x10fbc0;
        xi = (xi * _x) >> _precision;
        res += xi * 0x8c40;
        xi = (xi * _x) >> _precision;
        res += xi * 0x462;
        xi = (xi * _x) >> _precision;
        res += xi * 0x22;

        return res / 0xde1bc4d19efcac82445da75b00000000;
    }
}