Как и другие списки (но не Scheme), Emacs Lisp имеет отдельные пространства имен для переменных и функций (т.е. это 'Lisp 2 ', а не 'Lisp 1 ] '; см. Технические вопросы разделения в функциональных ячейках и ячейках значений для определения происхождения и значения этих терминов).
Вам нужно будет использовать funcall
или apply
для вызова лямбда-функции (или другой функции), которая хранится в переменной.
(cond (test-1 (funcall do-work 'a 'b 'c))
(test-2 (funcall do-work 'i 'j 'k))
Используйте funcall
, если вы всегда будете отправлять одинаковое количество аргументов. Используйте apply
, если вам нужно отправить переменное число аргументов.
Внутренний механизм состоит в том, что каждый символ имеет несколько «ячеек» . Какая ячейка используется, зависит от , где символ находится в оценочной форме . Когда символ является первым элементом оцененной формы, используется его ячейка «функции» . В любой другой позиции используется ее ячейка «значения» . В вашем коде do-work
имеет функцию в своей ячейке значения. Для доступа к нему в качестве функции вы используете funcall
или apply
. Если бы он был в ячейке функции, вы могли бы вызвать его напрямую, используя его имя в качестве машины оценочной формы. Вы можете сделать это с помощью flet
или labels
из пакета cl .
Вместо этого вы можете использовать этот метод:
int targetlevel = 0;
while (index >>= 1) ++targetlevel;
Примечание: это изменит индекс. Если он вам нужен без изменений, создайте другое временное int.
Угловой случай - когда index равен 0. Вероятно, вам следует проверить его отдельно и выбросить исключение или вернуть ошибку, если index == 0.
Насколько глубоко вы проецируете свое дерево? Вы можете установить диапазон, скажем ... +/- 0,00000001 для числа, чтобы заставить его принимать целочисленное значение.
На самом деле я не уверен, что вы наберете число, подобное 1.99999999, потому что ваш log2 не должен потерять точность при вычислении значений 2 ^ n (поскольку числа с плавающей запятой округляются до ближайшей степени 2).
У меня никогда не было проблем с точностью с плавающей запятой в формуле, которую вы используете (и быстрой проверкой чисел от 1 до 2 31 - 1 найдено ошибок нет), но если вы беспокоитесь, вы можете вместо этого использовать эту функцию, которая возвращает те же результаты и примерно на 66% быстрее в моих тестах:
int HighestBit(int i){
if(i == 0)
return -1;
int bit = 31;
if((i & 0xFFFFFF00) == 0){
i <<= 24;
bit = 7;
}else if((i & 0xFFFF0000) == 0){
i <<= 16;
bit = 15;
}else if((i & 0xFF000000) == 0){
i <<= 8;
bit = 23;
}
if((i & 0xF0000000) == 0){
i <<= 4;
bit -= 4;
}
while((i & 0x80000000) == 0){
i <<= 1;
bit--;
}
return bit;
}
Если вам просто нужна операция быстрого целочисленного журнала 2 , следующая функция mylog2 ()
сделает это, не беспокоясь о числах с плавающей запятой. точность:
#include <limits.h>
static unsigned int mylog2 (unsigned int val) {
if (val == 0) return UINT_MAX;
if (val == 1) return 0;
unsigned int ret = 0;
while (val > 1) {
val >>= 1;
ret++;
}
return ret;
}
#include <stdio.h>
int main (void) {
for (unsigned int i = 0; i < 20; i++)
printf ("%u -> %u\n", i, mylog2(i));
putchar ('\n');
for (unsigned int i = 0; i < 10; i++)
printf ("%u -> %u\n", i+UINT_MAX-9, mylog2(i+UINT_MAX-9));
return 0;
}
В приведенном выше коде также есть небольшая тестовая программа, поэтому вы можете проверить поведение:
0 -> 4294967295
1 -> 0
2 -> 1
3 -> 1
4 -> 2
5 -> 2
6 -> 2
7 -> 2
8 -> 3
9 -> 3
10 -> 3
11 -> 3
12 -> 3
13 -> 3
14 -> 3
15 -> 3
16 -> 4
17 -> 4
18 -> 4
19 -> 4
4294967286 -> 31
4294967287 -> 31
4294967288 -> 31
4294967289 -> 31
4294967290 -> 31
4294967291 -> 31
4294967292 -> 31
4294967293 -> 31
4294967294 -> 31
4294967295 -> 31
Он вернет UINT_MAX
для входного значения 0 в качестве указания на неопределенный результат, так что что-то, что вы должны проверить (ни одно допустимое целое число без знака не будет иметь такой высокий логарифм).
Между прочим, есть несколько безумно быстрых хаков, чтобы сделать именно это (найти самый высокий бит, установленный в дополнительном числе до 2), доступных из здесь . Я бы не советовал использовать их, если скорость не важна (я сам предпочитаю удобочитаемость), но вы должны знать, что они существуют.
Если вы используете новейшую платформу x86 или x86-64 (а вы, вероятно, так и есть), используйте инструкцию bsr
, которая вернет позицию самого высокого набора бит в целое число без знака. Оказывается, это то же самое, что и log2 (). Вот короткая функция C или C ++, которая вызывает bsr
с использованием встроенного ASM:
#include <stdint.h>
static inline uint32_t log2(const uint32_t x) {
uint32_t y;
asm ( "\tbsr %1, %0\n"
: "=r"(y)
: "r" (x)
);
return y;
}
Это не стандартно и не обязательно переносимо, но в целом работает. Я не знаю, насколько это эффективно.
Преобразуйте целочисленный индекс в число с плавающей запятой достаточной точности. Представление будет точным, если точность достаточна.
Найдите представление чисел с плавающей запятой IEEE,