Есть ли эффективный способ вычисления экспоненциальности дробного базиса и дробного показателя?

Во-первых, не такой вопрос, как this (что отлично). Мне нужно, чтобы показатель был дробным. Что-то вроде 2.5 ^ 0.75

6 голосов | спросил ZMitton 6 J0000006Europe/Moscow 2018, 00:19:36

1 ответ


2

Код хорошего решения:

function power(uint256 _baseN, uint256 _baseD, uint32 _expN, uint32 _expD) internal view returns (uint256, uint8) {
    assert(_baseN < MAX_NUM);

    uint256 baseLog;
    uint256 base = _baseN * FIXED_1 / _baseD;
    if (base < OPT_LOG_MAX_VAL) {
        baseLog = optimalLog(base);
    }
    else {
        baseLog = generalLog(base);
    }

    uint256 baseLogTimesExp = baseLog * _expN / _expD;
    if (baseLogTimesExp < OPT_EXP_MAX_VAL) {
        return (optimalExp(baseLogTimesExp), MAX_PRECISION);
    }
    else {
        uint8 precision = findPositionInMaxExpArray(baseLogTimesExp);
        return (generalExp(baseLogTimesExp >> (MAX_PRECISION - precision), precision), precision);
    }
}

Полный рабочий код: https: //github.com/Muhammad-Altabba/solidity-toolbox/blob/master/contracts/FractionalExponents.sol

Некоторое объяснение

Число с плавающей запятой x может быть представлено в двух числах: a/b

 if x = a/b and y = c/d, then x ^ y = (a/b) ^ (c/d)

Проблема

Проблема в том, что если код написан как (a/b) ^ (c/d), точность результата будет беспорядочна. Потому что разделение a/b и c/d будет разбить плавающую точку.

В другой попытке выражение (a/b) ^ (c/d) может быть оценено как a ^ (c/d) / b ^ (c/d) или (a^c + a^(1/d)) / (b^c + b^(1/d)). Проблема заключается в том, что питание a до c или даже c/d может легко переполнить uint256! Хотя конечное итоговое значение может быть небольшим uint8. (это объясняется здесь )

Решение

Существует приблизительное значение для x ^ y, как показано ниже:

x ^ y  = e ^ (log(x) * y)

Фактически, метод выше зависит от этого уравнения для вычисления энергетической функции. Как следует:

(_baseN / _baseD) ^ (_expN /_expD) = e ^ (log(base) * exp)

Где base = _baseN / _baseD (обратите внимание, что FIXEX_1, который используется в коде, используется только для сдвига числа слева, чтобы обеспечить лучшая точность разделения. И exp = _expN /_expD.

Ключевым моментом здесь является вычисление log(base) * exp перед включением питания e, предотвратит переполнение по сравнению с ранней обсуждаемой формулой, может легко произвести переполнение: a ^ (c/d) / b ^ (c/d) или (a^c + a^(1/d)) / (b^c + b^(1/d))

Однако для optimalLog vs. generalLog и optimalExp vs. generalExp, что используется в предоставленном коде, они предназначены для вычисления кода log и e ^ либо в оптимальном, либо приближенном вычислении.


Спасибо leonprou за его ценные замечания по этому вопросу.

ответил Muhammad Altabba 17 J0000006Europe/Moscow 2018, 06:03:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132