2016-05-10 7 views
3

Я пытаюсь изменить один бит в два раза, так что, к примеру:Изменение одного бита в двойном

Double х: -1.500912597 что:

Binary: 10111111 11111000 00000011 10111100 11101101 01100100 01001111 10010011

Изменение один бит в лежащий в основе двоичного кода (например, бит 16), так что:

Binary: 10111111 11111001 00000011 10111100 11101101 01100100 01001111 10010011

DOUBLE X: -1.563412596999999903

Есть ли код на C++, который я могу использовать для этого?

+0

Да, есть некоторый код C++, которые могут быть использованы для этого. Ключевое слово Google - «объединение». –

+0

Научитесь использовать [побитовые операции в C/C++] (http://www.cprogramming.com/tutorial/bitwise_operators.html) – Jens

+3

@SamVarshavchik Не в стандарте C++ –

ответ

1
#include <ieee754.h> 

ieee754_double d = {-1.500912597}; 
d.ieee.mantissa1 |= 1u << 16; // set bit 16 of mantissa 
double x = d.d; 

Заголовок ieee754.h на моей системе происходит от glibc-headers пакета.

+2

'ieee754.h' не является частью ISO C++, было бы неплохо добавить к вашему ответу объяснение того, какие пакеты и т. Д. Необходимы для использования вашего кода. –

+0

Хотя ieee754.h не является частью ISO C++, я думаю, что доступ к этому путь более чист, чем альтернативы. –

+0

Можно ли использовать пакет 'glibc-headers' в Visual Studio? Я пытался посмотреть, как, но правильно ли я говорю, что они не будут работать вместе? – Milan

1

Единственный переносной способ - использовать memcpy (да, я знаю, о чем вы думаете, и нет, это не является неэффективным).

Обратите внимание, что это решение не учитывает порядок байтов. Тебе нужно будет обслуживать это, чтобы быть строго переносимым.

#include <cstdlib> 
#include <cstring> 
#include <utility> 
#include <iostream> 

// only compile this function if Integer is the same size as a double 
template<class Integer, std::enable_if_t<sizeof(Integer) == sizeof(double)>* = nullptr> 
double or_bits(double input, Integer bits) 
{ 
    Integer copy; 

    // convert the double to a bit representation in the integer 
    std::memcpy(&copy, &input, sizeof(input)); 
    // perform the bitwise op 
    copy |= bits; 
    // convert the bits back to a double 
    std::memcpy(&input, &copy, sizeof(copy)); 
    // return the double 
    return input; 
} 

int main() 
{ 
    double d = 1.0; 
    d = or_bits(d, 0x10ul); 
    std::cout << d << std::endl; 
} 

выход сборки на gcc5.3:

double or_bits<unsigned long, (void*)0>(double, unsigned long): 
    movq %xmm0, %rax 
    orq  %rdi, %rax 
    movq %rax, -8(%rsp) 
    movsd -8(%rsp), %xmm0 
    ret 
+0

Насколько я знаю, 'memcpy' - не единственный переносной способ. Вручную изменяются биты с использованием символа 'char *'. – HolyBlackCat

+0

@HolyBlackCat - это справедливая точка. –

+0

Я буквально скопировал и вставил ваш код (в VS2015), но я получаю несколько ошибок: http://pastebin.com/YhkSQzq2. Это потому, что я использую другой компилятор? – Milan

0

Есть бесконечные возможности для манипуляции с битами. Поэтому вы должны практиковать; но я приведу вам несколько примеров.

Ниже код будет "установить" бит только 3 х (где бит 0 является наименее значащий бит):

#define SET_BIT3 (0x08) 
x |= SET_BIT3; 

Ниже код будет "сбросить" только бит 3:

#define RESET_BIT3 (0xFFFFFFFFFFFFFFF7) 
x &= RESET_BIT3; 

Еще одна вещь, которую вы могли бы сделать, это объединение, как это:

typedef union 
{ 
    struct 
    { 
     unsigned BIT0:1; 
     unsigned BIT1:1; 
     unsigned BIT2:1; 
     unsigned BIT3:1; 
     unsigned BIT4:1; 
     unsigned BIT5:1; 
     unsigned BIT6:1; 
     unsigned BIT7:1; 
     unsigned BIT8:1; 
     unsigned BIT9:1; 
     unsigned BIT10:1; 
     unsigned BIT11:1; 
     unsigned BIT12:1; 
     unsigned BIT13:1; 
     unsigned BIT14:1; 
     unsigned BIT15:1; 
    }; 
    struct 
    { 
     unsigned BYTE0:8; 
     unsigned BYTE1:8; 
    }; 
    struct 
    { 
     unsigned ALL:16; 
    }; 
}two_bytes; 

Что вы можете сделать с ним это:

two_bytes var; 

var.ALL = 0; // clear all bits 
var.BYTE1 = 0xFF; // make all bits of most significant byte 1 
var.BIT7 = 1; // set only bit 7 

Или вы можете снова включить в операторы поразрядными:

#define SET_BIT3 (0x08) 
var.ALL |= SET_BIT3; 
+0

На многих платформах 'unsigned' имеет ширину 4 байта. Используйте переносимый тип , например 'uint16_t'. –

+4

Объединение - это неопределенное поведение в стандартном C++. Битлэйт-макет определяется реализацией, поэтому это также затруднит понимание того, что вы получили правильный байт. –

+0

@MaximEgorushkin Да, но это всего лишь примерный тип , а иногда и на встроенных платформах, я предпочитаю гибкость переносимости. Это распространенный способ, которым производители определяют регистры микроконтроллера в своем коде. – etugcey

Смежные вопросы