In C multiplication overflow is ignored. If one multiplies two 32bit numbers, and the result is larger than 32bits the upper bits go into the bit bucket. As long as the result will fit into 32bits, nothing is lost. If the result will be larger than 32bits, one must use 64bit data types. However, as of 2011 the C standard has no integer data types larger than 64bit. So if larger numbers are desired one either has to use floatingpoint, or make their own multiply. At work this month I ran into a problem where I needed to multiply two 64bit numbers that would overflow a 64bit result. After the work day was complete, I wrote a simple function to do this, and we will examine how it works in this article.
When doing multiplication of binary numbers, the result will never be larger than twice the number of bits of the data types used. That is, two 32bit numbers multiplied together will never have a result larger than 64bits. The reason can be expressed mathematically.
Where n is the number of bits.
So when multiplying two 64bit values it is known the result will always fit into a 128bit. We can construct this result using two 64bit values—an upper word and a lower word.
Doing the multiplication one has to think back to their grade school days and long multiplication. Let us first solve a simple problem doing long multiplication to solve 12x34.
1 
2 

3 
4 

4 
8 

3 
6 
0 
4 
0 
8 
The steps are to first multiply the leastsignificant digits of the 34 by the leastsignificant digit of 12 (in this case 4 and 2) and place the result in the left most column. Then the mostsignificant digits of 34 by the leastsignificant digit of 12 (3 and 2) and place that in the second column from the left. Next is the mostsignificant digit of 34 by the leastsignificant of 12 (3 and 2) which is stored in the second column from the left, and lastly the mostsignificant digit of 34 by the mostsignificant digit of 12 (3 and 1) which is stored in the third column from the left. Sum the two results with carries and we have our end result.
These steps are precisely what is needed in order to multiply two 64bit numbers. But rather than digits, each column will represent 32bits. If you still think of each column as a digit, the following chart is an algebraic representation of the above. To change to 32bits just consider that rather than each column counting from 0 to 9 before carrying the digit to the next column, it counts from 0 to 2^{32} – 1 before carrying to the next column.
au 
al 

bu 
bl 

bl*au 
bl*al 

bu*au 
bu*al 
0 
Here au is the upper 32bits of the first word (a), and al is the lower 32bits. The only problem with looking at the setup this way is that it does not show the word sizes. So let us arrange things like this:
au 
al 

bu 
bl 

bl*al 

bl*au 

bu*al 

bu*au 
Now we can see that the results of the multiplications are twice the width of the two values being multiplied, and how that lines up with the other values in the finial summation. Again, each column is 32bits and the four total columns means we have a 128bit result. We split the input into two 32bit numbers so that each individual multiplication never has a result larger than 64bits. This way there is never an overflow. The trade off is that we now have to do 4 multiplications and several additions.
So here is the source code for doing the multiplication.
// Name: mult128.h
// Uses: 128bit multiplication using 64bit input.
// Date: 2013/12/08
// Author: Andrew Que (http://www.DrQue.net/)
// Compiler: C99 compliant.
// Revision:
// 1.0  2013/12/08  Creation.
//
// Public domain
//******************************************************************************
#ifndef MULT128_H
#define MULT128_H
#include <stdint.h>
// 128bit unsigned integer.
typedef struct
{
uint64_t upper;
uint64_t lower;
} UINT128;
//
// USES:
// Multiply two 64bit unsigned integers to form valueA 128bit result.
// INPUT:
// valueA  First multiplicand.
// valueB  Second multiplicand.
// OUTPUT:
// 128bit unsigned integer of multiply.
//
static inline UINT128 multiply_uint128( uint64_t valueA, uint64_t valueB )
{
int const SHIFT = 32;
uint64_t const MASK = 0xFFFFFFFF;
UINT128 result;
uint64_t product[ 4 ];
uint64_t multiply;
//
// Product is taken by dividing each 64bit word into two 32bit, and doing
// multiplication on the parts.
// a b < Upper/lower word of 'ValueA'
// * c d < Upper/lower word of 'ValueB'
//
// The complete multiply is then the sum of each of the parts. Each
// multiplication spans two words of the result as such:
// [3] [2] [1] [0] < Resulting full product, held in 'product'.
// [b * d]
// [a * d]
// [b * c]
// [a * c]
//
// b * d
multiply = ( valueA & MASK ) * ( valueB & MASK );
product[ 0 ] = ( multiply & MASK );
// a * d
multiply = ( valueA >> SHIFT ) * ( valueB & MASK ) + ( multiply >> SHIFT );
product[ 1 ] = ( multiply & MASK );
product[ 2 ] = ( multiply >> SHIFT );
// b * c
multiply = product[ 1 ] + ( valueA & MASK ) * ( valueB >> SHIFT );
product[ 1 ] = ( multiply & MASK );
// a * c
multiply = product[ 2 ] + ( valueA >> SHIFT ) * ( valueB >> SHIFT ) + ( multiply >> SHIFT );
product[ 2 ] = ( multiply & MASK );
product[ 3 ] = ( multiply >> SHIFT );
// Store result.
result.upper = ( product[ 3 ] << SHIFT )  product[ 2 ];
result.lower = ( product[ 1 ] << SHIFT )  product[ 0 ];
return result;
}
#endif // MULT128_H
There you have it. The code is easily adapted to other integer sizes. By changing the types to uint32_t, and the mask and shift values this function could produce a 64bit result. C already has built in support for 64bit types, but it could be done nonetheless.
The source code is here.