Size: a a a

Compiler Development

2020 May 19

V\

Vadim třetí \λ.λ in Compiler Development
MaxGraey
Ктонибудь знает эффективный алгоритм вычисления целочисленного логарифма с произвольным основанием? Требования достаточно необычные - нельзя использовать плавающую арифметику ну алготим должен быть как можно более бысртым и корректно отрабатывать всегда. Например первое что приходит в голову это:

ilogb(n: u64, base: i32) {
 t = u64(base)
 e = 1
 while (t <= n) {
   t *= base
   e += 1
 }
 return e
}

Но у него есть проблема с переполнением например ilogb(u64(-1), 2) провалиться в бесконечный цикл из-за переполнения после умножения. Если добавить проверку на переполнение то это + 1 деление, +1 проверка условия в цикле, все это выходит очень недешево для base = 2, 3 …
Да base находиться в промежутке [2, 36].

Все это нужно для подсчета колличества цифр необходимых для представления в виде строки.
Я встречал подход еще с бинарным поиском, но он требует возведения в степень и все это в цикле, в общем тоже весьма сомнительное удовольствие
Не помню есть ли там именно это, но попробуй fxtbook листануть
источник

M

MaxGraey in Compiler Development
Vadim třetí \λ.λ
Не помню есть ли там именно это, но попробуй fxtbook листануть
Спасибо, гляну
источник

AD

Artyom Drozdov in Compiler Development
MaxGraey
С проверкой на переполнением можно много чего нагородить, но это лишь сильно усложнит код. Может кто то знает более хитрый прием
if (n > max[base]) в начале так себе усложнение)
источник

AD

Artyom Drozdov in Compiler Development
Для небольших значений base можно сначала более высокими степенями оперировать
источник

AD

Artyom Drozdov in Compiler Development
Но кажется 32 операции в худшем случае не так уж и плохо?
источник

AD

Artyom Drozdov in Compiler Development
Можно сделать 16 если в таблицу прописать "среднее" значение
источник

MM

Mikhail Maltsev in Compiler Development
> Если добавить проверку на переполнение то это + 1 деление
А всякие __builtin_umulll_overflow недоступны?
источник

AD

Artyom Drozdov in Compiler Development
Mikhail Maltsev
> Если добавить проверку на переполнение то это + 1 деление
А всякие __builtin_umulll_overflow недоступны?
да просто проверку можно делать не делением, а сравнить с предпосчитанным значением (до цикла)
источник

M

MaxGraey in Compiler Development
Artyom Drozdov
Но кажется 32 операции в худшем случае не так уж и плохо?
Для radix=2 и 64-bit когда все биты установлены это 64 умножения и сложения + 64 деления (если делать проверку на переполнение)
источник

M

MaxGraey in Compiler Development
Mikhail Maltsev
> Если добавить проверку на переполнение то это + 1 деление
А всякие __builtin_umulll_overflow недоступны?
К сожалению нет
источник

MM

Mikhail Maltsev in Compiler Development
Артем прав, деление для проверки не нужно
источник

AD

Artyom Drozdov in Compiler Development
MaxGraey
Для radix=2 и 64-bit когда все биты установлены это 64 умножения и сложения + 64 деления (если делать проверку на переполнение)
проверка на переполнение может быть сделана одним сравнением (но наверное всё-таки в цикле, да), т.к. ты можешь заранее записать себе в таблицу, после какого числа она произайдет
источник

M

MaxGraey in Compiler Development
Artyom Drozdov
да просто проверку можно делать не делением, а сравнить с предпосчитанным значением (до цикла)
проверку можно делать и так clz(a) + clz(b) < 63 (гарантированное переполнение для a * b).
источник

MM

Mikhail Maltsev in Compiler Development
В смысле? clz(1)+clz(1) >= 63 => 1*1 переполнение?
источник

M

MaxGraey in Compiler Development
MaxGraey
проверку можно делать и так clz(a) + clz(b) < 63 (гарантированное переполнение для a * b).
Но там есть нюанс - для 62 и 61 может быть тоже перепонение и там целая эпопея для этого определения)
источник

AD

Artyom Drozdov in Compiler Development
MaxGraey
Но там есть нюанс - для 62 и 61 может быть тоже перепонение и там целая эпопея для этого определения)
мне кажется, ты усложняешь) в память лезть настолько сильно не хочется?)
источник

M

MaxGraey in Compiler Development
Mikhail Maltsev
В смысле? clz(1)+clz(1) >= 63 => 1*1 переполнение?
сорри, не в ту сторону знак поставил
источник

AD

Artyom Drozdov in Compiler Development
Artyom Drozdov
проверка на переполнение может быть сделана одним сравнением (но наверное всё-таки в цикле, да), т.к. ты можешь заранее записать себе в таблицу, после какого числа она произайдет
так же ты можешь записать в таблицу значение a для каждого b, после которого logB(a) превышает max(logB(a)) / 2, и начинать с него, тогда сокращаешь время перебора вдвое
источник

AD

Artyom Drozdov in Compiler Development
Artyom Drozdov
так же ты можешь записать в таблицу значение a для каждого b, после которого logB(a) превышает max(logB(a)) / 2, и начинать с него, тогда сокращаешь время перебора вдвое
данную процедуру можно повторить еще несколько раз, в соответствующее количество раз уменьшить время перебора
источник

MM

Mikhail Maltsev in Compiler Development
> сорри, не в ту сторону знак поставил
Но это не необходимый критерий. Т.е. переполнения может и не быть
источник