diff options
author | David Robillard <d@drobilla.net> | 2019-09-29 22:41:09 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-10-27 13:13:58 +0100 |
commit | a5ae2f6ee17cdbd033ac2cc13e726ff5d71cabdc (patch) | |
tree | 259f4f558df8a24ae183f5c82542c76c3186e20c /tests/bigint_test.c | |
parent | fd48cffcc1838060bcc451300b38982776779c13 (diff) | |
download | serd-a5ae2f6ee17cdbd033ac2cc13e726ff5d71cabdc.tar.gz serd-a5ae2f6ee17cdbd033ac2cc13e726ff5d71cabdc.tar.bz2 serd-a5ae2f6ee17cdbd033ac2cc13e726ff5d71cabdc.zip |
Add minimal big integer implementation
This is needed for floating point decimal conversion.
Diffstat (limited to 'tests/bigint_test.c')
-rw-r--r-- | tests/bigint_test.c | 930 |
1 files changed, 930 insertions, 0 deletions
diff --git a/tests/bigint_test.c b/tests/bigint_test.c new file mode 100644 index 00000000..1bead4cf --- /dev/null +++ b/tests/bigint_test.c @@ -0,0 +1,930 @@ +/* + Copyright 2011-2020 David Robillard <http://drobilla.net> + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#undef NDEBUG + +#include "../src/bigint.h" + +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#define MAX_HEX_LEN 512 + +/* Some test data borrowed from http://github.com/google/double-conversion + which uses a completely different bigint representation (so if these agree, + everything is probably fine). Others cases are either made up to hit the + edges of the implementation, or interesting cases collected from testing the + decimal implementation. Almost everything here uses the hex representation + so it is easy to dump into Python as a sanity check. */ + +static inline SerdBigint +bigint_from_hex(const char* str) +{ + SerdBigint num; + serd_bigint_set_hex_string(&num, str); + return num; +} + +static bool +check_string_equals(const char* const actual, const char* const expected) +{ + if (strcmp(actual, expected)) { + fprintf(stderr, "error: result \"%s\"\n", actual); + fprintf(stderr, "note: expected \"%s\"\n", expected); + return false; + } + + return true; +} + +static bool +check_hex_equals(const char* const str, const SerdBigint* const num) +{ + char buffer[MAX_HEX_LEN] = {0}; + serd_bigint_to_hex_string(num, buffer, sizeof(buffer)); + + const char* s = str; + while (*s == ' ') { + ++s; // Skip leading whitespace + } + + return check_string_equals(buffer, s); +} + +#define CHECK_HEXEQ(str, num) assert(check_hex_equals(str, num)) +#define CHECK_STREQ(s1, s2) assert(check_string_equals(s1, s2)) + +#define CHECK_SET(setter, value, expected) \ + do { \ + SerdBigint num; \ + serd_bigint_set_##setter(&num, value); \ + CHECK_HEXEQ(expected, &num); \ + } while (0) + +static void +test_set(void) +{ + CHECK_SET(u32, 0, "0"); + CHECK_SET(u32, 0xA, "A"); + CHECK_SET(u32, 0x20, "20"); + CHECK_SET(u32, 0x12345678, "12345678"); + + CHECK_SET(u64, 0, "0"); + CHECK_SET(u64, 0xA, "A"); + CHECK_SET(u64, 0x20, "20"); + CHECK_SET(u64, 0x12345678, "12345678"); + CHECK_SET(u64, 0xFFFFFFFFFFFFFFFFull, "FFFFFFFFFFFFFFFF"); + CHECK_SET(u64, 0x123456789ABCDEF0ull, "123456789ABCDEF0"); + CHECK_SET(u64, 0x123456789ABCDEF0ull, "123456789ABCDEF0"); + + CHECK_SET(decimal_string, "0", "0"); + CHECK_SET(decimal_string, "1", "1"); + CHECK_SET(decimal_string, "01234567890", "499602D2"); + CHECK_SET(decimal_string, "12345.67890", "499602D2"); + CHECK_SET(decimal_string, "12345.67890EOF", "499602D2"); + CHECK_SET(decimal_string, "012345678901", "2DFDC1C35"); + CHECK_SET(decimal_string, "12345.678901", "2DFDC1C35"); + CHECK_SET(decimal_string, + "340282366920938463463374607431768211456", + "100000000000000000000000000000000"); + + CHECK_SET(hex_string, "0", "0"); + CHECK_SET(hex_string, "123456789ABCDEF0", "123456789ABCDEF0"); + + const SerdBigint orig = bigint_from_hex("123456789ABCDEF01"); + SerdBigint copy; + serd_bigint_set(©, &orig); + CHECK_HEXEQ("123456789ABCDEF01", ©); +} + +static void +check_print_hex(const char* value, const size_t len) +{ + assert(len <= MAX_HEX_LEN); + + FILE* const stream = tmpfile(); + const SerdBigint num = bigint_from_hex(value); + + serd_bigint_print_hex(stream, &num); + fseek(stream, 0, SEEK_SET); + + char buf[MAX_HEX_LEN] = {0}; + const size_t n_read = fread(buf, 1, len, stream); + + fclose(stream); + + CHECK_STREQ(buf, value); + assert(n_read == len); +} + +static void +check_to_hex_string(const char* value, + const size_t len, + const char* expected, + const size_t expected_n_written) +{ + const SerdBigint num = bigint_from_hex(value); + char buf[MAX_HEX_LEN] = {0}; + const size_t n_written = serd_bigint_to_hex_string(&num, buf, len); + + assert(n_written == expected_n_written); + CHECK_STREQ(buf, expected); +} + +static void +test_output(void) +{ + check_print_hex("0", 1); + check_print_hex("1", 1); + check_print_hex("1234567", 7); + check_print_hex("12345678", 8); + check_print_hex("123456789ABCDEF0", 16); + check_print_hex("123456789ABCDEF01", 17); + + check_to_hex_string("123456789", 1, "", 0); + check_to_hex_string("123456789", 9, "12345678", 9); + check_to_hex_string("123456789", 10, "123456789", 9); + check_to_hex_string("123456789ABCDEF", 16, "123456789ABCDEF", 15); +} + +static void +check_left_shifted_bigit(const char* value, + const unsigned amount, + const unsigned index, + const Bigit expected) +{ + const SerdBigint num = bigint_from_hex(value); + const Bigit actual = serd_bigint_left_shifted_bigit(&num, amount, index); + + assert(expected == actual); +} + +static void +test_left_shifted_bigit(void) +{ + check_left_shifted_bigit("0", 100, 1, 0x0); + check_left_shifted_bigit("1", 0, 0, 0x1); + check_left_shifted_bigit("1", 1, 0, 0x2); + check_left_shifted_bigit("1", 4, 0, 0x10); + check_left_shifted_bigit("1", 32, 0, 0x0); + check_left_shifted_bigit("1", 32, 1, 0x1); + check_left_shifted_bigit("1", 64, 0, 0x0); + check_left_shifted_bigit("1", 64, 1, 0x0); + check_left_shifted_bigit("1", 64, 2, 0x1); + check_left_shifted_bigit("123456789ABCDEF", 64, 0, 0x0); + check_left_shifted_bigit("123456789ABCDEF", 64, 1, 0x0); + check_left_shifted_bigit("123456789ABCDEF", 64, 2, 0x89ABCDEF); + check_left_shifted_bigit("123456789ABCDEF", 64, 3, 0x1234567); + check_left_shifted_bigit("123456789ABCDEF", 64, 4, 0x0); + check_left_shifted_bigit("123456789ABCDEF", 65, 0, 0x0); + check_left_shifted_bigit("123456789ABCDEF", 65, 1, 0x0); + check_left_shifted_bigit("123456789ABCDEF", 65, 2, 0x13579BDE); + check_left_shifted_bigit("123456789ABCDEF", 65, 3, 0x2468ACF); + check_left_shifted_bigit("123456789ABCDEF", 65, 4, 0x0); +} + +static void +check_shift_left(const char* value, const unsigned amount, const char* expected) +{ + SerdBigint num = bigint_from_hex(value); + serd_bigint_shift_left(&num, amount); + CHECK_HEXEQ(expected, &num); +} + +static void +test_shift_left(void) +{ + check_shift_left("0", 100, "0"); + check_shift_left("1", 1, "2"); + check_shift_left("1", 4, "10"); + check_shift_left("1", 32, "100000000"); + check_shift_left("1", 64, "10000000000000000"); + check_shift_left("123456789ABCDEF", 0, "123456789ABCDEF"); + check_shift_left("123456789ABCDEF", 64, "123456789ABCDEF0000000000000000"); + check_shift_left("123456789ABCDEF", 65, "2468ACF13579BDE0000000000000000"); + check_shift_left("16B8B5E06EDC79", 23, "B5C5AF0376E3C800000"); +} + +static void +check_add_u32(const char* value, const uint32_t rhs, const char* expected) +{ + SerdBigint num = bigint_from_hex(value); + serd_bigint_add_u32(&num, rhs); + CHECK_HEXEQ(expected, &num); +} + +static void +test_add_u32(void) +{ + check_add_u32("0", 1, "1"); + check_add_u32("1", 1, "2"); + check_add_u32("FFFFFFF", 1, "10000000"); + check_add_u32("FFFFFFFFFFFFFF", 1, "100000000000000"); + + check_add_u32("10000000000000000000000000000000000080000000", + 0x80000000, + "10000000000000000000000000000000000100000000"); + + check_add_u32("10000000000000000000000000000000000000000000", + 0x1, + "10000000000000000000000000000000000000000001"); +} + +static void +check_add(const char* lhs_hex, const char* rhs_hex, const char* expected) +{ + SerdBigint lhs = bigint_from_hex(lhs_hex); + const SerdBigint rhs = bigint_from_hex(rhs_hex); + + serd_bigint_add(&lhs, &rhs); + CHECK_HEXEQ(expected, &lhs); +} + +static void +test_add(void) +{ + check_add("1", "0", "1"); + check_add("1", "1", "2"); + check_add("FFFFFFF", "1", "10000000"); + check_add("FFFFFFFFFFFFFF", "1", "100000000000000"); + check_add("1", "1000000000000", "1000000000001"); + check_add("FFFFFFF", "1000000000000", "100000FFFFFFF"); + + check_add("10000000000000000000000000000000000000000000", + "1", + "10000000000000000000000000000000000000000001"); + + check_add("10000000000000000000000000000000000000000000", + "1000000000000", + "10000000000000000000000000000001000000000000"); + + check_add("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "1000000000000", + "1000000000000000000000000000000FFFFFFFFFFFF"); + + check_add("10000000000000000000000000", + "1000000000000", + "10000000000001000000000000"); + + check_add("1", + "10000000000000000000000000000", + "10000000000000000000000000001"); + + check_add("FFFFFFF", + "10000000000000000000000000000", + "1000000000000000000000FFFFFFF"); + + check_add("10000000000000000000000000000000000000000000", + "10000000000000000000000000000", + "10000000000000010000000000000000000000000000"); + + check_add("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "10000000000000000000000000000", + "100000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + check_add("10000000000000000000000000", + "10000000000000000000000000000", + "10010000000000000000000000000"); +} + +static void +check_subtract(const char* lhs_hex, const char* rhs_hex, const char* expected) +{ + SerdBigint lhs = bigint_from_hex(lhs_hex); + const SerdBigint rhs = bigint_from_hex(rhs_hex); + + serd_bigint_subtract(&lhs, &rhs); + CHECK_HEXEQ(expected, &lhs); +} + +static void +test_subtract(void) +{ + check_subtract("1", "0", "1"); + check_subtract("2", "0", "2"); + check_subtract("10000000", "1", "FFFFFFF"); + check_subtract("1FFFFFFFF00000000", "FFFFFFFF", "1FFFFFFFE00000001"); + check_subtract("100000000000000", "1", "FFFFFFFFFFFFFF"); + check_subtract("1000000000001", "1000000000000", "1"); + check_subtract("100000FFFFFFF", "1000000000000", "FFFFFFF"); + + check_subtract("11F2678326EA00000000", + "0878678326EAC9000000", + "979FFFFFFFF37000000"); + + check_subtract("10000000000000000000000000000000000000000001", + "00000000000000000000000000000000000000000001", + "10000000000000000000000000000000000000000000"); + + check_subtract("10000000000000000000000000000001000000000000", + "00000000000000000000000000000001000000000000", + "10000000000000000000000000000000000000000000"); + + check_subtract("1000000000000000000000000000000FFFFFFFFFFFF", + "0000000000000000000000000000001000000000000", + " FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + check_subtract("10000000000000000000000000", + "00000000000001000000000000", + " FFFFFFFFFFFFF000000000000"); + + check_subtract("10000000000000000000000000", + "1000000000000000000000000", + "F000000000000000000000000"); + + check_subtract("FFFFFFF000000000000000", + "0000000000000800000000", + "FFFFFFEFFFFFF800000000"); + + check_subtract("10000000000000000000000000000000000000000000", + "00000000000000000000000000000000000800000000", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF800000000"); + + check_subtract("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "000000000000000000000000000000000800000000", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFF"); +} + +static void +check_subtract_left_shifted(const char* lhs_hex, + const char* rhs_hex, + const unsigned amount, + const char* expected) +{ + SerdBigint lhs = bigint_from_hex(lhs_hex); + const SerdBigint rhs = bigint_from_hex(rhs_hex); + + serd_bigint_subtract_left_shifted(&lhs, &rhs, amount); + CHECK_HEXEQ(expected, &lhs); +} + +static void +test_subtract_left_shifted(void) +{ + check_subtract_left_shifted("1", "0", 1, "1"); + check_subtract_left_shifted("10000000", "1", 1, "FFFFFFE"); + check_subtract_left_shifted("100000000", "40000000", 2, "0"); + check_subtract_left_shifted("1000000000000000", "400000000000000", 2, "0"); + check_subtract_left_shifted("1000000000000000", "800000000000000", 1, "0"); + check_subtract_left_shifted("1000000000000000", "F", 16, "FFFFFFFFFF10000"); + check_subtract_left_shifted("1000000000000000", "F", 24, "FFFFFFFF1000000"); + check_subtract_left_shifted("100000000000000", "1", 0, "FFFFFFFFFFFFFF"); + check_subtract_left_shifted("100000000000000", "1", 56, "0"); + + check_subtract_left_shifted("11F2678326EA00000000", + "43C33C1937564800000", + 1, + "979FFFFFFFF37000000"); +} + +static void +check_multiply_u32(const char* value, const uint32_t rhs, const char* expected) +{ + SerdBigint num = bigint_from_hex(value); + serd_bigint_multiply_u32(&num, rhs); + CHECK_HEXEQ(expected, &num); +} + +static void +test_multiply_u32(void) +{ + check_multiply_u32("0", 0x25, "0"); + check_multiply_u32("123456789ABCDEF", 0, "0"); + check_multiply_u32("2", 0x5, "A"); + check_multiply_u32("10000000", 0x9, "90000000"); + check_multiply_u32("100000000000000", 0xFFFF, "FFFF00000000000000"); + check_multiply_u32("100000000000000", 0xFFFFFFFF, "FFFFFFFF00000000000000"); + check_multiply_u32("1234567ABCD", 0xFFF, "12333335552433"); + check_multiply_u32("1234567ABCD", 0xFFFFFFF, "12345679998A985433"); + check_multiply_u32("FFFFFFFFFFFFFFFF", 0x2, "1FFFFFFFFFFFFFFFE"); + check_multiply_u32("FFFFFFFFFFFFFFFF", 0x4, "3FFFFFFFFFFFFFFFC"); + check_multiply_u32("FFFFFFFFFFFFFFFF", 0xF, "EFFFFFFFFFFFFFFF1"); + check_multiply_u32("FFFFFFFFFFFFFFFF", 0xFFFFFF, "FFFFFEFFFFFFFFFF000001"); + check_multiply_u32("377654D193A171", 10000000, "210EDD6D4CDD2580EE80"); + check_multiply_u32("2E3F36D108373C00000", 10, "1CE78242A52285800000"); + + check_multiply_u32("10000000000000000000000000", + 0x00000002, + "20000000000000000000000000"); + + check_multiply_u32("10000000000000000000000000", + 0x0000000F, + "F0000000000000000000000000"); + + check_multiply_u32("FFFF0000000000000000000000000", + 0xFFFF, + "FFFE00010000000000000000000000000"); + + check_multiply_u32("FFFF0000000000000000000000000", + 0xFFFFFFFF, + "FFFEFFFF00010000000000000000000000000"); + + check_multiply_u32("FFFF0000000000000000000000000", + 0xFFFFFFFF, + "FFFEFFFF00010000000000000000000000000"); +} + +static void +check_multiply_u64(const char* value, const uint64_t rhs, const char* expected) +{ + SerdBigint num = bigint_from_hex(value); + serd_bigint_multiply_u64(&num, rhs); + CHECK_HEXEQ(expected, &num); +} + +static void +test_multiply_u64(void) +{ + check_multiply_u64("0", 0x25, "0"); + check_multiply_u64("123456789ABCDEF", 0, "0"); + check_multiply_u64("123456789ABCDEF", 1, "123456789ABCDEF"); + check_multiply_u64("2", 0x5, "A"); + check_multiply_u64("10000000", 0x9, "90000000"); + check_multiply_u64("100000000000000", 0xFFFF, "FFFF00000000000000"); + check_multiply_u64("1234567ABCD", 0xFFF, "12333335552433"); + check_multiply_u64("1234567ABCD", 0xFFFFFFFFFFull, "1234567ABCBDCBA985433"); + check_multiply_u64("FFFFFFFFFFFFFFFF", 0x2, "1FFFFFFFFFFFFFFFE"); + check_multiply_u64("FFFFFFFFFFFFFFFF", 0x4, "3FFFFFFFFFFFFFFFC"); + check_multiply_u64("FFFFFFFFFFFFFFFF", 0xF, "EFFFFFFFFFFFFFFF1"); + + check_multiply_u64("100000000000000", + 0xFFFFFFFFFFFFFFFFull, + "FFFFFFFFFFFFFFFF00000000000000"); + + check_multiply_u64("FFFFFFFFFFFFFFFF", + 0xFFFFFFFFFFFFFFFFull, + "FFFFFFFFFFFFFFFE0000000000000001"); + + check_multiply_u64("10000000000000000000000000", + 0x00000002, + "20000000000000000000000000"); + + check_multiply_u64("10000000000000000000000000", + 0x0000000F, + "F0000000000000000000000000"); + + check_multiply_u64("FFFF0000000000000000000000000", + 0xFFFF, + "FFFE00010000000000000000000000000"); + + check_multiply_u64("FFFF0000000000000000000000000", + 0xFFFFFFFF, + "FFFEFFFF00010000000000000000000000000"); + + check_multiply_u64("FFFF0000000000000000000000000", + 0xFFFFFFFFFFFFFFFFull, + "FFFEFFFFFFFFFFFF00010000000000000000000000000"); + + check_multiply_u64("377654D193A171", + 0x8AC7230489E80000ull, + "1E10EE4B11D15A7F3DE7F3C7680000"); +} + +static void +check_multiply_pow10(const char* value, + const unsigned exponent, + const char* expected) +{ + SerdBigint num = bigint_from_hex(value); + serd_bigint_multiply_pow10(&num, exponent); + CHECK_HEXEQ(expected, &num); +} + +static void +test_multiply_pow10(void) +{ + check_multiply_pow10("0", 10, "0"); + check_multiply_pow10("1234", 0, "1234"); + check_multiply_pow10("4D2", 1, "3034"); + check_multiply_pow10("4D2", 2, "1E208"); + check_multiply_pow10("4D2", 3, "12D450"); + check_multiply_pow10("4D2", 4, "BC4B20"); + check_multiply_pow10("4D2", 5, "75AEF40"); + check_multiply_pow10("4D2", 6, "498D5880"); + check_multiply_pow10("4D2", 7, "2DF857500"); + check_multiply_pow10("4D2", 8, "1CBB369200"); + check_multiply_pow10("4D2", 9, "11F5021B400"); + check_multiply_pow10("4D2", 10, "B3921510800"); + check_multiply_pow10("4D2", 11, "703B4D2A5000"); + check_multiply_pow10("4D2", 12, "4625103A72000"); + check_multiply_pow10("4D2", 13, "2BD72A24874000"); + check_multiply_pow10("4D2", 14, "1B667A56D488000"); + check_multiply_pow10("4D2", 15, "11200C7644D50000"); + check_multiply_pow10("4D2", 16, "AB407C9EB0520000"); + check_multiply_pow10("4D2", 17, "6B084DE32E3340000"); + check_multiply_pow10("4D2", 18, "42E530ADFCE0080000"); + check_multiply_pow10("4D2", 19, "29CF3E6CBE0C0500000"); + check_multiply_pow10("4D2", 20, "1A218703F6C783200000"); + check_multiply_pow10("4D2", 21, "1054F4627A3CB1F400000"); + check_multiply_pow10("4D2", 22, "A3518BD8C65EF38800000"); + check_multiply_pow10("4D2", 23, "6612F7677BFB5835000000"); + check_multiply_pow10("4D2", 24, "3FCBDAA0AD7D17212000000"); + check_multiply_pow10("4D2", 25, "27DF68A46C6E2E74B4000000"); + check_multiply_pow10("4D2", 26, "18EBA166C3C4DD08F08000000"); + check_multiply_pow10("4D2", 27, "F9344E03A5B0A259650000000"); + check_multiply_pow10("4D2", 28, "9BC0B0C2478E6577DF20000000"); + check_multiply_pow10("4D2", 29, "61586E796CB8FF6AEB740000000"); + check_multiply_pow10("4D2", 30, "3CD7450BE3F39FA2D32880000000"); + check_multiply_pow10("4D2", 31, "26068B276E7843C5C3F9500000000"); + + check_multiply_pow10("4D2", + 50, + "149D1B4CFED03B23AB5F4E1196EF45C0" + "8000000000000"); + + check_multiply_pow10("4D2", + 100, + "5827249F27165024FBC47DFCA9359BF3" + "16332D1B91ACEECF471FBAB06D9B2000" + "0000000000000000000000"); + + check_multiply_pow10("4D2", + 305, + "AFBA390D657B0829339F5B98DC852A89" + "682758E01829EADFD016D1528D4D548B" + "80894B9ED9C2EC6A9CABB4881302A637" + "9FF3058908FEAC310C52FCA009799718" + "8260B0B2E2EC96E471B7892AD9B4F9F9" + "A448CBF150D2E87F3934000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000"); + + check_multiply_pow10("123456789ABCDEF0", 0, "123456789ABCDEF0"); + check_multiply_pow10("123456789ABCDEF0", + 44, + "51A1AD66ACE4E5C79209330F58F52DE3" + "7CEFFF1F000000000000"); + check_multiply_pow10("123456789ABCDEF0", + 88, + "16E0C6D18F4BFA7D0289B88382F56151" + "EB9DA5DB09D56C9BA5D8305619CEE057" + "4F00000000000000000000000"); + check_multiply_pow10("123456789ABCDEF0", + 132, + "6696B1DA27BEA173B5EFCAABBB8492A9" + "2AE3D97F7EE3C7314FB7E2FF8AEFD329" + "F5F8202C22650BB79A7D9F3867F00000" + "00000000000000000000000000000"); + check_multiply_pow10("123456789ABCDEF0", + 176, + "1CC05FF0499D8BC7D8EBE0C6DC2FDC09" + "E93765F3448235FB16AD09D98BBB3A0A" + "843372D33A318EE63DAE6998DA59EF34" + "B15C40A65B9B65ABF3CAF00000000000" + "00000000000000000000000000000000" + "00"); + check_multiply_pow10("123456789ABCDEF0", + 220, + "80ED0FD9A6C0F56A495F466320D34E22" + "507FAA83F0519E7FF909FDDBDA184682" + "BB70D38D43284C828A3681540722E550" + "960567BAB1C25389C1BE7705228BE8CC" + "AF3EBD382829DF000000000000000000" + "00000000000000000000000000000000" + "000000"); + check_multiply_pow10("123456789ABCDEF0", + 264, + "2421FD0F55C486D05211339D45EC2DC4" + "12AE7A64DDFE619DA81B73C069088D3E" + "83D7AA9F99B571815DE939A5275FB4A6" + "9D8930798C01FB96781B9D633BB59AD5" + "A7F322A7EC14154D1B8B5DF1718779A5" + "2291FE0F000000000000000000000000" + "00000000000000000000000000000000" + "00000000000"); + check_multiply_pow10("123456789ABCDEF0", + 308, + "A206620F35C83E9E780ECC07DCAF13BB" + "0A7EE2E213747914340BC172D783BA56" + "661E8DCFFD03C398BD66F5570F445AC6" + "737126283C64AE1A289B9D8BB4531033" + "8C3E34DE2D534187092ABA1F4706100E" + "ECF66D14059461A05A9BEBBCCBA0F693" + "F0000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000"); +} + +static void +check_divmod(const char* lhs_hex, + const char* rhs_hex, + const uint32_t expected_divisor, + const char* expected_mod_hex) +{ + SerdBigint lhs = bigint_from_hex(lhs_hex); + const SerdBigint rhs = bigint_from_hex(rhs_hex); + const uint32_t divisor = serd_bigint_divmod(&lhs, &rhs); + + assert(divisor == expected_divisor); + CHECK_HEXEQ(expected_mod_hex, &lhs); +} + +static void +test_divmod(void) +{ + check_divmod("A", "2", 5, "0"); + check_divmod("B", "2", 5, "1"); + check_divmod("C", "2", 6, "0"); + check_divmod("A", "1234567890", 0, "A"); + check_divmod("FFFFFFFF", "3", 0x55555555, "0"); + check_divmod("12345678", "3789012", 5, "D9861E"); + check_divmod("70000001", "1FFFFFFF", 3, "10000004"); + check_divmod("28000000", "12A05F20", 2, "2BF41C0"); + check_divmod("FFFFFFFFF", "FFFFFFFF", 16, "F"); + check_divmod("100000000000001", "FFFFFFF", 0x10000001, "2"); + check_divmod("40000000000002", "2FAF0800000000", 1, "1050F800000002"); + check_divmod("40000000000000", "40000000000000", 1, "0"); + + check_divmod("43DE72C3DF858FC278A361EEB5A000000", + "80000000000000000000000000000000", + 8, + "3DE72C3DF858FC278A361EEB5A000000"); + + check_divmod("B5C5AF0376E3C800000", + "43C33C1937564800000", + 2, + "2E3F36D108373800000"); + + + check_divmod("A0000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000000", + "20000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000000", + 5, + "0"); + + check_divmod("A0000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000001", + "20000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000000", + 5, + "1"); + + check_divmod("B6080000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000000FF" + "F", + "A0000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "000000000000000000000000000000", + 0x1234, + "FFF"); + + check_divmod("B6080000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "00000000000000000000000000000000" + "0", + "9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + "FFFFFFFFFFFFFFFFFFFFFFFFFFF001", + 0x1234, + "1232DCC"); +} + +static void +check_compare(const char* lhs_hex, const char* rhs_hex, const int expected_cmp) +{ + const SerdBigint lhs = bigint_from_hex(lhs_hex); + const SerdBigint rhs = bigint_from_hex(rhs_hex); + const int cmp = serd_bigint_compare(&lhs, &rhs); + + assert(cmp == expected_cmp); + + if (cmp) { + const int rcmp = serd_bigint_compare(&rhs, &lhs); + assert(rcmp == -cmp); + } +} + +static void +test_compare(void) +{ + check_compare("1", "1", 0); + check_compare("0", "1", -1); + check_compare("F", "FF", -1); + check_compare("F", "FFFFFFFFF", -1); + check_compare("10000000000000000", "10000000000000000", 0); + check_compare("10000000000000000", "10000000000000001", -1); + check_compare("FFFFFFFFFFFFFFFFF", "100000000000000000", -1); + check_compare("10000000000000000", "10000000000000001", -1); + check_compare("1234567890ABCDEF12345", "1234567890ABCDEF12345", 0); + check_compare("1234567890ABCDEF12345", "1234567890ABCDEF12346", -1); + + const char* const huge = "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF0"; + + const char* const huger = "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF0" + "123456789ABCDEF0123456789ABCDEF1"; + + check_compare(huge, huge, 0); + check_compare(huger, huger, 0); + check_compare(huge, huger, -1); +} + +static void +check_plus_compare(const char* l_hex, + const char* p_hex, + const char* c_hex, + const int expected_cmp) +{ + const SerdBigint l = bigint_from_hex(l_hex); + const SerdBigint p = bigint_from_hex(p_hex); + const SerdBigint c = bigint_from_hex(c_hex); + const int cmp = serd_bigint_plus_compare(&l, &p, &c); + const int rcmp = serd_bigint_plus_compare(&p, &l, &c); + + assert(cmp == expected_cmp); + assert(rcmp == expected_cmp); +} + +static void +test_plus_compare(void) +{ + check_plus_compare("1", "0", "1", 0); + check_plus_compare("0", "0", "1", -1); + check_plus_compare("FFFFFFFFF", "F", "F", 1); + check_plus_compare("F", "F", "800000000", -1); + check_plus_compare("F", "F", "80000000000000000", -1); + check_plus_compare("800000000", "F", "80000000000000000", -1); + check_plus_compare("2D79883D20000", "2D79883D20000", "5AF3107A40000", 0); + check_plus_compare("20000000000000", "1", "20000000000000", +1); + + check_plus_compare("0588A503282FE00000", + "0588A503282FE00000", + "0AD78EBC5AC6200000", + +1); + + check_plus_compare("2F06018572BEADD1280000000", + "0204FCE5E3E25026110000000", + "4000000000000000000000000", + -1); + + check_plus_compare("1234567890ABCDEF12345", + "000000000000000000001", + "1234567890ABCDEF12345", + +1); + + check_plus_compare("1234567890ABCDEF12344", + "000000000000000000001", + "1234567890ABCDEF12345", + 0); + + check_plus_compare("123456789000000000000", + "0000000000ABCDEF12345", + "1234567890ABCDEF12345", + 0); + + check_plus_compare("123456789000000000000", + "0000000000ABCDEF12344", + "1234567890ABCDEF12345", + -1); + + check_plus_compare("123456789000000000000", + "0000000000ABCDEF12346", + "1234567890ABCDEF12345", + 1); + + check_plus_compare("123456789100000000000", + "0000000000ABCDEF12345", + "1234567890ABCDEF12345", + 1); + + check_plus_compare("123456788900000000000", + "0000000000ABCDEF12345", + "1234567890ABCDEF12345", + -1); + + check_plus_compare("12345678900000000000000000000", + "0000000000ABCDEF1234500000000", + "1234567890ABCDEF1234500000000", + 0); + + check_plus_compare("12345678900000000000000000000", + "0000000000ABCDEF1234400000000", + "1234567890ABCDEF1234500000000", + -1); + + check_plus_compare("12345678900000000000000000000", + "0000000000ABCDEF1234600000000", + "1234567890ABCDEF1234500000000", + 1); + + check_plus_compare("12345678910000000000000000000", + "0000000000ABCDEF1234500000000", + "1234567890ABCDEF1234500000000", + 1); + check_plus_compare("12345678890000000000000000000", + "0000000000ABCDEF1234500000000", + "1234567890ABCDEF1234500000000", + -1); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12345", + "123456789000000000ABCDEF12345", + 0); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12346", + "123456789000000000ABCDEF12345", + 1); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12344", + "123456789000000000ABCDEF12345", + -1); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12345", + "12345678900000ABCDEF123450000", + -1); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12344", + "12345678900000ABCDEF123450000", + -1); + + check_plus_compare("12345678900000000000000000000", + "000000000000000000ABCDEF12345", + "12345678900000ABCDEF123450001", + -1); + + check_plus_compare("12345678900000000000000000000", + "00000000000000ABCDEF123460000", + "12345678900000ABCDEF123450000", + 1); +} + +static void +check_pow10(const unsigned exponent, const char* expected) +{ + SerdBigint num; + serd_bigint_set_pow10(&num, exponent); + CHECK_HEXEQ(expected, &num); +} + +static void +test_set_pow10(void) +{ + check_pow10(0, "1"); + check_pow10(1, "A"); + check_pow10(2, "64"); + check_pow10(5, "186A0"); + check_pow10(8, "5F5E100"); + check_pow10(16, "2386F26FC10000"); + check_pow10(30, "C9F2C9CD04674EDEA40000000"); + check_pow10(31, "7E37BE2022C0914B2680000000"); +} + +int +main(void) +{ + test_set(); + test_output(); + test_left_shifted_bigit(); + test_shift_left(); + test_add_u32(); + test_add(); + test_subtract(); + test_subtract_left_shifted(); + test_multiply_u32(); + test_multiply_u64(); + test_multiply_pow10(); + test_divmod(); + test_compare(); + test_plus_compare(); + test_set_pow10(); + + return 0; +} |