Работая с числами двойной точности во встроенном ассемблерном коде (GCC, IA-32)

Я только начинаю изучать блок в своем классе информатики, и у меня есть присвоение на раунд значение с плавающей точкой с помощью указанного режима округления. Я попытался реализовать это использование fstcw, fldcw, и frndint. Я изменяю округляющиеся биты управления, вокруг числа, и затем восстанавливаю предыдущие биты управления (требование присвоения).

Текущая нерешенная проблема состоит в том что инструкция fld %1 кажется, загружает неправильное значение в st(0) регистр с плавающей точкой (например, если я вызываю функцию со значением 2,6207, номер-1.9427 (...) электронный 29, загружается в регистр). Это может произойти из-за неправильного употребления gccвстроенный asm(), или что-то еще, но я не уверен, почему это происходит.

Вот то, что я имею:

double roundD (double n, RoundingMode roundingMode)
{
    // control word storage (2 bytes for previous, 2 for current)
    char *cw = malloc(4*sizeof(char));
    char *cw2 = cw + 2;

    asm("fstcw %3;" // store control word in cw
        "mov %3,%4;" // copy control word into cw2
        "and $0xF3FF,%4;" // zero out rounding control bits
        "or %2,%4;" // put new mode into rounding control bits
        "fldcw %5;" // load the modified control word
        "fld %1;" // load n into st(0)
        "frndint;" // round n
        "fstp %0;" // load st(0) back into n
        "fldcw %3;" // load the old control word from cw
        : "=m" (n)
        : "m" (n), "m" (roundingMode),
          "m" (cw), "r" (cw2), "m" (cw2) // mov requires one argument in a register
        );

    free(cw);

    return n;
}

Я ценил бы любые указатели на что случилось с тем кодом, конкретно касающимся fld %1 строка и asm исходные данные/выводы. (Конечно, если можно найти другие проблемы, не стесняйтесь сообщать мне о них также.) Я не хочу, чтобы любой сделал мою домашнюю работу для меня, просто указал на меня в правильном направлении.Спасибо!

5
задан Bill the Lizard 17 December 2012 в 14:22
поделиться

3 ответа

По крайней мере, одна проблема с вашим текущим кодом заключается в том, что он использует версии fld и fstp с плавающей запятой одинарной точности. Если вы замените их на fldl и fstpl, возможно, это сработает.

2
ответ дан 15 December 2019 в 01:00
поделиться

Если вы используете ветвь с именем heroku в качестве «альтернативной главной» ветви (с конфиденциальными данными) и старую главную ветвь без конфиденциальных данных, то вы всегда можете сделать

git merge master

Так что вы можете толкать ветвь heroku в heroku не главную ветвь.

-121--2414480-

У меня нет алгоритма, чтобы дать вам ключевые функции, но вот некоторые вещи, которые могут помочь.

Во-первых, я бы не стал слишком беспокоиться о поиске характерного пикселя для каждого символа, потому что, в среднем, проверка соответствия данного символа заданному образу (5x5) двоичного изображения не должна занимать больше 5-7 проверок, чтобы сказать, что нет совпадения. Почему? Вероятность. Для 7 двоичных пикселей существует 2 * * 7 = 128 различных возможностей. Это означает, что вероятность совпадения символа до 7 пикселей составляет 1/128 < 1%. Просто убедитесь, что вы остановите сравнения, когда обнаружите несоответствие.

Во-вторых, если вы не хотите делать хэш-таблицу, вы можете использовать trie для хранения всех ваших символьных данных. Он будет использовать меньше памяти, и вы будете проверять все символы одновременно. Поиск не будет таким быстрым, как в хэш-таблице, но также не придется преобразовывать в последовательность. В каждом узле дерева может быть не более 2 потомков. Например, если у вас есть два символа 2x2 (назовем их A и B):

A   B
01  00
10  11

У вас будет только один потомок в первом узле - только слева (ветвь 0). Переходим к следующему узлу. Он имеет два потомка, левая (0) ветвь ведёт к остальной части B, а правая (1) ветвь ведёт к остальной части A. Вы получаете картину. Дайте мне знать, если эта часть не ясна.

-121--3653456-

Изменение знака означает, что бит знака (который является наиболее значимым, первым) неверен. Это означает, что указатель% 1 неправильно выровнен. Если у вас есть один байт, он может начать с 0,1,2... но если вы получаете доступ к двум байтам, адрес должен быть 0,2,4.... и в случае double адрес должен быть четным разделяемым на 8: 0,8,16

Поэтому проверьте, является ли адрес, который используется для загрузки значения, разделяемым на 8. Сборка имеет ключевое слово align, гарантирующее правильное выравнивание данных.

0
ответ дан 15 December 2019 в 01:00
поделиться

Вот что у меня есть. Он не тестировался, но, надеюсь, вам будет проще работать с ним. : -)

double
roundd(double n, short mode)
{
    short cw, newcw;

    __asm__("fstcw %w0" : "=m" (cw));
    newcw = cw & 0xf3ff | mode;
    __asm__("fldcw %w0" : : "m" (newcw));
    __asm__("frndint" : "+t" (n));
    __asm__("fldcw %w0" : : "m" (cw));
    return n;
}

Хотя, если вам не требуется использовать сборку для достижения вашего режима округления, подумайте об использовании вместо этого функций из . : -)

2
ответ дан 15 December 2019 в 01:00
поделиться
Другие вопросы по тегам:

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