#include #include #define CHECK_OVERFLOW(r) \ if (abs(r->num) > 0x7fffffff || abs(r->den) > 0x7fffffff) \ { r->num = 0; r->den = 0; } #define Check_Undef(r,res) if (r->den==0) {res->num=0; res->den=0; return res;} #define UNIQUE_ZERO(r) if(r->num==0) r->den=1; /* if not defined then ... typedef long long int64; typedef unsigned long long uint64; */ typedef struct rational { int64 num; uint64 den; } rational; uint64 gcd (uint64 a, uint64 b) { int64 c; if (a==0 || b==0) return -1; if (b>a) { c=a; a=b; b=c; } while (b) { c = a % b; a = b; b = c; } return a; } rational *rational_in(char *str) { int64 i = 0; int64 g; rational *result = (rational *) palloc(sizeof(rational)); result->num = 0; while (str[i] >= '0' && str[i] <= '9') result->num = 10*result->num + (str[i++] - '0'); while (str[i] && !(str[i] >= '0' && str[i] <= '9')) i++; if (!str[i]) { result->den = 1; CHECK_OVERFLOW(result); return result; } result->den = 0; while (str[i] >= '0' && str[i] <= '9') result->den = 10*result->den + (str[i++] - '0'); g = gcd (result->num, result->den); if (g>1) { result->num /= g; result->den /= g; } UNIQUE_ZERO(result); CHECK_OVERFLOW(result); return result; } char *rational_out(rational *r) { int64 size = snprintf(NULL, 0, "%lld/%lld", r->num, r->den); char *result = (char*) palloc (size+1); result[size]=0; snprintf(result, size+1, "%lld/%lld", r->num, r->den); return result; } bool rational_eq(rational *a, rational *b) { return a->num*b->den == b->num*a->den; } bool rational_ne(rational *a, rational *b) { return a->num*b->den != b->num*a->den; } bool rational_gt(rational *a, rational *b) { return a->num*b->den > b->num*a->den; } bool rational_ge(rational *a, rational *b) { return a->num*b->den >= b->num*a->den; } bool rational_lt(rational *a, rational *b) { return a->num*b->den < b->num*a->den; } bool rational_le(rational *a, rational *b) { return a->num*b->den <= b->num*a->den; } rational *rational_add(rational *a, rational *b) { int64 g = gcd (a->den, b->den); rational *result = (rational *) palloc(sizeof(rational)); Check_Undef(a, result); Check_Undef(b, result); if (g==-1) { result->num = 0; result->den = 0; } else { result->num = a->num*b->den/g + b->num*a->den/g; result->den = a->den*b->den/g; } UNIQUE_ZERO(result); CHECK_OVERFLOW(result); return result; } rational *rational_sub(rational *a, rational *b) { int64 g = gcd (a->den, b->den); rational *result = (rational *) palloc(sizeof(rational)); Check_Undef(a, result); Check_Undef(b, result); if (g==-1) { result->num = 0; result->den = 0; } else { result->num = a->num*b->den/g - b->num*a->den/g; result->den = a->den*b->den/g; } UNIQUE_ZERO(result); CHECK_OVERFLOW(result); return result; } rational *rational_mult(rational *a, rational *b) { int64 g; rational *result = (rational *) palloc(sizeof(rational)); Check_Undef(a, result); Check_Undef(b, result); result->num = a->num*b->num; result->den = a->den*b->den; g = gcd (abs(result->num), result->den); if (g==-1) { result->num = 0; result->den = 0; } else { result->num /= g; result->den /= g; } UNIQUE_ZERO(result); CHECK_OVERFLOW(result); return result; } rational *rational_div(rational *a, rational *b) { rational *result = (rational *) palloc(sizeof(rational)); int64 g; Check_Undef(a, result); Check_Undef(b, result); if (b->num == 0) { result->num = 0; result->den = 0; return result; } if (b->num < 0) { result->num = a->num*(-b->den); result->den = a->den*(-b->num); } else { result->num = a->num*b->den; result->den = a->den*b->num; } g = gcd (abs(result->num), result->den); if (g==-1) { result->num = 0; result->den = 0; } else { result->num /= g; result->den /= g; } UNIQUE_ZERO(result); CHECK_OVERFLOW(result); return result; }