Multiplication of two 32 bit numbers using only 8 bit numbers - c

I saw this interview question online and can't find a good method other than the usual additive methods.
Any suggestions if this can be done quicker using some bitshift / recursion or something similar ?

Bitshifting would be natural part of a solution.
To multiply a value a by an eight-bit value b, for each 1 bit in b, add up all the values of a multiplied by b with all other bits set to 0. For example, a * 10100001 = a * 10000000 + a * 00100000 + a * 00000001.
Taking this further, suppose we want to multiply 11001011 by 0010000, this is 11001011(bin) << 4(dec). Doing this on an eight-bit value gives you 10110000. You have also lost (8-4)=4 bits from the beginning. Hence you would also want to do 11001011(bin) >> 4(dec) to get 00001100 as a carry into the next "8-bit column" (assuming that we are using 8 columns to represent a 64-bit answer).
Recursion would not really be necessary. All you'd need is a loop through the 4 bytes of the first 32-bit number, with another loop through the 4 bytes of the second number inside, multiplying each pair of bytes together in turn and adding it to your solution.

Related

How do you convert the remainder of a division operation to a fixed point in C?

I understand the concept of fixed point pretty well at this point, but I'm having trouble making a logical jump.
I'm working with M68000 CPUs using gcc with no standard libraries of any sort. Using DIVU/DIVS opcodes, I can obtain the quotient and the remainder. Given a Q16.16 fixed point value stored in an unsigned 32bit memory space, I know I can put the quotient in the upper 16 bits. However, how does one convert the integer remainder into the fractional portion of the fixed point value?
I'm sure this is something simple and I'm just missing it. Any help would be greatly appreciated.
The way to think about it is that fixed point numbers are actually integers hold the value of your number times some fixed multiplier. You want to build you fixed point operations out of the integer operations you have available in your hardware.
So for a 16.16 fixed-point format, your multiplier is 65536 (216), so if you want to do a divide c = a/b, the numbers (integers) you have to work with are actually a' = a * 65536 and b' = b * 65536 and you want to find c' = c * 65536. So substituting into the desired c = a/b, you have
c'/65536 = (a'/65536) / (b'/65536) = a'/b'
c' = 65536 * a' / b'
So you actually want to first (integer) mulitply the fixed-point value of a by 65536 (left shift by 16), then do an integer divide by the fixed point value of b, and that will give you the fixed point value of c. The issue is that the first multiply will almost certainly overflow 32 bits, so you need a 64 bit (actually only 48 bit) intermediate. So if you're using a 68020+ with a 64/32 DIVS.L instruction (divides a 64 bit value in a pair of registers by a 32 bit value), you're fine. You don't need the remainder at all.
If you're using a pure 68000 that doesn't have the wide divide, you'll need to do 16-bit long division on the values (where you use 16 bit numbers as "digits", so you're dividing a 3-"digit" number by a 2-"digit" one)

Subtracting 1 from 0 in 8 bit binary

I have 8 bit int zero = 0b00000000; and 8 bit int one = 0b00000001;
according to binary arithmetic rule,
0 - 1 = 1 (borrow 1 from next significant bit).
So if I have:
int s = zero - one;
s = -1;
-1 = 0b1111111;
where all those 1s are coming from? There are nothing to borrow since all bits are 0 in zero variable.
This is a great question and has to do with how computers represent integer values.
If you’re writing out a negative number in base ten, you just write out the regular number and then prefix it with a minus sign. But if you’re working inside a computer where everything needs to either be a zero or a one, you don’t have any minus signs. The question then comes up of how you then choose to represent negative values.
One popular way of doing this is to use signed two’s complement form. The way this works is that you write the number using ones and zeros, except that the meaning of those ones and zeros differs from “standard” binary in how they’re interpreted. Specifically, if you have a signed 8-bit number, the lower seven bits have their standard meaning as 20, 21, 22, etc. However, the meaning of the most significant bit is changed: instead of representing 27, it represents the value -27.
So let’s look at the number 0b11111111. This would be interpreted as
-27 + 26 + 25 + 24 + 23 + 22 + 21 + 20
= -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1
= -1
which is why this collection of bits represents -1.
There’s another way to interpret what’s going on here. Given that our integer only has eight bits to work with, we know that there’s no way to represent all possible integers. If you pick any 257 integer values, given that there are only 256 possible bit patterns, there’s no way to uniquely represent all these numbers.
To address this, we could alternatively say that we’re going to have our integer values represent not the true value of the integer, but the value of that integer modulo 256. All of the values we’ll store will be between 0 and 255, inclusive.
In that case, what is 0 - 1? It’s -1, but if we take that value mod 256 and force it to be nonnegative, then we get back that -1 = 255 (mod 256). And how would you write 255 in binary? It’s 0b11111111.
There’s a ton of other cool stuff to learn here if you’re interested, so I’d recommend reading up on signed and unsigned two’s-complement numbers.
As some exercises: what would -4 look like in this format? How about -9?
These aren't the only ways you can represent numbers in a computer, but they're probably the most popular. Some older computers used the balanced ternary number system (notably the Setun machine). There's also the one's complement format, which isn't super popular these days.
Zero minus one must give some number such that if you add one to it, you get zero. The only number you can add one to and get zero is the one represented in binary as all 1's. So that's what you get.
So long as you use any valid form of arithmetic, you get the same results. If there are eight cars and someone takes away three cars, the value you get for how many case are left should be five, regardless of whether you do the math with binary, decimal, or any other kind of representation.
So any valid system of representation that supports the operations you are using with their normal meanings must produce the same result. When you take the representation for zero and perform the subtraction operation using the representation for one, you must get the representation such that when you add one to it, you get the representation for zero. Otherwise, the result is just wrong based on the definitions of addition, subtraction, zero, one, and so on.

Bit arithmetic in C

Say we have 11101111 stored in the address address, how would I add the first 4 bits to the last 4 bits?
My prof showed us we can do this (*address)/16 + (*address)%16 but I don't understand why it works. Can someone explain where the division and modulo with 16 come from?
#VanGo, See to perform operation on bits, you have to learn bitwise operator first.
I am explaining your problem here.
11101111 (is in binary form) and is equivalent to 239 (in decimal).
Now you have to add 1110 in 1111. In order to get these two pair of 4 bits from 11101111, you have to perform bitwise operation on 11101111.
To get higher 4 bits, shift 11101111 four times from left to right.
*address >> 4 :- is equal to *address/16
internally compiler convert *address>>4 into (*address)/(2 pow 4).
To get lower 4 bits, either perform (*address)&0x0f or (*address)%16. Both operation will clear all bits except lower 4 bits.
printf(".....%d\n",(((*address)>>4) + ((*address)&0x0f)));
hope it helps you.

loop over 2^n states of n bits in C with n > 32

I'd like to have a loop in C over all possible 2^n states of n bits. For example if n=4 I'd like to loop over 0000, 0001, 0010, 0011, ..., 1110, 1111. The bits can be represented in any way, for example an integer array of length n with values 0 or 1, or a character array of length n with values "0" or "1", etc, it doesn't really matter.
For smallish n what I do is calculate x=2^n using integer arithmetic (both n and x are integers), then
for(i=0;i<x;i++) {
bits = convert_integer_to_bits( i );
work_on_bits( bits );
}
Here 'bits' is in the given representation of bits, what was useful so far is an integer array of length n with values 0 or 1 (but can be anything else).
If n>32 this approach obviously doesn't work even with longs.
How would I work with n>32?
Specifically, do I really need to evaluate 2^n, or is there a tricky way of writing the loop which does not refer to the actual value of 2^n but nevertheless iterates 2^n times?
For n > 32 use unsigned long long. This will work for n up to 64. Still for values even close to 50 you will have to wait long time until the cycle finishes.
It's not clear why you say that if n>32, it obviously won't work. Is your concern the width of bits, or is your concern the run time?
If you're concerned about number width, investigate a big math library such as http://gmplib.org/.
If you're concerned about run time... you won't live long enough for your loop to complete if the width is large enough, so get a different hobby ;) Seriously... figure out the rough run time of one iteration through your loop and multiply that by 4 billion, divide by 20 years, and you'll have an estimate of the number of generations of your ancestors that will need to wait for the answer.

Printing multiple integers as one arbitrarily long decimal string

Say I have 16 64-bit unsigned integers. I have been careful to feed the carry as appropriate between them when performing operations. Could I feed them into a method to convert all of them into a single string of decimal digits, as though it was one 1024-bit binary number? In other words, is it possible to make a method that will work for an arbitrary number of integers that represent one larger integer?
I imagine that it would be more difficult for signed integers, as there is the most significant bit to deal with. I suppose it would be that the most significant integer would be the signed integer, and the rest would be unsigned, to represent the remaining 'parts' of the number.
(This is semi-related to another question.)
You could use the double dabble algorithm, which circumvents the need for multi-precision multiplication and division. In fact, the Wikipedia page contains a C implementation for this algorithm.
This is a bit unclear.
Of course, a function such as
void print_1024bit(uint64_t digits[]);
could be written to do this. But if you mean if any of the standard library's printf()-family of functions can do this, then I think the answer is no.
As you probably saw in the other question, the core of converting a binary number into a different base b is made of two operations:
Modulo b, to figure out the current least significant digit
Division by b, to remove that digit once it's been generated
When applied until the number is 0, this generates all the digits in reverse order.
So, you need to implement "modulo 10" and "divide by 10" for your 1024-bit number.
For instance, consider the number decimal 4711, which we want to convert to octal just for this example:
4711 % 8 is 7, so the right-most digit is 7
4711 / 8 is 588
588 % 8 is 4, the next digit is 4
588 / 8 is 73
73 % 8 is 1
73 / 8 is 9
9 % 8 is 1
8 / 8 is 1
1 % 8 is 1
1 / 8 is 0, we're done.
So, reading the bold digits from the bottom and up towards the right-most digits, we conclude that 471110 = 111478. You can use a calculator to verify this, or just trust me. :)
It's possible, of course, but not terribly straight-forward.
Rather than reinventing the wheel, how about reusing a library?
The GNU Multi Precision Arithmetic Library is one such possibility. I've not needed such things myself, but it seems to fit your bill.

Resources