Деление денормализованного числа на 2 - PullRequest
1 голос
/ 01 февраля 2012

Я пишу алгоритм, который делит число с плавающей запятой на 2. В случае уже нормализованных чисел (биты экспоненты> 0), я думаю, что процесс довольно прост. Я думаю, что просто уменьшить значение поля экспоненты на единицу, а затем вставить это значение обратно - правильный подход.

У меня возникают проблемы с тем, как обработать число с плавающей запятой, которое уже денормализовано (все экспонентные биты равны 0). Я понимаю, что такое денормализованное число, и полагаю, что я в целом понимаю, что значит разделить их. Я запускаю алгоритм, который пишу через другую программу, и вот одно сообщение, которое меня смущает:

Передача значения 0x7fffff в функцию возвращает 3fffff. Функция должна возвращать 0x400000.

Я не очень понимаю, что здесь происходит, и почему это должно возвращать указанное значение. Кто-нибудь может попытаться объяснить это и почему он должен возвращать это значение?

Мой первоначальный подход к обработке денормализованного числа состоял в том, чтобы сдвинуть биты дроби вправо на единицу (деление на 2), и это, похоже, не является желательной процедурой.

Вот что у меня есть:

unsigned float_half(unsigned uf) {

  unsigned exp = uf & (0x7F800000);
  unsigned sign = uf & (0x80000000);
  unsigned fract = uf & (0x007FFFFF);
  // Check for NaN or infinity
  if(exp == 0x7F800000) {
    return uf;
  }
  // Check for denormalized numbers
  if(exp == 0x00000000) {
    // Need to do something here, not really sure...

    return sign | exp | fract;
  } 
  // Check for exponent of 1 (going to a denormalized number changes things)
  if(exp == 0x00800000) {
    fract = (0x00FFFFFF & uf) >> 1;
    return fract | sign;
  }

  exp--;
  exp = exp & (0x7F800000);
  return sign | exp | fract;
}

Ответы [ 2 ]

4 голосов
/ 11 мая 2012

То, что функция должна возвращать 0x400000, должно соответствовать режиму округления до четного.Вот моя функция:

unsigned float_half(unsigned uf){
    unsigned sign = uf & (0x80000000);
    unsigned exp = uf >> 23 & 0xff;
    unsigned frac = f & 0x7fffff;

    if(exp == 0xff)
        return uf;
    else if (exp > 1)
        return sign | --exp << 23 | frac;
    else {
        if (exp == 1)
            frac |= 1 << 23;
        if ((frac & 3) == 3)
            frac++;
        frac >>= 1;
        return sign | frac;
    }
}

Другой

unsigned float_half(unsigned uf){
    unsigned sign = uf & (0x80000000);
    unsigned exp_frac = uf & 0x7fffffff;

    if (exp_frac >= 0x7f800000)
        return uf;
    else if (exp_frac > 0x00ffffff)
        return uf + 0xff800000;
    else {
        if ((exp_frac & 3) == 3)
            exp_frac++;
        exp_frac >> 1;
        return sign | exp_frac;
    }
}
2 голосов
/ 01 февраля 2012

Вероятно, вы должны округлить значение в денормализованном случае. Для 0x7fffff вы обрезаете последний бит 1 со сдвигом. Похоже, что вместо этого ожидается округление значения, например, так:

if(exp == 0x00000000) {
  fract = (0x00FFFFFF & uf) >> 1;
  if (0x00000001 & uf)
    fract++;
  return fract | sign;
}

Если вы должны округлить вверх или вниз, это также может зависеть от знака.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...