https://github.com/jprjr/bigint
Single-header C library for big integer arithmetic
https://github.com/jprjr/bigint
Last synced: 4 months ago
JSON representation
Single-header C library for big integer arithmetic
- Host: GitHub
- URL: https://github.com/jprjr/bigint
- Owner: jprjr
- License: 0bsd
- Created: 2023-03-19T21:48:45.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-04-17T17:45:23.000Z (about 2 years ago)
- Last Synced: 2025-01-24T21:14:04.635Z (5 months ago)
- Language: C
- Size: 63.5 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# bigint.h
A single-file C library for performing big-integer arithmetic,
including functions for converting from/to strings.This isn't meant to be the fastest thing in the world, I did
this mostly as a learning exercise.## Building
In one source file, define `BIGINT_IMPLEMENTATION`, then include
`bigint.h`.```c
#define BIGINT_IMPLEMENTATION
#include "bigint.h"
```By default, all math operations use 32-bit, unsigned integers
with 64-bit unsigned integers for temporary additions, carries,
etc.If for some reason you don't have a larger type available for
multiplication, you can define `BIGINT_SINGLE_WORD_ONLY`, and
the library will fall back to cross-product multiplication.You can customize the width by setting `BIGINT_WORD_WIDTH` to any of:
* `1` (uses `uint8_t`)
* `2` (uses `uint16_t)`)
* `4` (uses `uint32_t`)
* `8` (uses `uint64_t`)In the case of using a 64-bit word width, the library will
try to perform 128-bit multiplications if support is detected via
C macros, and fall back to cross-product multiplication otherwise.If you need some other type you can define `BIGINT_WORD_TYPE`. You
still need to also define the type width, in bytes. You can also
specify a double-width type, `BIGINT_DWORD_TYPE`.By default, all bigint objects are limited to using 4096 bytes of
memory, this can be customized per-object by setting the `limit`
field. The intention is for you to not, say, run out of memory while
parsing a never-ending string of data. You can also set the default
by defining `BIGINT_DEFAULT_LIMIT`.Finally, if you want to have everything be statically-allocated, you
can define `BIGINT_NO_MALLOC`. This will cause all bigints to use
a fixed-size number of bytes (set to `BIGINT_DEFAULT_LIMIT`).If you define any of:
* `BIGINT_WORD_WIDTH`
* `BIGINT_WORD_TYPE`
* `BIGINT_DEFAULT_LIMIT`
* `BIGINT_NO_MALLOC`They will need to be defined before any `#include` of the library,
since those values will affect things like function signatures and
the structure definition.## Usage
bigint objects can be allocated however you wish, then initialized
with either `bigint_init()` or using the defined `BIGINT_INIT`, ie:```c
bigint a = BIGINT_INIT; /* static initialization */
bigint *b = malloc(sizeof(bigint));
bigint_init(b); /* initialize with function */
```When no longer used, you'll need to use `bigint_free()` to free used
memory.By default, bigint objects are initialized to represent 0.
You can set a starting value from various integer types:
```c
bigint_from_u8(&b,5);
bigint_from_i32(&b,-2147483648);
```Or parse a string, provide the string and the base to use (2, 8, 10, 16, or 0 for auto):
```c
bigint_from_cstring(&b,"12345",10);
bigint_from_cstring(&b,"-12345",10);
bigint_from_cstring(&b,"0x100",16);
bigint_from_cstring(&b,"-0x100",16);
bigint_from_cstring(&b,"-0b100",2);/* bigint_from_cstring is a wrapper around bigint_from_string - bigint_from_string
takes a length parameter, bigint_from_cstring just uses strlen() */
bigint_from_string(&b,"12345",5,10);
bigint_from_string(&b,"-12345",6,10);
bigint_from_string(&b,"0x100",5,16);
bigint_from_string(&b,"-0x100",6,16);
bigint_from_string(&b,"-0b100",6,2);
```You can copy bigints:
```c
bigint_copy(&dup,&b); /* dup now has the same data as b */
```You can increment, decrement, add, subtract, multiply, and divide bigints.
Functions do not modify your input arguments.
```c
/* equivalent to c = b + 1 */
bigint_inc(&c, &b);/* equivalent to c = b - 1 */
bigint_dec(&c, &b);/* equivalent to c = a + b */
bigint_add(&c, &a, &b);/* equivalent to c = a - b */
bigint_sub(&c, &a, &b);/* equivalent to c = a * b */
bigint_mul(&c, &a, &b);/* returns the quotient and remainder of an operation at once,
similar to:
q = a / b
r = a % b
*/
bigint_div_mod(&q, &r, &a, &b);
```There's also left-shifting and right-shifting:
```c
bigint_lshift(&res, &a, 128); /* equivalent to res = a << 128 */
bigint_rshift(&res, &a, 128); /* equivalent to res = a >> 128 */
```All functions work on temporary values and perform a copy at the end,
meaning it's safe to do things like:```c
bigint_add(&b, &b, &a); /* equivalent to b += a
```In some cases there's faster versions of math operations if
overwriting the original is OK (for example, left-shifting and
right-shifting). Those functions are:```c
bigint_lshift_overwrite(bigint *b, size_t bits); /* equivalent to b <<= bits */
bigint_rshift_overwrite(bigint *b, size_t bits); /* equivalent to b >>= bits *//* this one takes bigint_words as parameters (default uint32_t), it's a much faster division,
equivalent to:
remainder = numerator % denominator
numerator /= denominator
*/
bigint_div_mod_word(bigint *numerator, bigint_word* remainder, bigint_word denominator);
```Finally there's a function to write the bigint out as a string. It accepts
a buffer, the size of the buffer, and the base to use. Notably, it does NOT write out a NULL
character. It *does* include a prefix based on the base:* base 2 - prefix with '0b'
* base 8 - prefix with '0'
* base 16 - prefix with '0x'```c
char buffer[101];
/* always pass size-1 to leave room for null terminator */
buffer[bigint_to_string(buffer,100,&b,10)] = '\0';
```If you need a length estimate you can pass `NULL` as the buffer:
```c
size_t needed = bigint_to_string(NULL,0, &b, 10);
if(!needed) return some_kind_of_error;/* add extra byte for '\0' terminator */
char *buffer = malloc(needed+1);
buffer[bigint_to_string(buffer,needed,&b,10)] = '\0';
```All functions (besides `bigint_to_string`) return an integer,
with 0 meaning success, or one of the following error codes:* `BIGINT_ENOMEM` - an attempt to resize a bigint ran out of memory.
* `BIGINT_ELIMIT` - an attempt to resize a bigint would exceed the `limit` field.
* `BIGINT_EINVAL` - returned when parsing a string with invalid data.`bigint_to_string` returns the number of characters required/written,
returning `0` indicates some kind of error.## LICENSE
BSD Zero Clause (see the `LICENSE` file).
Some files are third-party and have their own licensing:
* `utest.h`: Public Domain / Unlicense, see file for details.
* Note, `utest.h` is not required for library usage, this is for running automated tests.