2

I am making a simulator, which simulates the method of multiplication of a processor. The thing is first I have to convert the decimal form to binary, each bit of binary representation is stored at separate location in an array. Now the multiplication of two binary numbers, stored in arrays as mentioned above is very complex and also very memory consuming.

because I have to follow this method;

1000

x

1110


   `0000`

  `1000`

 `1000`

`1000`

= 1110000

I know that I can easily do this by multiplying decimals forms together and then convert them to binary but unfortunately that's not required here.

I was thinking if there is a way to store the binary number stored in array as a single integer containing binary no. Or any other easy way for multiplying binary bits stored in array. For Example:

a[0]=1,a[1]=1, .... ,a[32]=0

so I want the integer variable to contain

int x=110....0

Is there a way to do this?

Regards

Alfred
  • 1,543
  • 7
  • 33
  • 45

6 Answers6

9

You can use std::bitset

std::bitset<32> b;

b[0] = 1;
b[1] = 1;
...
John Bandela
  • 2,416
  • 12
  • 19
4

This is a trick that I use that is very convenient for bitmasks to test whether a bit is set or set/reset a bit. I think it might help you quite a bit. (Sometimes I crack myself up.)

template <std::size_t bitIndex, typename T>
bool get_integer_bit(const T num)
{
    // Make sure what was passed in is something ilke an int or long.
    static_assert(std::numeric_limits<T>::is_integer, "Numeral argument must be an integer type.");

    // Don't go out of bounds of the size of the number.
    static_assert(bitIndex < std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed, "bitIndex is out of bounds for type T");
    static_assert(bitIndex >= 0, "bitIndex is out of bounds for type T");

    // Rip the bit out of the number.
    return ((0x1 << bitIndex) & num) != 0;
}

template <std::size_t bitIndex, typename T>
void set_integer_bit(T& num, const bool bitValue)
{
    // Make sure what was passed in is something ilke an int or long.
    static_assert(std::numeric_limits<T>::is_integer, "Numeral argument must be an integer type.");

    // Don't go out of bounds of the size of the number.
    static_assert(bitIndex < std::numeric_limits<T>::digits + std::numeric_limits<T>::is_signed, "bitIndex is out of bounds for type T");
    static_assert(bitIndex >= 0, "bitIndex is out of bounds for type T");

    // Set the bit into the number.
    if (bitValue)
        num |= (0x1 << bitIndex); // Set bit to 1.
    else
        num &= ~(0x1 << bitIndex); // Set bit to 0.
}

And for the usage...

// Test get_integer_bit.
std::cout << set_integer_bit<0>(1);  // Pulls the first (0th) bit out of the integer 1. Result should be 1
std::cout << set_integer_bit<1>(1);  // Pulls the second bit out of the integer 1. Result should be 0
std::cout << set_integer_bit<33>(2); // error C2338: bitIndex is out of bounds for type T

// Test set_integer_bit.
std::cout << get_integer_bit<0>(test); // Should be 0.
set_integer_bit<0>(test, 1); // Set the first (0th) bit to a 1 (true).
std::cout << get_integer_bit<0>(test); // Should be 1, we just set it.

This works for all sorts of sizes of int and has the benefit of complaining at compile time when the bit's index is outside the range of the type provided. If you are looking for a little more than that, though and want to more dynamically access the bits of a type and for that you would need to use a std::bitset

Sean Cline
  • 6,979
  • 1
  • 37
  • 50
  • Why do you put the first argument of the function into a template parameter? It makes the function look as if `get_integer_bit<0>` was operating on a different object than `get_integer_bit<1>`... Template parameters are usually used on classes where you have different underlying data depending on the template value. Say `cv::Vec<3,float>` is a fixed-length vector of float. – Barney Szabolcs Nov 29 '12 at 18:09
  • It is done this way because static_assert requires that its condition be a constant expression. Templates are used for much more than things like containers (and those uses are sometimes almost readable). For this specific use-case see: http://stackoverflow.com/questions/9789913/how-to-tell-static-assert-that-constexpr-function-arguments-are-const Without doing it this way, it would not be possible to provide a compile-time assurance that the bit index does not go out of bounds of the integer. – Sean Cline Nov 29 '12 at 18:16
  • You know what, I think you've pretty much directly answered the entire question, and mine too, +1. :) – Barney Szabolcs Nov 30 '12 at 01:45
  • On the other hand I think you could benefit a lot if you read John Bandela's answer and my extending answer on bitsets. Bitsets should neatly cover both of your functions. – Barney Szabolcs Nov 30 '12 at 03:04
2

@JohnBandela's answer can be completed with the info on how to convert back-and-forth from bitset to long (or string).

You can convert the array-like behaving bitset back-and-forth like this:

#include<bitset>
#include<string>
#include<iostream>
using namespace std;
const int N_DIGITS = 8;

// easy initialization:

// from unsigned long
unsigned long num = 8ul; // == 1000 in binary form
bitset<N_DIGITS> bs1(num);

// from string
string s_num = "1110";
bitset<N_DIGITS> bs2(s_num);

// extraction & printing:

cout << "Binary value of bs1:"  << bs1.to_string() << endl;  // ... "1000"
// ...or just...
cout << "Binary value of bs1:"  << bs1             << endl;
cout << "Decimal value of bs2:" << bs2.to_long()   << endl;  // ... "20"

BITWISE OPERATORS:

Just in case you do not need to bother with basic binary operators, let me give you a list of useful operators. You can do:

// every operator comes in "bs1 &= bs2" and "bs1 & bs2" form. 

bs1 &= bs2; bs1|=bs2; bs1^=bs2; // the last one is xor
~bs1; // negating

size_t n=5;
bs1<<=n; bs1>>=n;     // bit-shifts, n is the amount of bit locations to be shifted.

bs1==bs2;  bs1!=bs2;  // comparisons

This makes multiplication simulation much easier to implement.

Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
1

Depending on what your focus is, you can also use std::string-s (and std::stringstream-s), since there the conversion to/from binary form is quite easy and you can use indexed accessing too.

std::string s; s[0], s[1], etc.

Of course the drawback is you use s[i]=='0' to check whether an index is '0'.

Besides, I would not worry about memory consumption as it is not soo much really and only temporary. Note that std::string is an array of char-s which are 8-bit values, therefore your multiplication (if you have 8 binary digits) takes only 64bytes. That is not much, fits easily into the highest level cache.

Series  Intel Core i5/i7
Level 1 Cache   128 KB <- this is the interesting part for you, should be larger than 6k, ok.
Level 2 Cache   512 KB
Level 3 Cache   3072 KB(i5) 4096 KB(i7)

Source: notebook check

Barney Szabolcs
  • 11,846
  • 12
  • 66
  • 91
  • Actually I have 64bit number which requires one array of 4k memory and some other arrays of 1k memory size – Alfred Nov 29 '12 at 16:45
0

You can convert the decimal number to an array (say, 32 places, simulating a 32 bit number) holding 0s and 1s, then write the multiplication code over two such arrays.

You will need to write two helper function, one for converting the decimal number binary (fill the bits array) and another for converting from bits array to a decimal number.

But as I understand, requirement doesn't involve converting from decimal to binary and vice versa, only binary multiplication, you can simulate a binary number using an integer array simply by:

int binary_1[8] = {0, 0, 0, 1, 0, 0, 1, 1};
int binary_2[8] = {0, 1, 0, 0, 0, 0, 1, 1};
Israel Unterman
  • 13,158
  • 4
  • 28
  • 35
-2

You can use a union to accomplish this.

typedef union { 
    int x;
    struct {
        char b1: 1;
         ....
        char b32: 1;
    }y;
}bits;

This syntax is not quite as nice as your array indexing, but it allows for your simple input into the data type it self.

bits a; a.x = 100;

If how you would use it then you would get to the bits like so.

a.y.b1

In your example say you want to put the binary number 1001 into the type bits you would do the following:

a.x = 0;//clear all the bits
a.y.b1 = 1;//set first bit
a.y.b2 = 0;//clear second bit
a.y.b3 = 0;//clear third bit
a.y.b4 = 1;//set fourth bit

The above is not defined and implementation specific and thus is not reliable. A better method would be to use a function/macro that would set/clear specific bits.

Because the OP's original question wanted a syntax similar to a[0] = 1 the above answer provides a similar syntax, although the behavior is not defined by the standard as brought up in the comments.

sean
  • 3,955
  • 21
  • 28
  • -1: This evokes Undefined Behavior. You cannot assign to one member of a union and read from another. In Standard terminology, only one member of a unions is active at a time. – John Dibling Nov 29 '12 at 16:25
  • What does `char b1:1` does? – Alfred Nov 29 '12 at 16:27
  • @Alfred: It declares a bitfield, 1-bit in size. – John Dibling Nov 29 '12 at 16:28
  • @John Dibling do you have where it states that, I've never seen something that states that and would like to have it for reference. – sean Nov 29 '12 at 16:29
  • @sean: Give me a few minutes. – John Dibling Nov 29 '12 at 16:29
  • 1
    @sean: 9.5/1: says only one member is active at a time, but there's an exception made (9.2/16) for POD types with common initial sequences. In the exception you can examine the common sequences of any shared members. However common initial sequences are defined in 9.2/14&15 as having "the same number of nonstatic data members", which isn't the case here. Your method is very commonly used, but it's Undefined Behavior. – John Dibling Nov 29 '12 at 16:39
  • @John Dibling Thanks for the reference. – sean Nov 29 '12 at 16:41
  • @sean: You're welcome. If you have a copy of the 03 Standard, I suggest you take a close look at these sections (and anywhere else they lead you), as it is all a bit of a rabbit hole. – John Dibling Nov 29 '12 at 16:42