diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-06-08 12:03:40 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-06-08 12:03:40 +0100 |
| commit | 9b61adb97dd78e1cf04ad410e72166f684f97925 (patch) | |
| tree | ccb50b757f31c36dcd2bac161d191e2d23dcb6d1 /src/integer128.c | |
| parent | 333924cce15e10e941ee63d6fcdc19d5cb95bb3c (diff) | |
Build as C++
Diffstat (limited to 'src/integer128.c')
| -rw-r--r-- | src/integer128.c | 612 |
1 files changed, 0 insertions, 612 deletions
diff --git a/src/integer128.c b/src/integer128.c deleted file mode 100644 index 6cce03143..000000000 --- a/src/integer128.c +++ /dev/null @@ -1,612 +0,0 @@ -typedef struct u128 {u64 lo; u64 hi;} u128; -typedef struct i128 {u64 lo; i64 hi;} i128; - -#define BIT128_U64_HIGHBIT 0x8000000000000000ul -#define BIT128_U64_BITS62 0x7ffffffffffffffful -#define BIT128_U64_ALLBITS 0xfffffffffffffffful - -static u128 const U128_ZERO = {0, 0}; -static u128 const U128_ONE = {1, 0}; -static i128 const I128_ZERO = {0, 0}; -static i128 const I128_ONE = {1, 0}; -static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS}; -static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS}; - -u128 u128_lo_hi (u64 lo, u64 hi); -u128 u128_from_u32 (u32 u); -u128 u128_from_u64 (u64 u); -u128 u128_from_i64 (i64 u); -u128 u128_from_f32 (f32 f); -u128 u128_from_f64 (f64 f); -u128 u128_from_string(String string); - -i128 i128_lo_hi (u64 lo, i64 hi); -i128 i128_from_u32 (u32 u); -i128 i128_from_u64 (u64 u); -i128 i128_from_i64 (i64 u); -i128 i128_from_f32 (f32 f); -i128 i128_from_f64 (f64 f); -i128 i128_from_string(String string); - -u64 u128_to_u64(u128 a); -i64 u128_to_i64(u128 a); -f64 u128_to_f64(u128 a); - -u64 i128_to_u64(i128 a); -i64 i128_to_i64(i128 a); -f64 i128_to_f64(i128 a); - -String u128_to_string(u128 a, char *buf, isize len); -String i128_to_string(i128 a, char *buf, isize len); - -i32 u128_cmp (u128 a, u128 b); -bool u128_eq (u128 a, u128 b); -bool u128_ne (u128 a, u128 b); -bool u128_lt (u128 a, u128 b); -bool u128_gt (u128 a, u128 b); -bool u128_le (u128 a, u128 b); -bool u128_ge (u128 a, u128 b); -u128 u128_add (u128 a, u128 b); -u128 u128_not (u128 a); -u128 u128_neg (u128 a); -u128 u128_sub (u128 a, u128 b); -u128 u128_and (u128 a, u128 b); -u128 u128_or (u128 a, u128 b); -u128 u128_xor (u128 a, u128 b); -u128 u128_and_not(u128 a, u128 b); -u128 u128_shl (u128 a, u32 n); -u128 u128_shr (u128 a, u32 n); -u128 u128_mul (u128 a, u128 b); -void u128_divide (u128 num, u128 den, u128 *quo, u128 *rem); -u128 u128_quo (u128 a, u128 b); -u128 u128_mod (u128 a, u128 b); - -i128 i128_abs (i128 a); -i32 i128_cmp (i128 a, i128 b); -bool i128_eq (i128 a, i128 b); -bool i128_ne (i128 a, i128 b); -bool i128_lt (i128 a, i128 b); -bool i128_gt (i128 a, i128 b); -bool i128_le (i128 a, i128 b); -bool i128_ge (i128 a, i128 b); -i128 i128_add (i128 a, i128 b); -i128 i128_not (i128 a); -i128 i128_neg (i128 a); -i128 i128_sub (i128 a, i128 b); -i128 i128_and (i128 a, i128 b); -i128 i128_or (i128 a, i128 b); -i128 i128_xor (i128 a, i128 b); -i128 i128_and_not(i128 a, i128 b); -i128 i128_shl (i128 a, u32 n); -i128 i128_shr (i128 a, u32 n); -i128 i128_mul (i128 a, i128 b); -void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem); -i128 i128_quo (i128 a, i128 b); -i128 i128_mod (i128 a, i128 b); - - -//////////////////////////////////////////////////////////////// - - -u64 bit128__digit_value(Rune r) { - if ('0' <= r && r <= '9') { - return r - '0'; - } else if ('a' <= r && r <= 'f') { - return r - 'a' + 10; - } else if ('A' <= r && r <= 'F') { - return r - 'A' + 10; - } - return 16; // NOTE(bill): Larger than highest possible -} - -u128 u128_lo_hi(u64 lo, u64 hi) { return (u128){lo, hi}; } -u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); } -u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); } -u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); } -u128 u128_from_f32(f32 f) { return u128_lo_hi(cast(u64)f, 0); } -u128 u128_from_f64(f64 f) { return u128_lo_hi(cast(u64)f, 0); } -u128 u128_from_string(String string) { - // TODO(bill): Allow for numbers with underscores in them - u64 base = 10; - bool has_prefix = false; - if (string.len > 2 && string.text[0] == '0') { - switch (string.text[1]) { - case 'b': base = 2; has_prefix = true; break; - case 'o': base = 8; has_prefix = true; break; - case 'd': base = 10; has_prefix = true; break; - case 'z': base = 12; has_prefix = true; break; - case 'x': base = 16; has_prefix = true; break; - } - } - - u8 *text = string.text; - isize len = string.len; - if (has_prefix) { - text += 2; - len -= 2; - } - - u128 base_ = u128_from_u64(base); - - u128 result = {0}; - for (isize i = 0; i < len; i++) { - Rune r = cast(Rune)text[i]; - if (r == '_') { - continue; - } - u64 v = bit128__digit_value(r); - if (v >= base) { - break; - } - result = u128_mul(result, base_); - result = u128_add(result, u128_from_u64(v)); - } - return result; -} - - -i128 i128_lo_hi(u64 lo, i64 hi) { - i128 i; - i.lo = lo; - i.hi = hi; - return i; -} -i128 i128_from_u32(u32 u) { return i128_lo_hi(cast(u64)u, 0); } -i128 i128_from_u64(u64 u) { return i128_lo_hi(cast(u64)u, 0); } -i128 i128_from_i64(i64 u) { return i128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); } -i128 i128_from_f32(f32 f) { return i128_lo_hi(cast(u64)f, 0); } -i128 i128_from_f64(f64 f) { return i128_lo_hi(cast(u64)f, 0); } -i128 i128_from_string(String string) { - // TODO(bill): Allow for numbers with underscores in them - u64 base = 10; - bool has_prefix = false; - if (string.len > 2 && string.text[0] == '0') { - switch (string.text[1]) { - case 'b': base = 2; has_prefix = true; break; - case 'o': base = 8; has_prefix = true; break; - case 'd': base = 10; has_prefix = true; break; - case 'z': base = 12; has_prefix = true; break; - case 'x': base = 16; has_prefix = true; break; - } - } - - u8 *text = string.text; - isize len = string.len; - if (has_prefix) { - text += 2; - len -= 2; - } - - i128 base_ = i128_from_u64(base); - - i128 result = {0}; - for (isize i = 0; i < len; i++) { - Rune r = cast(Rune)text[i]; - if (r == '_') { - continue; - } - u64 v = bit128__digit_value(r); - if (v >= base) { - break; - } - result = i128_mul(result, base_); - result = i128_add(result, i128_from_u64(v)); - } - - return result; -} - - - -u64 u128_to_u64(u128 a) { - return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT); -} -i64 u128_to_i64(u128 a) { - return a.lo; -} -f64 u128_to_f64(u128 a) { - if (a.hi >= 0) { - return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo; - } - i64 h = cast(i64)a.hi; - u64 l = a.lo; - h = ~h; - l = ~l; - l += 1; - if (l == 0) { - h += 1; - } - - return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); -} - -u64 i128_to_u64(i128 a) { - return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT); -} -i64 i128_to_i64(i128 a) { - return cast(i64)a.lo; -} -f64 i128_to_f64(i128 a) { - if (a.hi >= 0) { - return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo; - } - i64 h = a.hi; - u64 l = a.lo; - h = ~h; - l = ~l; - l += 1; - if (l == 0) { - h += 1; - } - - return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); -} - - -String u128_to_string(u128 v, char *out_buf, isize out_buf_len) { - char buf[200] = {0}; - isize i = gb_size_of(buf); - - u128 b = u128_from_u64(10);; - while (u128_ge(v, b)) { - buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))]; - v = u128_quo(v, b); - } - buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))]; - - isize len = gb_min(gb_size_of(buf)-i, out_buf_len); - gb_memcopy(out_buf, &buf[i], len); - return make_string(cast(u8 *)out_buf, len); -} -String i128_to_string(i128 a, char *out_buf, isize out_buf_len) { - char buf[200] = {0}; - isize i = gb_size_of(buf); - bool negative = false; - if (i128_lt(a, I128_ZERO)) { - negative = true; - a = i128_neg(a); - } - - u128 v = *cast(u128 *)&a; - u128 b = u128_from_u64(10);; - while (u128_ge(v, b)) { - buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))]; - v = u128_quo(v, b); - } - buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))]; - - if (negative) { - buf[--i] = '-'; - } - - isize len = gb_min(gb_size_of(buf)-i, out_buf_len); - gb_memcopy(out_buf, &buf[i], len); - return make_string(cast(u8 *)out_buf, len); -} - - - -//////////////////////////////////////////////////////////////// - -i32 u128_cmp(u128 a, u128 b) { - if (a.hi == b.hi && b.lo == b.lo) { - return 0; - } - if (a.hi == b.hi) { - return a.lo < b.lo ? -1 : +1; - } - return a.hi < b.hi ? -1 : +1; -} - -bool u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; } -bool u128_ne(u128 a, u128 b) { return !u128_eq(a, b); } -bool u128_lt(u128 a, u128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; } -bool u128_gt(u128 a, u128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; } -bool u128_le(u128 a, u128 b) { return !u128_gt(a, b); } -bool u128_ge(u128 a, u128 b) { return !u128_lt(a, b); } - -u128 u128_add(u128 a, u128 b) { - u128 old_a = a; - a.lo += b.lo; - a.hi += b.hi; - if (a.lo < old_a.lo) { - a.hi += 1; - } - return a; -} -u128 u128_not(u128 a) { return u128_lo_hi(~a.lo, ~a.hi); } - -u128 u128_neg(u128 a) { - return u128_add(u128_not(a), u128_from_u64(1)); -} -u128 u128_sub(u128 a, u128 b) { - return u128_add(a, u128_neg(b)); -} -u128 u128_and(u128 a, u128 b) { return u128_lo_hi(a.lo&b.lo, a.hi&b.hi); } -u128 u128_or (u128 a, u128 b) { return u128_lo_hi(a.lo|b.lo, a.hi|b.hi); } -u128 u128_xor(u128 a, u128 b) { return u128_lo_hi(a.lo^b.lo, a.hi^b.hi); } -u128 u128_and_not(u128 a, u128 b) { return u128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); } - - -u128 u128_shl(u128 a, u32 n) { - if (n >= 128) { - return u128_lo_hi(0, 0); - } - - if (n >= 64) { - n -= 64; - a.hi = a.lo; - a.lo = 0; - } - - if (n != 0) { - u64 mask = ~(BIT128_U64_ALLBITS >> n); - - a.hi <<= n; - a.hi |= (a.lo&mask) >> (64 - n); - a.lo <<= n; - } - return a; -} - -u128 u128_shr(u128 a, u32 n) { - if (n >= 128) { - return u128_lo_hi(0, 0); - } - - if (n >= 64) { - n -= 64; - a.lo = a.hi; - a.hi = 0; - } - - if (n != 0) { - u64 mask = ~(BIT128_U64_ALLBITS << n); - a.lo >>= n; - a.lo |= (a.hi&mask) << (64 - n); - a.hi >>= n; - } - return a; -} - - -u128 u128_mul(u128 a, u128 b) { - if (a.lo == 0 && a.hi == 0) { - return u128_from_u64(0); - } else if (b.lo == 0 && b.hi == 0) { - return u128_from_u64(0); - } - if (u128_eq(a, U128_ONE)) { - return b; - } - if (u128_eq(b, U128_ONE)) { - return a; - } - - u128 res = {0}; - u128 t = b; - for (u32 i = 0; i < 128; i++) { - if ((t.lo&1) != 0) { - res = u128_add(res, u128_shl(a, i)); - } - - t = u128_shr(t, 1); - } - - return res; -} - -void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { - if (u128_eq(den, U128_ZERO)) { - if (quo) *quo = u128_from_u64(num.lo/den.lo); - if (rem) *rem = U128_ZERO; - } else { - u128 n = num; - u128 d = den; - u128 x = U128_ONE; - u128 r = U128_ZERO; - - while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) { - x = u128_shl(x, 1); - d = u128_shl(d, 1); - } - - while (u128_ne(x, U128_ZERO)) { - if (u128_ge(n, d)) { - n = u128_sub(n, d); - r = u128_or(r, x); - } - - x = u128_shr(x, 1); - d = u128_shr(d, 1); - } - - if (quo) *quo = r; - if (rem) *rem = n; - } -} - -u128 u128_quo(u128 a, u128 b) { - u128 res = {0}; - u128_divide(a, b, &res, NULL); - return res; -} -u128 u128_mod(u128 a, u128 b) { - u128 res = {0}; - u128_divide(a, b, NULL, &res); - return res; -} - -//////////////////////////////////////////////////////////////// - -i128 i128_abs(i128 a) { - if ((a.hi&BIT128_U64_HIGHBIT) != 0) { - return i128_neg(a); - } - return a; -} - -i32 i128_cmp(i128 a, i128 b) { - if (a.hi == b.hi && b.lo == b.lo) { - return 0; - } - if (a.hi == b.hi) { - return a.lo < b.lo ? -1 : +1; - } - return a.hi < b.hi ? -1 : +1; -} - -bool i128_eq(i128 a, i128 b) { return a.hi == b.hi && a.lo == b.lo; } -bool i128_ne(i128 a, i128 b) { return !i128_eq(a, b); } -bool i128_lt(i128 a, i128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; } -bool i128_gt(i128 a, i128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; } -bool i128_le(i128 a, i128 b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; } -bool i128_ge(i128 a, i128 b) { return a.hi == b.hi ? a.lo >= b.lo : a.hi >= b.hi; } - -i128 i128_add(i128 a, i128 b) { - i128 old_a = a; - a.lo += b.lo; - a.hi += b.hi; - if (a.lo < old_a.lo) { - a.hi += 1; - } - return a; -} -i128 i128_not(i128 a) { return i128_lo_hi(~a.lo, ~a.hi); } - -i128 i128_neg(i128 a) { - return i128_add(i128_not(a), i128_from_u64(1)); -} -i128 i128_sub(i128 a, i128 b) { - return i128_add(a, i128_neg(b)); -} -i128 i128_and(i128 a, i128 b) { return i128_lo_hi(a.lo&b.lo, a.hi&b.hi); } -i128 i128_or (i128 a, i128 b) { return i128_lo_hi(a.lo|b.lo, a.hi|b.hi); } -i128 i128_xor(i128 a, i128 b) { return i128_lo_hi(a.lo^b.lo, a.hi^b.hi); } -i128 i128_and_not(i128 a, i128 b) { return i128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); } - - -i128 i128_shl(i128 a, u32 n) { - if (n >= 128) { - return i128_lo_hi(0, 0); - } - - if (n >= 64) { - n -= 64; - a.hi = a.lo; - a.lo = 0; - } - - if (n != 0) { - u64 mask = ~(BIT128_U64_ALLBITS >> n); - - a.hi <<= n; - a.hi |= (a.lo&mask) >> (64 - n); - a.lo <<= n; - } - return a; -} - -i128 i128_shr(i128 a, u32 n) { - if (n >= 128) { - return i128_lo_hi(0, 0); - } - - if (n >= 64) { - n -= 64; - a.lo = a.hi; - a.hi = 0; - } - - if (n != 0) { - u64 mask = ~(BIT128_U64_ALLBITS << n); - a.lo >>= n; - a.lo |= (a.hi&mask) << (64 - n); - a.hi >>= n; - } - return a; -} - - -i128 i128_mul(i128 a, i128 b) { - if (a.lo == 0 && a.hi == 0) { - return i128_from_u64(0); - } else if (b.lo == 0 && b.hi == 0) { - return i128_from_u64(0); - } - if (i128_eq(a, I128_ONE)) { - return b; - } - if (i128_eq(b, I128_ONE)) { - return a; - } - - i128 res = {0}; - i128 t = b; - for (u32 i = 0; i < 128; i++) { - if ((t.lo&1) != 0) { - res = i128_add(res, i128_shl(a, i)); - } - - t = i128_shr(t, 1); - } - - return res; -} - -void i128_divide(i128 a, i128 b, i128 *quo, i128 *rem) { - // TODO(bill): Which one is correct?! -#if 1 - i128 s = i128_shr(b, 127); - b = i128_sub(i128_xor(b, s), s); - s = i128_shr(a, 127); - b = i128_sub(i128_xor(a, s), s); - - u128 n, r = {0}; - u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &n, &r); - i128 ni = *cast(i128 *)&n; - i128 ri = *cast(i128 *)&r; - - if (quo) *quo = i128_sub(i128_xor(ri, s), s); - if (rem) *rem = i128_sub(i128_xor(ni, s), s); -#else - if (i128_eq(b, I128_ZERO)) { - if (quo) *quo = i128_from_u64(a.lo/b.lo); - if (rem) *rem = I128_ZERO; - } else { - i128 n = a; - i128 d = b; - i128 x = I128_ONE; - i128 r = I128_ZERO; - - while (i128_ge(n, d) && ((i128_shr(d, 128-1).lo&1) == 0)) { - x = i128_shl(x, 1); - d = i128_shl(d, 1); - } - - while (i128_ne(x, I128_ZERO)) { - if (i128_ge(n, d)) { - n = i128_sub(n, d); - r = i128_or(r, x); - } - - x = i128_shr(x, 1); - d = i128_shr(d, 1); - } - - if (quo) *quo = r; - if (rem) *rem = n; - } -#endif -} - -i128 i128_quo(i128 a, i128 b) { - i128 res = {0}; - i128_divide(a, b, &res, NULL); - return res; -} -i128 i128_mod(i128 a, i128 b) { - i128 res = {0}; - i128_divide(a, b, NULL, &res); - return res; -} |