Переведите int в IEEE 754, извлеките показатель и добавьте 1 к показателю

#c

#c

Вопрос:

Проблема

Мне нужно умножить число без использования оператора * or или других библиотек, только двоичную логику

Чтобы умножить число на два, используя норму IEEE, вы добавляете единицу к показателю степени, например:

12 = 1 10000010 100000(...)

Итак, показатель равен: 10000010 (130)

Если я хочу умножить его на 2, я просто добавляю к нему 1, и оно становится 10000011 (131).

Вопрос

Если я получу значение с плавающей точкой, как мне преобразовать его в двоичный файл, а затем в норму IEEE? Пример: 8.0 = 1000.0 в IEEE мне нужно, чтобы в левой части было только одно число, поэтому 1.000 * 2^3 . Тогда как мне добавить единицу, чтобы умножить ее на 2?

Мне нужно получить значение с плавающей точкой, т. Е. 6.5

Преобразуем его в двоичный 110.1

Затем в IEEE 754 0 10000001 101000(...)

Извлеките показатель степени 10000001

Добавьте к нему единицу 10000010

Верните его в IEEE 754 0 10000010 101000(...)

Затем вернитесь к значению float 13

Комментарии:

1. Зачем вам нужно умножать число на два без использования оператора умножения? Это какая-то проблема?

2. Вы могли бы просто добавить его к самому себе, если вам нужно умножать без использования * .

3. Используйте объединение с int и float, добавьте 1<<23 к int, затем получите значение float.

4. Поэтому используйте повторяющиеся добавления:D

5. Вы знаете, что a a == a * 2

Ответ №1:

Учитывая, что известно, что реализация C использует базовый 32-разрядный двоичный код IEEE-754 с плавающей запятой для своего float типа, следующий код показывает, как разделить биты, представляющие a float , настроить показатель степени и повторно собрать биты. Обрабатываются только простые умножения, включающие обычные числа.

 #include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>


int main(void)
{
    float f = 6.125;

    //  Copy the bits that represent the float f into a 32-bit integer.
    uint32_t u;
    assert(sizeof f == sizeof u);
    memcpy(amp;u, amp;f, sizeof u);

    //  Extract the sign, exponent, and significand fields.
    uint32_t sign        = u >> 31;
    uint32_t exponent    = (u >> 23) amp; 0xff;
    uint32_t significand = u amp; 0x7fffff;

    //  Assert the exponent field is in the normal range and will remain so.
    assert(0 < exponent amp;amp; exponent < 254);

    //  Increment the exponent.
      exponent;

    //  Reassemble the bits and copy them back into f.
    u = sign << 31 | exponent << 23 | significand;
    memcpy(amp;f, amp;u, sizeof f);

    //  Display the result.
    printf("%gn", f);
}
  

Комментарии:

1. Эй, отличный ответ, я почерпнул из него хорошую идею, но я не могу использовать другие библиотеки для решения этой проблемы. Только <stdio.h>

Ответ №2:

Возможно, это не совсем то, что вы ищете, но C имеет библиотечную функцию ldexp , которая делает именно то, что вам нужно:

 double x = 6.5;
x = ldexp(x, 1); // now x is 13
  

Ответ №3:

Возможно, объединения — это тот инструмент, который вам нужен.

     #include<iostream>

    union fb {
        float f;
        struct b_s {
            unsigned int sign :1;
            unsigned int mant :22;
            unsigned int exp :8;
        } b;

    };

    fb num;

    int main() {
        num.f = 3.1415;
        num.b.exp  ;
        std::cout << num.f << std::endl;
        return 0;
    }
  

Комментарии:

1. Здесь не используйте битовые поля. Расположение битового поля не определено в соответствии со стандартом C : «Реализация может выделить любой адресуемый блок памяти, достаточно большой, чтобы вместить битовое поле. Если остается достаточно места, битовое поле, которое непосредственно следует за другим битовым полем в структуре, должно быть упаковано в соседние биты того же блока. Если остается недостаточно места, переносится ли битовое поле, которое не помещается, в следующий блок или перекрывает соседние блоки, определяется реализацией.

2. (продолжение) Порядок распределения битовых полей внутри единицы (от старшего порядка к младшему или от младшего порядка к старшему порядку) определяется реализацией . Выравнивание адресуемой единицы хранения не указано .» Битовые поля ужасно непереносимы, и вы просто не можете с какой-либо уверенностью утверждать, что ваше sign битовое поле находится где-либо рядом с фактическим битом знака значения с плавающей запятой f .

3. Это давнее злоупотребление объединениями и имеет неопределенное поведение.

4. В комментариях к коленному рефлексу упущены важные факты о том, что поле significand имеет неправильный размер (должно быть 23, а не 22) и поля расположены не по порядку (должно быть sign-exponent-significand или наоборот, в зависимости). Код напечатал только 6.283, потому что слишком короткое поле significand компенсировало неправильное расположение поля sign, оставляя показатель степени в нужном месте.

5. @LightnessRacesinOrbit: Стандарт C определяет доступ к объединяющему элементу, отличному от последнего, записанного для переосмысления байтов.