Streamlining Big Number Calculations in C using GMP

Streamlining Big Number Calculations in C using GMP

Nowadays, technologies like Cryptography need computers to compute complex mathematical operations. These algorithms need the CPU to perform arithmetic operations on large numbers with high precision.

The amount of data a processor can execute at once depends on its number of virtual memory addresses. The maximum integer representation a 32-bit processor can work with is 4,294,967,295 (2^32 − 1), while for a 64-bit processor is 18,446,744,073,709,551,615 (2^64 − 1). These bit constraints affect C standard integer and float data types.

Most high-level languages, like Python, allows programmers to work with larger numbers. Allowing programmers to write programs for processing numbers larger than what the CPU can handle. It's possible to write programs for calculating big numbers in C, but it can get very complex and confusing.

GMP, GNU Multiple Precision Arithmetic Library, streamlines the complexity of working with big numbers in C. This article covers how you can use the GMP Library to perform basic mathematical operations on various kinds of numbers.

Prerequisites

To follow this article, you need to have;

  • A basic understanding of C,

  • GCC installed - for compiling C programs,

  • Basic understanding of GCC,

  • Access to the internet - for installing GMP, and

  • A text editor was installed.

What is GMP?

GMP is a free library for arbitrary precision arithmetic, operating on signed integers, rational numbers, and floating-point numbers. There is no practical limit to the precision except the ones implied by the available memory in the machine GMP runs on. GMP has a rich set of functions, and the functions have a regular interface. - gmplib.org

GMP allows you to calculate big numbers of many kinds with high precision. It represents numbers in its program as strings.

Installing GMP

To install the GMP library, you can follow this informative guide. It explains how you can download, configure and build the library on Windows, Mac, and Linux.

Performing Arithmetical Operations Using GMP

After installing the library, you need to include the GMP header file in your program to use the library for calculations.

Addition

For adding two integers, you need to declare and initialize the variables in a special way before calculations.

Include GMP library header. This allows you to access the types and macros declared in the header file.

#include <gmp.h>

Declare and initialize the variables for the result, and the numbers to add together.

mpz_t res, num_a, num_b;

/* Initializing integers */
mpz_init(res), mpz_init(num_a), mpz_init(num_b);

Initializing the variables using mpz_init function tells GMP to allocate memory space to the variables. Then you can assign any large number to the initialized variables.

The lines below assign 3479349783486297692763769376273723897236 to num_a and 9223372036854775807 to num_b. There is no limit to the amount of precision you get when using GMP for calculations.

/* Assigning integers */
mpz_set_str(num_a, "3479349783486297692763769376273723897236", 10);
mpz_set_str(num_b, "9223372036854775807", 10);

The mpz_set_str function takes the first argument as the variable to assign a value. The second argument is the string representation of the integer you want to assign. The third argument represents the base of the integer (which, in this case, is the second argument). In the above example, the integers are in base 10, meaning decimal numbers.

Now you can add the number together using the mpz_add function from the GMP library. The function sets res to num_a + num_b. Then you can use gmp_printf to print the values. It works like C standard library printf function. The only difference is that gmp_printf allows you to format larger numbers. The %Zd flag in the format string in gmp_printf is to format large integers.

/* Addition */
mpz_add(res, num_a, num_b);
gmp_printf("Addition:\n%Zd + %Zd = %Zd\n\n", num_a, num_b, res);

Now you need to clear the variables. Clearing the variables frees the memory allocated for the variables.

/* Clearing memory */
mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);

The full program should look like this.

// main.c

#include <gmp.h>

int main(void)
{
    mpz_t res, num_a, num_b;

    /* Initializing integers */
    mpz_init(res), mpz_init(num_a), mpz_init(num_b);

    /* Assigning integers */
    mpz_set_str(num_a, "3479349783486297692763769376273723897236", 10);
    mpz_set_str(num_b, "9223372036854775807", 10);

    /* Addition */
    mpz_add(res, num_a, num_b);
    gmp_printf("Addition:\n%Zd + %Zd = %Zd\n\n", num_a, num_b, res);

    /* Clearing memory */
    mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);

    return (0);
}

You need to link the GMP library when compiling your program. You can only link the dynamic or static library if you have installed GMP on your machine. If you haven’t, go back to the installation section above.

Run the command below to build your program. The -lgmp flag tells gcc to search for the GMP library when linking. GCC will search the list of standard directories to find the library.

gcc main.c -o main -lgmp

If it could not find the GMP library on your machine. Try with the build flags below. The -L~/gmp-6.2.1/.libs flag tells gcc to also check the ~/gmp-6.2.1/.libs directory if it could not find the library using the standard list. For you, this path is the location you installed GMP.

gcc main.c -o main -L~/gmp-6.2.1/.libs -lgmp -static

That covers how you can add large numbers in C and build your program.

Subtraction

You can use the mpz_sub function from the GMP library to subtract large numbers. Ensure you initialize the variables and assign their integers respectively.

This subtracts num_b from num_a and assigns the result to res.

/* Subtraction */
mpz_sub(res, num_b, num_a);
gmp_printf("Substraction:\n%Zd - %Zd = %Zd\n\n", num_a, num_b, res);

Your full program might look like this.

// main.c

#include <gmp.h>

int main(void)
{
    mpz_t res, num_a, num_b;

    /* Initializing integers */
    mpz_init(res), mpz_init(num_a), mpz_init(num_b);

    /* Assigning integers */
    mpz_set_str(num_a, "3434234245245245252452452452", 10);
    mpz_set_str(num_b, "9999943444444434344444444434232323232322", 10);

    /* Subtraction */
    mpz_sub(res, num_a, num_b);
    gmp_printf("Substraction:\n%Zd - %Zd = %Zd\n\n", num_a, num_b, res);

    /* Clearing memory */
    mpz_clear(res), mpz_clear(num_a), mpz_clear(num_b);

    return (0);
}

Multiplication

For multiplying integers, use mpz_mul function from the GMP library.

This multiplies num_a and num_b and assigns results to res.

/* Multiplication */
mpz_mul(res, num_a, num_b);
gmp_printf("Multiplication:\n%Zd x %Zd = %Zd\n\n", num_a, num_b, res);

Division

For division, things will look a little different. Instead of using the type mpz_t to declare integers as you have seen before, you will use mpf_t instead to declare floats.

To divide large numbers using GMP you need to declare and initialize floats and not integers.

mpf_t div_res, div_a, div_b;

Then you initialize the variables using mpf_init.

/* Initializing floats */
mpf_init(div_res), mpf_init(div_a), mpf_init(div_b);

Assign values you want to the variables. They can be as large as needed. The last argument to mpf_set_str tells GMP that the string is in a decimal format.

/* Assign floats */
mpf_set_str(div_a, "7347973477376467734.34322335550000000000", 10);
mpf_set_str(div_b, "489384838948848.4783873847", 10);

Divide and print out the results using the functions below. The GMP function mpf_div divides div_a by div_b and assigns the result to div_res. Then prints out the formatted string.

/* Division */
mpf_div(div_res, div_a, div_b);
gmp_printf("Division:\n%Ff / %Ff = %Ff\n\n", div_a, div_b, div_res);

Your final code should look like this.

// main.c

#include <gmp.h>

int main(void)
{
    mpf_t div_res, div_a, div_b;

    /* Initializing floats */
    mpf_init(div_res), mpf_init(div_a), mpf_init(div_b);

    /* Assign floats */
    mpf_set_str(div_a, "7347973477376467734.34322335550000000000", 10);
    mpf_set_str(div_b, "489384838948848.4783873847", 10);

    /* Division */
    mpf_div(div_res, div_a, div_b);
    gmp_printf("Division:\n%Ff / %Ff = %Ff\n\n", div_a, div_b, div_res);

    /* Clearing memory */
    mpf_clear(div_res), mpf_clear(div_a), mpf_clear(div_b);

    return (0);
}

Square root

Ensure you declare and initialize the float variables. Then calculate the square root of that variable using mpf_sqrt function. This function only accepts two arguments. The variable to square root and the variable to assign the result.

/* Squre root */
mpf_sqrt(div_res, div_a);
gmp_printf("Square root:\nsqrt(%Ff) = %Ff\n", div_a, div_res);

Conclusion

You can perform other arithmetical operations that are not covered in this article using GMP. Check out the resources section below for their documentation to learn more. It covers how you can perform more Arithmetical operations with Logical and Bitwise operations. Also, you can calculate using C int types and rational numbers.

Use the resources provided below to learn more about working with big numbers in C using the GMP library. If you are looking for a challenge try writing a C function to add two large numbers.

Thanks for reading this article. 😊

Resources