/* We use two's complement Adding the value Adding a positive number to a negative number is actually subtracting the value. Last bit is a biggest possible negative number for that bit range. 0111 1111 => 127 1111 1111 => -128 - 127 = 1 1000 0000 => -128 if we add 4 we get 1000 0100 => -124 Negating the value 1000 0001 => -127 flip bits 0111 1110 => 126 we need to add 1 0111 1111 -> 127 */ struct S128{U64 hi, lo;}; function S64 is_negative(S128 v){ S64 result = v.hi >> 63; return result; } function S64 sign(S128 val){ S64 result = is_negative(val) ? -1 : 1; return result; } function S128 s128(S64 value){ S128 result = {value < 0 ? ~0 : 0ull, (U64)value}; return result; } function S128 s128_from_u64(U64 value){ S128 result = {0, value}; return result; } function S128 operator+(S128 a, S128 b){ U64 lo = a.lo + b.lo; U64 hi = a.hi + b.hi + (a.lo > lo); // (a.lo > lo) is carry return {hi,lo}; } function S128 operator-(S128 a, S128 b){ U64 lo = a.lo - b.lo; U64 hi = a.hi - b.hi - (a.lo < lo); // (a.lo < lo) is carry return {hi,lo}; } force_inline U64 lo32(U64 a){return a & 0xffffffff;} force_inline U64 hi32(U64 a){return a >> 32;} force_inline S128 operator~(S128 a){return {~a.hi, ~a.lo};} force_inline S128 operator^(S128 a, S128 b){return {a.hi ^ b.hi, a.lo ^ b.lo};} force_inline S128 operator&(S128 a, S128 b){return {a.hi & b.hi, a.lo & b.lo};} force_inline S128 operator|(S128 a, S128 b){return {a.hi | b.hi, a.lo | b.lo};} function S128 operator-(S128 a){ a = (~a) + s128(1); return a; } /* U64 u1 = lo32(u); U64 v1 = lo32(v); U64 t = u1 * v1; U64 w3 = lo32(t); U64 k = hi32(t); u >>= 32; t = u * v1 + k; k = lo32(t); U64 w1 = hi32(t); v >>= 32; t = u1 * v + k; return { (u * v) + w1 + hi32(t), (t << 32) + w3 }; */ void mult64to128(U64 u, U64 v, U64& h, U64 &l) { U64 u1 = (u & 0xffffffff); U64 v1 = (v & 0xffffffff); U64 t = (u1 * v1); U64 w3 = (t & 0xffffffff); // w3 = t1_lo U64 k = (t >> 32); // k = t1_hi u >>= 32; // u_hi t = (u * v1) + k; // t2 = (u_hi * v_lo) + t1_hi k = (t & 0xffffffff); // t2_lo U64 w1 = (t >> 32); // t2_hi v >>= 32; t = (u1 * v) + k; // t3 = (u_lo * v_hi) + t2_lo k = (t >> 32); // t3_hi h = (u * v) + w1 + k; l = (t << 32) + w3; } function S128 u64_mul(U64 u, U64 v){ U64 u_lo = lo32(u); U64 v_lo = lo32(v); U64 u_hi = hi32(u); U64 v_hi = hi32(v); U64 t1 = u_lo * v_lo; U64 t1_lo = lo32(t1); U64 t1_hi = hi32(t1); U64 t2 = (u_hi * v_lo) + t1_hi; U64 t2_lo = lo32(t2); U64 t2_hi = hi32(t2); U64 t3 = (u_lo * v_hi) + t2_lo; U64 t3_hi = hi32(t3); U64 lo = (t3 << 32) + t1_lo; U64 hi = (u_hi * v_hi) + t2_hi + t3_hi; return {hi,lo}; } function S128 operator*(S128 a, S128 b){ S128 c = u64_mul(a.lo, b.lo); c.hi += (a.hi * b.lo) + (a.lo * b.hi); return c; } function void test_big_int(){ S128 v1 = s128(-1); assert(v1.hi == U64MAX && v1.lo == U64MAX); assert(is_negative(v1)); assert(sign(v1) == -1); S128 v2 = s128_from_u64(U64MAX) + s128_from_u64(1); assert(v2.lo == 0 && v2.hi == 1); S128 v3 = s128_from_u64(U64MAX) + s128_from_u64(100); assert(v3.lo == 99 && v3.hi == 1); // S64 s64_max = S64MAX; S128 v4 = s128(S64MIN) + s128_from_u64(100); assert((v4.lo - S64MAX) == 101); // 101 cause S64MIN is larher by 1 S128 v5 = {1, 0}; S128 v6 = v5 - s128(1); assert(v6.lo == U64MAX && v6.hi == 0); { S128 v7 = u64_mul(S64MAX, S64MAX); U64 a,b; mult64to128(S64MAX,S64MAX,a,b); assert(v7.hi == a && v7.lo == b); } { S128 v7 = u64_mul(S64MIN, S64MIN); U64 a,b; mult64to128(S64MIN,S64MIN,a,b); assert(v7.hi == a && v7.lo == b); } { S128 v7 = u64_mul(15125125, -1424124); U64 a,b; mult64to128(15125125,-1424124,a,b); assert(v7.hi == a && v7.lo == b); } { S128 v7 = u64_mul(52242, 2); U64 a,b; mult64to128(52242, 2,a,b); assert(v7.hi == a && v7.lo == b); assert(v7.lo == 52242*2); } }