Натуральный логарифм в Solidity

Тема в разделе "Solidity", создана пользователем Instincted, 16 ноя 2017.

Метки:
  1. Instincted

    Instincted New Member

    Для написания смарт-контракта мне необходима функция натурального логарифма от X, где 1 < X < 10^30.
    Гугл выдаёт только ЭТО и ЭТО. Не могу понять, как использовать предложенные варианты.

    Может кто-нибудь помочь или объяснить, как применить эти советы на практике ?
     
    Последнее редактирование: 20 ноя 2017
  2. Vasay

    Vasay New Member

    Доброго дня! A какая точность нужна?
     
  3. Instincted

    Instincted New Member

    Точность была нужна максимальная. Я уже воспользовался ЭТИМ советом Бутерина и немного усовершенствовал функцию.
    На входе X (>= 1), умноженное на 10 в степени P, и само P (точность). Т.е. чтобы найти натуральный логарифм от 1,5 c точностью 6, например, нужно вызвать nLog(1500000, 6) и разделить потом на 10**6.
    Точностью лучше не злоупотреблять, особенно при больших X, чтобы не переполнились переменные.

    Поправьте, если что-то недоглядел или знаете более простой способ !

    function nLog(uint x, uint p) returns (uint log) {

    uint y;
    uint i;
    uint m = 10**p;
    uint m15 = m * 3 / 2;
    uint n = 40546510810816438197801311546434913657199042346249419761401432414410067124891 / 10**(77 - p);

    while (x >= m15) {
    log = log + n;
    x = x * 2 / 3;
    }

    x = x - m;
    y = x;
    i = 1;

    while (i < 10) {
    log = log + (y / i);
    i = i + 1;
    y = y * x / m;
    log = log - (y / i);
    i = i + 1;
    y = y * x / m;
    }

    return log;
    }
     
    Последнее редактирование: 20 ноя 2017
    Vasay нравится это.
  4. Vasay

    Vasay New Member

    Спасибо за код - довольно хорош в плане потребления газа.

    Но что-то с точностью не совсем то (или я не так вызвал :) )

    Вызываю: nLog(43210000000000, 10);

    Результат: 83712420118 или 8,3712420118

    Близко к правде, но точность 10 не соответствует:
    8,3712420118
    8,3712421359
     
    Instincted нравится это.
  5. Instincted

    Instincted New Member

    Да, действительно. Спасибо за наблюдательность !
    Изменил в последнем цикле 10 на p * 2, точность повысилась, но всегда фактически меньше на пару знаков.
    Т.е. если хочешь точность 10, то следует использовать 10**12. Как-то так :D

    function nLog(uint x, uint p) returns (uint log) {

    uint y;
    uint i;
    uint m = 10**p;
    uint m15 = m * 3 / 2;
    uint n = 40546510810816438197801311546434913657199042346249419761401432414410067124891 / 10**(77 - p);

    while (x >= m15) {
    log = log + n;
    x = x * 2 / 3;
    }

    x = x - m;
    y = x;
    i = 1;

    while (i < p * 2) {
    log = log + (y / i);
    i = i + 1;
    y = y * x / m;
    log = log - (y / i);
    i = i + 1;
    y = y * x / m;
    }

    return log;
    }