/* Float object implementation */ /* XXX There should be overflow checks here, but it's hard to check for any kind of float exception without losing portability. */ #include #include #include #include "PROTO.h" #include "object.h" #include "floatobject.h" #include "stringobject.h" #include "objimpl.h" #include "errors.h" #ifndef THINK_C extern double fmod PROTO((double, double)); extern double pow PROTO((double, double)); #endif object * newfloatobject(fval) double fval; { /* For efficiency, this code is copied from newobject() */ register floatobject *op = (floatobject *) malloc(sizeof(floatobject)); if (op == NULL) return err_nomem(); NEWREF(op); op->ob_type = &Floattype; op->ob_fval = fval; return (object *) op; } double getfloatvalue(op) object *op; { if (!is_floatobject(op)) { err_badarg(); return -1; } else return ((floatobject *)op) -> ob_fval; } /* Methods */ static void float_buf_repr(buf, v) char *buf; floatobject *v; { register char *cp; /* Subroutine for float_repr and float_print. We want float numbers to be recognizable as such, i.e., they should contain a decimal point or an exponent. However, %g may print the number as an integer; in such cases, we append ".0" to the string. */ sprintf(buf, "%.12g", v->ob_fval); cp = buf; if (*cp == '-') cp++; for (; *cp != '\0'; cp++) { /* Any non-digit means it's not an integer; this takes care of NAN and INF as well. */ if (!isdigit(*cp)) break; } if (*cp == '\0') { *cp++ = '.'; *cp++ = '0'; *cp++ = '\0'; } } static void float_print(v, fp, flags) floatobject *v; FILE *fp; int flags; { char buf[100]; float_buf_repr(buf, v); fputs(buf, fp); } static object * float_repr(v) floatobject *v; { char buf[100]; float_buf_repr(buf, v); return newstringobject(buf); } static int float_compare(v, w) floatobject *v, *w; { double i = v->ob_fval; double j = w->ob_fval; return (i < j) ? -1 : (i > j) ? 1 : 0; } static object * float_add(v, w) floatobject *v; object *w; { if (!is_floatobject(w)) { err_badarg(); return NULL; } return newfloatobject(v->ob_fval + ((floatobject *)w) -> ob_fval); } static object * float_sub(v, w) floatobject *v; object *w; { if (!is_floatobject(w)) { err_badarg(); return NULL; } return newfloatobject(v->ob_fval - ((floatobject *)w) -> ob_fval); } static object * float_mul(v, w) floatobject *v; object *w; { if (!is_floatobject(w)) { err_badarg(); return NULL; } return newfloatobject(v->ob_fval * ((floatobject *)w) -> ob_fval); } static object * float_div(v, w) floatobject *v; object *w; { if (!is_floatobject(w)) { err_badarg(); return NULL; } if (((floatobject *)w) -> ob_fval == 0) { err_setstr(ZeroDivisionError, "float division by zero"); return NULL; } return newfloatobject(v->ob_fval / ((floatobject *)w) -> ob_fval); } static object * float_rem(v, w) floatobject *v; object *w; { double wx; if (!is_floatobject(w)) { err_badarg(); return NULL; } wx = ((floatobject *)w) -> ob_fval; if (wx == 0.0) { err_setstr(ZeroDivisionError, "float division by zero"); return NULL; } return newfloatobject(fmod(v->ob_fval, wx)); } static object * float_pow(v, w) floatobject *v; object *w; { double iv, iw, ix; if (!is_floatobject(w)) { err_badarg(); return NULL; } iv = v->ob_fval; iw = ((floatobject *)w)->ob_fval; if (iw == 0.0) return newfloatobject(1.0); /* x**0 is always 1, even 0**0 */ errno = 0; ix = pow(iv, iw); if (errno != 0) { /* XXX could it be another type of error? */ err_errno(OverflowError); return NULL; } return newfloatobject(ix); } static object * float_neg(v) floatobject *v; { return newfloatobject(-v->ob_fval); } static object * float_pos(v) floatobject *v; { return newfloatobject(v->ob_fval); } static number_methods float_as_number = { float_add, /*tp_add*/ float_sub, /*tp_subtract*/ float_mul, /*tp_multiply*/ float_div, /*tp_divide*/ float_rem, /*tp_remainder*/ float_pow, /*tp_power*/ float_neg, /*tp_negate*/ float_pos, /*tp_plus*/ }; typeobject Floattype = { OB_HEAD_INIT(&Typetype) 0, "float", sizeof(floatobject), 0, free, /*tp_dealloc*/ float_print, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ float_compare, /*tp_compare*/ float_repr, /*tp_repr*/ &float_as_number, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ }; /* XXX This is not enough. Need: - automatic casts for mixed arithmetic (3.1 * 4) - mixed comparisons (!) - look at other uses of ints that could be extended to floats */