Python decimal 模块,localcontext() 实例源码

我们从Python开源项目中,提取了以下27个代码示例,用于说明如何使用decimal.localcontext()

项目:graphql-compiler    作者:kensho-technologies    | 项目源码 | 文件源码
def represent_float_as_str(value):
    """Represent a float as a string without losing precision."""
    # In Python 2, calling str() on a float object loses precision:
    #
    # In [1]: 1.23456789012345678
    # Out[1]: 1.2345678901234567
    #
    # In [2]: 1.2345678901234567
    # Out[2]: 1.2345678901234567
    #
    # In [3]: str(1.2345678901234567)
    # Out[3]: '1.23456789012'
    #
    # The best way to ensure precision is not lost is to convert to string via Decimal:
    # https://github.com/mogui/pyorient/pull/226/files
    if not isinstance(value, float):
        raise GraphQLInvalidArgumentError(u'Attempting to represent a non-float as a float: '
                                          u'{}'.format(value))

    with decimal.localcontext() as ctx:
        ctx.prec = 20  # floats are max 80-bits wide = 20 significant digits
        return u'{:f}'.format(decimal.Decimal(value))
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def __init__(self, default_position, undercut_market_by=0.01, minimum_return=1.005, market_fee=0.005):
        '''
        default_position is whether the Strategy should hold the minor currency (sell, False) or
        the major currency (buy / True) after scalping the market. For example, in a USD-CAD market
        True would mean CAD is held after scalping and False would mean USD is held after scalping.

        It is assumed that the default_position is currently being held. If not, override it by setting
        current_position after initializing the strategy.
        '''

        Strategy.__init__(self)

        self._spread_size_indicator = SpreadSize(minimum_return, market_fee)
        self.default_position = default_position
        self.current_position = default_position
        self._first_time_unprofitable = True #Prevents repeating the same message.

        # undercut_market_by is used to make the strategy's order be the next one filled on the market.
        with localcontext() as context:
            context.prec = 8
            self.undercut_market_by = Decimal(undercut_market_by)
项目:meta    作者:flowdas    | 项目源码 | 文件源码
def _load_(self, value, context):
        if isinstance(value, decimal.Decimal):
            if not self.get_options().allow_nan and not value.is_finite():
                raise ValueError()
            return value
        elif isinstance(value, text_types):
            try:
                with decimal.localcontext() as ctx:
                    ctx.traps[decimal.InvalidOperation] = 1
                    value = decimal.Decimal(value)
                    if not self.get_options().allow_nan and not value.is_finite():
                        raise ValueError()
                    return value
            except decimal.InvalidOperation:
                raise ValueError()
        elif isinstance(value, integer_types):
            return decimal.Decimal(value)
        elif isinstance(value, float):
            if not self.get_options().allow_nan:
                if math.isnan(value) or math.isinf(value):
                    raise ValueError()
            return decimal.Decimal(value)
        else:
            raise ValueError()
项目:rectpack    作者:secnot    | 项目源码 | 文件源码
def float2dec(ft, decimal_digits):
    """
    Convert float (or int) to Decimal (rounding up) with the
    requested number of decimal digits.

    Arguments:
        ft (float, int): Number to convert
        decimal (int): Number of digits after decimal point

    Return:
        Decimal: Number converted to decima
    """
    with decimal.localcontext() as ctx:
        ctx.rounding = decimal.ROUND_UP
        places = decimal.Decimal(10)**(-decimal_digits)
        return decimal.Decimal.from_float(float(ft)).quantize(places)


# Sorting algos for rectangle lists
项目:kodi-bandcamp    作者:wallon-ines    | 项目源码 | 文件源码
def _do_decode(self, state):
        """This is the internal function that does the JSON decoding.

        Called by the decode() method, after it has performed any Unicode decoding, etc.
        """
        buf = state.buf
        self.skipws(state)

        if buf.at_end:
            state.push_error('No value to decode')
        else:
            if state.options.decimal_context:
                dec_ctx = decimal.localcontext( state.options.decimal_context )
            else:
                dec_ctx = _dummy_context_manager

            with dec_ctx:
                state.obj = self.decodeobj(state, at_document_start=True )

            if not state.should_stop:
                # Make sure there's nothing at the end
                self.skipws(state)
                if not buf.at_end:
                    state.push_error('Unexpected text after end of JSON value')
项目:tumanov_castleoaks    作者:Roamdev    | 项目源码 | 文件源码
def _format_number(cls, number):
        if isinstance(number, (Number, str)):
            try:
                value = Decimal(number)
            except InvalidOperation:
                raise ValueError('Invalid coordinate format: %r' % number)
            else:
                with localcontext() as ctx:
                    ctx.prec = 13
                    ctx.rounding = ROUND_HALF_UP
                    return value + 0
        elif isinstance(number, Decimal):
            return number
        else:
            raise TypeError('Invalid coordinates type: %r' % number)
项目:SaBoT    作者:froscon    | 项目源码 | 文件源码
def getPriceGross(self):
        with localcontext() as ctx:
            ctx.rounding = ROUND_HALF_EVEN

            vatPercent = Decimal(settings.INVOICE_VAT) * Decimal("0.01")
            grossPrice = self.price + (self.price * vatPercent)
            return grossPrice.quantize(Decimal("0.01"))
项目:SaBoT    作者:froscon    | 项目源码 | 文件源码
def getVATAmount(self):
        with localcontext() as ctx:
            ctx.rounding = ROUND_HALF_EVEN

            vatPercent = Decimal(settings.INVOICE_VAT) * Decimal("0.01")
            vatAmount = self.price * vatPercent
            return vatAmount.quantize(Decimal("0.01"))
项目:Project-Euler    作者:XiaoTaoWang    | 项目源码 | 文件源码
def working(maxnum=100):
    sums = []
    for i in range(1, maxnum+1):
        rootint = int(i ** 0.5)
        if rootint ** 2 != i:
            with decimal.localcontext() as c:
                c.prec = 102
                rootstr = str(decimal.Decimal(i) ** decimal.Decimal('0.5'))
                rootstr = rootstr.replace('.', '')
                tmpsum = 0
                for j in range(100):
                    tmpsum += int(rootstr[j])
                sums.append(tmpsum)

    return sum(sums)
项目:astrocats    作者:astrocatalogs    | 项目源码 | 文件源码
def set_pd_mag_from_counts(photodict,
                           c='',
                           ec='',
                           lec='',
                           uec='',
                           zp=DEFAULT_ZP,
                           sig=DEFAULT_UL_SIGMA):
    """Set photometry dictionary from a counts measurement."""
    with localcontext() as ctx:
        if lec == '' or uec == '':
            lec = ec
            uec = ec
        prec = max(
            get_sig_digits(str(c), strip_zeroes=False),
            get_sig_digits(str(lec), strip_zeroes=False),
            get_sig_digits(str(uec), strip_zeroes=False)) + 1
        ctx.prec = prec
        dlec = Decimal(str(lec))
        duec = Decimal(str(uec))
        if c != '':
            dc = Decimal(str(c))
        dzp = Decimal(str(zp))
        dsig = Decimal(str(sig))
        photodict[PHOTOMETRY.ZERO_POINT] = str(zp)
        if c == '' or float(c) < DEFAULT_UL_SIGMA * float(uec):
            photodict[PHOTOMETRY.UPPER_LIMIT] = True
            photodict[PHOTOMETRY.UPPER_LIMIT_SIGMA] = str(sig)
            photodict[PHOTOMETRY.MAGNITUDE] = str(dzp - (D25 * (dsig * duec
                                                                ).log10()))
            dnec = Decimal('10.0') ** (
                (dzp - Decimal(photodict[PHOTOMETRY.MAGNITUDE])) / D25)
            photodict[PHOTOMETRY.E_UPPER_MAGNITUDE] = str(D25 * (
                (dnec + duec).log10() - dnec.log10()))
        else:
            photodict[PHOTOMETRY.MAGNITUDE] = str(dzp - D25 * dc.log10())
            photodict[PHOTOMETRY.E_UPPER_MAGNITUDE] = str(D25 * (
                (dc + duec).log10() - dc.log10()))
            photodict[PHOTOMETRY.E_LOWER_MAGNITUDE] = str(D25 * (
                dc.log10() - (dc - dlec).log10()))
项目:astrocats    作者:astrocatalogs    | 项目源码 | 文件源码
def set_pd_mag_from_flux_density(photodict,
                                 fd='',
                                 efd='',
                                 lefd='',
                                 uefd='',
                                 sig=DEFAULT_UL_SIGMA):
    """Set photometry dictionary from a flux density measurement.

    `fd` is assumed to be in microjanskys.
    """
    with localcontext() as ctx:
        if lefd == '' or uefd == '':
            lefd = efd
            uefd = efd
        prec = max(
            get_sig_digits(str(fd), strip_zeroes=False),
            get_sig_digits(str(lefd), strip_zeroes=False),
            get_sig_digits(str(uefd), strip_zeroes=False)) + 1
        ctx.prec = prec
        dlefd = Decimal(str(lefd))
        duefd = Decimal(str(uefd))
        if fd != '':
            dfd = Decimal(str(fd))
        dsig = Decimal(str(sig))
        if fd == '' or float(fd) < DEFAULT_UL_SIGMA * float(uefd):
            photodict[PHOTOMETRY.UPPER_LIMIT] = True
            photodict[PHOTOMETRY.UPPER_LIMIT_SIGMA] = str(sig)
            photodict[PHOTOMETRY.MAGNITUDE] = str(Decimal('23.9') - D25 * (
                dsig * duefd).log10())
            if fd:
                photodict[PHOTOMETRY.E_UPPER_MAGNITUDE] = str(D25 * (
                    (dfd + duefd).log10() - dfd.log10()))
        else:
            photodict[PHOTOMETRY.MAGNITUDE] = str(Decimal('23.9') - D25 *
                                                  dfd.log10())
            photodict[PHOTOMETRY.E_UPPER_MAGNITUDE] = str(D25 * (
                (dfd + duefd).log10() - dfd.log10()))
            photodict[PHOTOMETRY.E_LOWER_MAGNITUDE] = str(D25 * (
                dfd.log10() - (dfd - dlefd).log10()))
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def is_profitable(self, highest_bid, lowest_ask):
        '''
        Returns: True if the spread is profitable, False if it is not.
        '''

        with localcontext() as context:
            context.prec = 8

            lowest_ask = Decimal(lowest_ask)
            highest_bid = Decimal(highest_bid)

            spread = lowest_ask - highest_bid

            return spread > self.threshold(highest_bid)
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def satoshi_to_usd( satoshi ):
    '''
    Pre: satoshi is a Decimal.
    Returns: A Decimal with eight significant decimal places. The value of the satoshi in USD.
    '''
    with localcontext() as context:
        context.prec = 8
        return satoshi * current_price_of_bitcoin()
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def current_price_of_bitcoin():
    '''
    Pre: coinmarketcap's api can be accessed. This will require an internet connection.
    Returns: The price of Bitcoin in USD according to coinmarketcap.com
             The variable will be a Decimal with eight decimal places.
    '''
    with localcontext() as context:
        context.prec = 8
        r = requests.get("https://api.coinmarketcap.com/v1/ticker/bitcoin/")
        return Decimal(r.json()[0]["price_usd"])
项目:ouroboros    作者:pybee    | 项目源码 | 文件源码
def test_decimal_extendedcontext_mismatched_infs_to_nan(self):
        # Test adding Decimal INFs with opposite sign returns NAN.
        inf = Decimal('inf')
        data = [1, 2, inf, 3, -inf, 4]
        with decimal.localcontext(decimal.ExtendedContext):
            self.assertTrue(math.isnan(statistics._sum(data)[1]))
项目:ouroboros    作者:pybee    | 项目源码 | 文件源码
def test_decimal_basiccontext_mismatched_infs_to_nan(self):
        # Test adding Decimal INFs with opposite sign raises InvalidOperation.
        inf = Decimal('inf')
        data = [1, 2, inf, 3, -inf, 4]
        with decimal.localcontext(decimal.BasicContext):
            self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
项目:eth-utils    作者:ethereum    | 项目源码 | 文件源码
def to_wei(number, unit):
    """
    Takes a number of a unit and converts it to wei.
    """
    if unit.lower() not in units:
        raise ValueError(
            "Unknown unit.  Must be one of {0}".format('/'.join(units.keys()))
        )

    if is_integer(number) or is_string(number):
        d_number = decimal.Decimal(value=number)
    elif isinstance(number, float):
        d_number = decimal.Decimal(value=str(number))
    elif isinstance(number, decimal.Decimal):
        d_number = number
    else:
        raise TypeError("Unsupported type.  Must be one of integer, float, or string")

    s_number = str(number)

    if d_number == 0:
        return 0

    unit_value = units[unit.lower()]

    if d_number < 1 and '.' in s_number:
        with localcontext() as ctx:
            multiplier = len(s_number) - s_number.index('.') - 1
            ctx.prec = multiplier
            d_number = decimal.Decimal(value=number, context=ctx) * 10**multiplier
        unit_value /= 10**multiplier

    result_value = d_number * unit_value

    if result_value < MIN_WEI or result_value > MAX_WEI:
        raise ValueError("Resulting wei value must be between 1 and 2**256 - 1")

    return int(result_value)
项目:flask-zhenai-mongo-echarts    作者:Fretice    | 项目源码 | 文件源码
def to_decimal(self):
        """Returns an instance of :class:`decimal.Decimal` for this
        :class:`Decimal128`.
        """
        high = self.__high
        low = self.__low
        sign = 1 if (high & _SIGN) else 0

        if (high & _SNAN) == _SNAN:
            return decimal.Decimal((sign, (), 'N'))
        elif (high & _NAN) == _NAN:
            return decimal.Decimal((sign, (), 'n'))
        elif (high & _INF) == _INF:
            return decimal.Decimal((sign, (0,), 'F'))

        if (high & _EXPONENT_MASK) == _EXPONENT_MASK:
            exponent = ((high & 0x1fffe00000000000) >> 47) - _EXPONENT_BIAS
            return decimal.Decimal((sign, (0,), exponent))
        else:
            exponent = ((high & 0x7fff800000000000) >> 49) - _EXPONENT_BIAS

        arr = bytearray(15)
        mask = 0x00000000000000ff
        for i in range(14, 6, -1):
            arr[i] = (low & mask) >> ((14 - i) << 3)
            mask = mask << 8

        mask = 0x00000000000000ff
        for i in range(6, 0, -1):
            arr[i] = (high & mask) >> ((6 - i) << 3)
            mask = mask << 8

        mask = 0x0001000000000000
        arr[0] = (high & mask) >> 48

        # Have to convert bytearray to bytes for python 2.6.
        digits = [int(digit) for digit in str(_from_bytes(bytes(arr), 'big'))]

        with decimal.localcontext(_DEC128_CTX) as ctx:
            return ctx.create_decimal((sign, digits, exponent))
项目:ethwallet    作者:absortium    | 项目源码 | 文件源码
def truncate(number, places):
    if not isinstance(places, int):
        raise ValueError("Decimal places must be an integer.")
    if places < 1:
        raise ValueError("Decimal places must be at least 1.")
    # If you want to truncate to 0 decimal places, just do int(number).

    with localcontext() as context:
        context.rounding = ROUND_DOWN
        exponent = Decimal(str(math.pow(10, - places)))
        return Decimal(str(number)).quantize(exponent)
项目:kbe_server    作者:xiaohaoppy    | 项目源码 | 文件源码
def test_decimal_mismatched_infs_to_nan(self):
        # Test adding Decimal INFs with opposite sign returns NAN.
        inf = Decimal('inf')
        data = [1, 2, inf, 3, -inf, 4]
        with decimal.localcontext(decimal.ExtendedContext):
            self.assertTrue(math.isnan(statistics._sum(data)))
项目:kbe_server    作者:xiaohaoppy    | 项目源码 | 文件源码
def test_decimal_mismatched_infs_to_nan(self):
        # Test adding Decimal INFs with opposite sign raises InvalidOperation.
        inf = Decimal('inf')
        data = [1, 2, inf, 3, -inf, 4]
        with decimal.localcontext(decimal.BasicContext):
            self.assertRaises(decimal.InvalidOperation, statistics._sum, data)
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def process_order_book(self, highest_bid, lowest_ask):
        '''
        Pre: Traders keep track of their balance / assets and do not attempt a trade when they do not
             have the balance to buy with or the assets to sell.
        '''

        # Financial calculations need accurate decimals
        with localcontext() as context:
            context.prec = 8

            # The spread has to be calculated using the values that the strategy will try to use, not what
            # is already being used.
            highest_bid = Decimal(highest_bid)+self.undercut_market_by
            lowest_ask = Decimal(lowest_ask)-self.undercut_market_by

            if self._spread_size_indicator.is_profitable(highest_bid, lowest_ask):

                # Changing current_position causes the trader to vacillate between buying and selling.
                # Traders will not enter a position when the trader does not have the balance/assets
                # so this causes the Trader to wait until their position is exited before they enter the
                # market again - with the opposite position.

                if self.current_position:
                    self.notify_observers(False, lowest_ask)
                    self.current_position = False
                else:
                    self.notify_observers(True, highest_bid)
                    self.current_position = True
                self._first_time_unprofitable = True

            else:

                # Not profitable = hold default position.
                if self.default_position == DefaultPosition.HOLD:
                    if self._first_time_unprofitable:
                        print("Spread is not profitable. Holding.")
                    self.notify_observers(None, -1) # market_value is irrelevant so it will be set to -1
                else:
                    if self.default_position == DefaultPosition.BUY:
                        if self._first_time_unprofitable:
                            print("Spread is not profitable. Holding major currency.")
                        self.notify_observers(None, lowest_ask)
                    elif self.default_position == DefaultPosition.SELL:
                        if self._first_time_unprofitable:
                            print("Spread is not profitable. Holding minor currency.")
                        self.notify_observers(None, highest_bid)
                    self.current_position = self.default_position
                self._first_time_unprofitable = False
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def __init__(self, options, percentage_to_trade=1, start_by_buying=True, starting_amount=100):
        '''
        Pre: options is an instance of QuadrigaOptions and must have pair and ticker set.
        Post: self.is_test = True until authenticate() is called
        '''

        # Trader is in test mode by default.
        # minimum_trade is the minimum amount of assets that can be sold on a trade.
        Trader.__init__(self, True, options.minimum_trade, options.ticker)

        # Will be set to a number (order ID) when an order is placed.
        self._waiting_for_order_to_fill = None

        # In test mode: Is used to prevent the same transaction from being counted twice.
        self._last_simulation_transaction_check = 0

        # In test mode: tracks how much the trader's order has been filled.
        self._expecting_simulation_balance = 0
        self._expecting_simulation_assets = 0
        self._filled_simulation_balance = 0
        self._filled_simulation_assets = 0

        # Used when aborting to determine if any positions need to be closed.
        self._active_buy_order = False
        self._active_sell_order = False

        self.major_currency = options.major_currency
        self.minor_currency = options.minor_currency
        self.percentage_to_trade = Decimal(percentage_to_trade)
        self.amount_precision = options.amount_precision
        self.price_precision = options.price_precision
        self.start_by_buying = start_by_buying

        with localcontext() as context:
            context.prec = 8

            if self.start_by_buying:
                self.balance = Decimal(starting_amount)
                self.assets = Decimal(0)
            else:
                self.balance = Decimal(0)
                self.assets = Decimal(starting_amount)
            self.post_fee = Decimal(1) - Decimal(options.fee)
项目:cryptocurrency-trader    作者:TobCar    | 项目源码 | 文件源码
def __init__(self, trading_pair, percentage_to_trade=1, start_by_buying=True, starting_amount=1):
        '''
        Post: self.is_test = True until authenticate() is called
        '''

        # Split up the trading pair for currency specific options and for console output.
        self.market_ticker = trading_pair
        split_pair = trading_pair.split("_")
        self.major_currency = split_pair[0]
        self.minor_currency = split_pair[1]

        # Trader is in test mode by default.
        # minimum_trade is the minimum amount of assets that can be sold on a trade.
        Trader.__init__(self, True, minimum_trade_for[self.minor_currency])

        # Will be set to a number (order ID) when an order is placed.
        self._waiting_for_order_to_fill = None

        # In test mode: Is used to prevent the same transaction from being counted twice.
        self._last_simulation_transaction_check = 0

        # In test mode: tracks how much the trader's order has been filled.
        self._expecting_simulation_balance = 0
        self._expecting_simulation_assets = 0
        self._filled_simulation_balance = 0
        self._filled_simulation_assets = 0

        # Needs to be None or the program will crash in simulation mode when it
        # checks if the bot was shut off manually (a live-only feature)
        self.emergency_shutdown_id = None

        # Used when aborting to determine if any positions need to be closed.
        self._active_buy_order = False
        self._active_sell_order = False

        self.percentage_to_trade = Decimal(percentage_to_trade)
        self.amount_precision = 8
        self.price_precision = 8
        self.start_by_buying = start_by_buying

        with localcontext() as context:
            context.prec = 8

            if self.start_by_buying:
                self.balance = Decimal(starting_amount)
                self.assets = Decimal(0)
            else:
                self.balance = Decimal(0)
                self.assets = Decimal(starting_amount)
            self.post_fee = Decimal(1) - cryptopia_fee
项目:flask-zhenai-mongo-echarts    作者:Fretice    | 项目源码 | 文件源码
def _decimal_to_128(value):
    """Converts a decimal.Decimal to BID (high bits, low bits).

    :Parameters:
      - `value`: An instance of decimal.Decimal
    """
    with decimal.localcontext(_DEC128_CTX) as ctx:
        value = ctx.create_decimal(value)

    if value.is_infinite():
        return _NINF if value.is_signed() else _PINF

    sign, digits, exponent = value.as_tuple()

    if value.is_nan():
        if digits:
            raise ValueError("NaN with debug payload is not supported")
        if value.is_snan():
            return _NSNAN if value.is_signed() else _PSNAN
        return _NNAN if value.is_signed() else _PNAN

    significand = int("".join([str(digit) for digit in digits]))
    bit_length = _bit_length(significand)

    high = 0
    low = 0
    for i in range(min(64, bit_length)):
        if significand & (1 << i):
            low |= 1 << i

    for i in range(64, bit_length):
        if significand & (1 << i):
            high |= 1 << (i - 64)

    biased_exponent = exponent + _EXPONENT_BIAS

    if high >> 49 == 1:
        high = high & 0x7fffffffffff
        high |= _EXPONENT_MASK
        high |= (biased_exponent & 0x3fff) << 47
    else:
        high |= biased_exponent << 49

    if sign:
        high |= _SIGN

    return high, low
项目:mathpy    作者:aschleg    | 项目源码 | 文件源码
def binomial_factorial(self):
        r"""
        Implementation of the binomial coefficient computation. Not meant for actual computation
        as the other methods available are more efficient.

        Parameters
        ----------
        n : int
            Number of possibilities
        k : int
            number of unordered outcomes

        Returns
        -------
        float
            The binomial coefficient

        Notes
        -----
        The binomial coefficient equation (in compact form) is defined as:

        .. math::

            \binom{n}{k} = \frac{n!}{k!(n-k)!} \qquad 0 \leq k \leq n

        References
        ----------
        Binomial coefficient. (2017, April 17). In Wikipedia, The Free Encyclopedia.
            From https://en.wikipedia.org/w/index.php?title=Binomial_coefficient&oldid=775905810

        Press, W., Teukolsky, S., Vetterling, W., & Flannery, B. (2007). Numerical recipes (3rd ed.).
            Cambridge: Cambridge University Press.

        Weisstein, Eric W. "Binomial Coefficient." From MathWorld--A Wolfram Web Resource.
            http://mathworld.wolfram.com/BinomialCoefficient.html

        """
        nk = np.minimum(self.n, self.n - self.k)

        if nk >= 100:
            with localcontext() as ctx:
                ctx.prec = 50
                bico = Decimal(factorial(self.n)) / (Decimal(factorial(self.k)) * Decimal(factorial(nk)))
        else:
            bico = float(factorial(self.n)) / float(factorial(self.k) * factorial(nk))

        return bico
项目:mathpy    作者:aschleg    | 项目源码 | 文件源码
def ramanujan(n, prec=100):
    r"""
    Approximates the factorial :math:`n!` given an integer :math:`n` using Ramanujan's formula.
    Ramanujan's formula is just as or more accurate than several other factorial approximation
    formulas.

    Parameters
    ----------
    n
        Integer to approximate factorial
    prec
        Defines level of precision for factorials over 100. Default 100. Optional

    Returns
    -------
    int or Decimal
        Factorial of :math:`n` as approximated by Ramanujan's formula.

    Notes
    -----
    Ramanujan's formula is another factorial approximation method known for its accuracy
    in comparison to other factorial approximation approaches including Stirling's and
    Gosper's approximations. Ramanujan's formula is defined as:

    .. math::

        n! \approx \sqrt{\pi} \left(\frac{n}{e}\right)^n \sqrt[6]{8n^3 + 4n^2 + n + \frac{1}{30}}

    Examples
    --------
    >>> ramanujan(10)
    3628800.3116126074
    >>> ramanujan(5)
    120.00014706585664

    References
    ----------
    Mortici, Cristinel. On Gosper's Formula for the Gamma Function. Valahia University of Targoviste,
        Department of Mathematics. Retrieved from http://files.ele-math.com/articles/jmi-05-53.pdf

    """
    if n != np.floor(n):
        n = np.floor(n)

    if n >= 100:
        with localcontext() as ctx:
            ctx.prec = prec
            f = Decimal(
                np.sqrt(np.pi) * n ** n * np.exp(-n) * (8. * n ** 3. + 4. * n ** 2. + n + 1. / 30.) ** (1. / 6.))
    else:
        f = np.sqrt(np.pi) * n ** n * np.exp(-n) * (8. * n ** 3. + 4. * n ** 2. + n + (1. / 30.)) ** (1. / 6.)

    return f