#include "exc.h"
#include "consts.h"
#include "builtin.h"
#include "model.h"
#include "exc.h"
#include <cstdio>
#include <sstream>
#include <cctype>
#include <cstdlib>
using std::stringstream;
extern EmptyList *empty_list;
static const int NUM_LVL_COMP = 0;
static const int NUM_LVL_REAL = 1;
static const int NUM_LVL_RAT = 2;
static const int NUM_LVL_INT = 3;
string double_to_str(double val, bool force_sign = false) {
stringstream ss;
if (force_sign) ss << std::showpos;
ss << val;
return ss.str();
}
string int_to_str(int val) {
stringstream ss;
ss << val;
return ss.str();
}
double str_to_double(string repr, bool &flag) {
const char *nptr = repr.c_str();
char *endptr;
double val = strtod(nptr, &endptr);
if (endptr != nptr + repr.length())
{
flag = false;
return 0;
}
flag = true;
return val;
}
int gcd(int a, int b) {
int t;
while (b) t = b, b = a % b, a = t;
return abs(a);
}
InexactNumObj::InexactNumObj(NumLvl level) : NumObj(level, false) {}
CompNumObj::CompNumObj(double _real, double _imag) :
InexactNumObj(NUM_LVL_COMP), real(_real), imag(_imag) {}
CompNumObj *CompNumObj::from_string(string repr) {
// spos: the position of the last sign
// ipos: the position of i
int spos = -1, ipos = -1,
len = repr.length();
bool sign;
for (int i = 0; i < len; i++)
if (repr[i] == '+' || repr[i] == '-')
{
spos = i;
sign = repr[i] == '-';
}
else if (repr[i] == 'i' || repr[i] == 'I')
ipos = i;
if (spos == -1 || ipos == -1 || !(spos < ipos))
return NULL;
bool flag;
double real = 0, imag = 1;
if (spos > 0)
{
real = str_to_double(repr.substr(0, spos), flag);
if (!flag) return NULL;
}
if (ipos > spos + 1)
{
imag = str_to_double(repr.substr(spos + 1, ipos - spos - 1), flag);
if (!flag) return NULL;
}
if (sign) imag = -imag;
return new CompNumObj(real, imag);
}
CompNumObj *CompNumObj::convert(NumObj *obj) {
switch (obj->level)
{
case NUM_LVL_COMP :
return static_cast<CompNumObj*>(obj); break;
case NUM_LVL_REAL :
return new CompNumObj(static_cast<RealNumObj*>(obj)->real, 0);
break;
case NUM_LVL_RAT :
{
RatNumObj *rat = static_cast<RatNumObj*>(obj);
return new CompNumObj(rat->a / double(rat->b), 0);
break;
}
case NUM_LVL_INT :
return new CompNumObj(static_cast<IntNumObj*>(obj)->val, 0);
}
throw NormalError(INT_ERR);
}
#define A (real)
#define B (imag)
#define C (r->real)
#define D (r->imag)
NumObj *CompNumObj::plus(NumObj *_r) {
CompNumObj *r = static_cast<CompNumObj*>(_r);
return new CompNumObj(A + C, B + D);
}
NumObj *CompNumObj::minus(NumObj *_r) {
CompNumObj *r = static_cast<CompNumObj*>(_r);
return new CompNumObj(A - C, B - D);
}
NumObj *CompNumObj::multi(NumObj *_r) {
CompNumObj *r = static_cast<CompNumObj*>(_r);
return new CompNumObj(A * C - B * D,
B * C + A * D);
}
NumObj *CompNumObj::div(NumObj *_r) {
CompNumObj *r = static_cast<CompNumObj*>(_r);
double f = 1.0 / (C * C + D * D);
return new CompNumObj((A * C + B * D) * f,
(B * C - A * D) * f);
}
bool CompNumObj::lt(NumObj *_r) {
throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
}
bool CompNumObj::gt(NumObj *_r) {
throw TokenError("a comparable number", RUN_ERR_WRONG_TYPE);
}
bool CompNumObj::eq(NumObj *_r) {
CompNumObj *r = static_cast<CompNumObj*>(_r);
return A == C && B == D; // TODO: more proper judgement
}
string CompNumObj::ext_repr() {
return double_to_str(real) + double_to_str(imag, true) + "i";
}
#undef A