mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 11:49:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			526 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			526 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/***********************************************************
 | 
						|
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
 | 
						|
The Netherlands.
 | 
						|
 | 
						|
                        All Rights Reserved
 | 
						|
 | 
						|
Permission to use, copy, modify, and distribute this software and its 
 | 
						|
documentation for any purpose and without fee is hereby granted, 
 | 
						|
provided that the above copyright notice appear in all copies and that
 | 
						|
both that copyright notice and this permission notice appear in 
 | 
						|
supporting documentation, and that the names of Stichting Mathematisch
 | 
						|
Centrum or CWI not be used in advertising or publicity pertaining to
 | 
						|
distribution of the software without specific, written prior permission.
 | 
						|
 | 
						|
STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
 | 
						|
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | 
						|
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
 | 
						|
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 | 
						|
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 | 
						|
******************************************************************/
 | 
						|
 | 
						|
/* 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 "allobjects.h"
 | 
						|
#include "modsupport.h"
 | 
						|
 | 
						|
#include <errno.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include "mymath.h"
 | 
						|
 | 
						|
#ifdef i860
 | 
						|
/* Cray APP has bogus definition of HUGE_VAL in <math.h> */
 | 
						|
#undef HUGE_VAL
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(HUGE_VAL) && !defined(CHECK)
 | 
						|
#define CHECK(x) if (errno != 0) ; \
 | 
						|
	else if (-HUGE_VAL <= (x) && (x) <= HUGE_VAL) ; \
 | 
						|
	else errno = ERANGE
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef CHECK
 | 
						|
#define CHECK(x) /* Don't know how to check */
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef HAVE_LIMITS_H
 | 
						|
#include <limits.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef LONG_MAX
 | 
						|
#define LONG_MAX 0X7FFFFFFFL
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef LONG_MIN
 | 
						|
#define LONG_MIN (-LONG_MAX-1)
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef __NeXT__
 | 
						|
#ifdef __sparc__
 | 
						|
/*
 | 
						|
 * This works around a bug in the NS/Sparc 3.3 pre-release
 | 
						|
 * limits.h header file.
 | 
						|
 * 10-Feb-1995 bwarsaw@cnri.reston.va.us
 | 
						|
 */
 | 
						|
#undef LONG_MIN
 | 
						|
#define LONG_MIN (-LONG_MAX-1)
 | 
						|
#endif
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined(__STDC__) && !defined(macintosh)
 | 
						|
extern double fmod PROTO((double, double));
 | 
						|
extern double pow PROTO((double, double));
 | 
						|
#endif
 | 
						|
 | 
						|
object *
 | 
						|
#ifdef __SC__
 | 
						|
newfloatobject(double fval)
 | 
						|
#else
 | 
						|
newfloatobject(fval)
 | 
						|
	double fval;
 | 
						|
#endif
 | 
						|
{
 | 
						|
	/* For efficiency, this code is copied from newobject() */
 | 
						|
	register floatobject *op = (floatobject *) malloc(sizeof(floatobject));
 | 
						|
	if (op == NULL)
 | 
						|
		return err_nomem();
 | 
						|
	op->ob_type = &Floattype;
 | 
						|
	op->ob_fval = fval;
 | 
						|
	NEWREF(op);
 | 
						|
	return (object *) op;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
float_dealloc(op)
 | 
						|
	object *op;
 | 
						|
{
 | 
						|
	DEL(op);
 | 
						|
}
 | 
						|
 | 
						|
double
 | 
						|
getfloatvalue(op)
 | 
						|
	object *op;
 | 
						|
{
 | 
						|
	number_methods *nb;
 | 
						|
	floatobject *fo;
 | 
						|
	double val;
 | 
						|
	
 | 
						|
	if (op && is_floatobject(op))
 | 
						|
		return GETFLOATVALUE((floatobject*) op);
 | 
						|
	
 | 
						|
	if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
 | 
						|
	    nb->nb_float == NULL) {
 | 
						|
		err_badarg();
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	
 | 
						|
	fo = (floatobject*) (*nb->nb_float) (op);
 | 
						|
	if (fo == NULL)
 | 
						|
		return -1;
 | 
						|
	if (!is_floatobject(fo)) {
 | 
						|
		err_setstr(TypeError, "nb_float should return float object");
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
	
 | 
						|
	val = GETFLOATVALUE(fo);
 | 
						|
	DECREF(fo);
 | 
						|
	
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
/* Methods */
 | 
						|
 | 
						|
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(Py_CHARMASK(*cp)))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	if (*cp == '\0') {
 | 
						|
		*cp++ = '.';
 | 
						|
		*cp++ = '0';
 | 
						|
		*cp++ = '\0';
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/* ARGSUSED */
 | 
						|
static int
 | 
						|
float_print(v, fp, flags)
 | 
						|
	floatobject *v;
 | 
						|
	FILE *fp;
 | 
						|
	int flags; /* Not used but required by interface */
 | 
						|
{
 | 
						|
	char buf[100];
 | 
						|
	float_buf_repr(buf, v);
 | 
						|
	fputs(buf, fp);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
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 long
 | 
						|
float_hash(v)
 | 
						|
	floatobject *v;
 | 
						|
{
 | 
						|
	double intpart, fractpart;
 | 
						|
	int expo;
 | 
						|
	long x;
 | 
						|
	/* This is designed so that Python numbers with the same
 | 
						|
	   value hash to the same value, otherwise comparisons
 | 
						|
	   of mapping keys will turn out weird */
 | 
						|
 | 
						|
#ifdef MPW /* MPW C modf expects pointer to extended as second argument */
 | 
						|
{
 | 
						|
	extended e;
 | 
						|
	fractpart = modf(v->ob_fval, &e);
 | 
						|
	intpart = e;
 | 
						|
}
 | 
						|
#else
 | 
						|
	fractpart = modf(v->ob_fval, &intpart);
 | 
						|
#endif
 | 
						|
 | 
						|
	if (fractpart == 0.0) {
 | 
						|
		if (intpart > 0x7fffffffL || -intpart > 0x7fffffffL) {
 | 
						|
			/* Convert to long int and use its hash... */
 | 
						|
			object *w = dnewlongobject(v->ob_fval);
 | 
						|
			if (w == NULL)
 | 
						|
				return -1;
 | 
						|
			x = hashobject(w);
 | 
						|
			DECREF(w);
 | 
						|
			return x;
 | 
						|
		}
 | 
						|
		x = (long)intpart;
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		fractpart = frexp(fractpart, &expo);
 | 
						|
		fractpart = fractpart*2147483648.0; /* 2**31 */
 | 
						|
		x = (long) (intpart + fractpart) ^ expo; /* Rather arbitrary */
 | 
						|
	}
 | 
						|
	if (x == -1)
 | 
						|
		x = -2;
 | 
						|
	return x;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_add(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	return newfloatobject(v->ob_fval + w->ob_fval);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_sub(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	return newfloatobject(v->ob_fval - w->ob_fval);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_mul(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	return newfloatobject(v->ob_fval * w->ob_fval);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_div(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	if (w->ob_fval == 0) {
 | 
						|
		err_setstr(ZeroDivisionError, "float division");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return newfloatobject(v->ob_fval / w->ob_fval);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_rem(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	double vx, wx;
 | 
						|
	double /* div, */ mod;
 | 
						|
	wx = w->ob_fval;
 | 
						|
	if (wx == 0.0) {
 | 
						|
		err_setstr(ZeroDivisionError, "float modulo");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	vx = v->ob_fval;
 | 
						|
	mod = fmod(vx, wx);
 | 
						|
	/* div = (vx - mod) / wx; */
 | 
						|
	if (wx*mod < 0) {
 | 
						|
		mod += wx;
 | 
						|
		/* div -= 1.0; */
 | 
						|
	}
 | 
						|
	return newfloatobject(mod);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_divmod(v, w)
 | 
						|
	floatobject *v;
 | 
						|
	floatobject *w;
 | 
						|
{
 | 
						|
	double vx, wx;
 | 
						|
	double div, mod;
 | 
						|
	wx = w->ob_fval;
 | 
						|
	if (wx == 0.0) {
 | 
						|
		err_setstr(ZeroDivisionError, "float divmod()");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	vx = v->ob_fval;
 | 
						|
	mod = fmod(vx, wx);
 | 
						|
	div = (vx - mod) / wx;
 | 
						|
	if (wx*mod < 0) {
 | 
						|
		mod += wx;
 | 
						|
		div -= 1.0;
 | 
						|
	}
 | 
						|
	return mkvalue("(dd)", div, mod);
 | 
						|
}
 | 
						|
 | 
						|
static double powu(x, n)
 | 
						|
	double x;
 | 
						|
	long n;
 | 
						|
{
 | 
						|
	double r = 1.;
 | 
						|
	double p = x;
 | 
						|
	long mask = 1;
 | 
						|
	while (mask > 0 && n >= mask) {
 | 
						|
		if (n & mask)
 | 
						|
			r *= p;
 | 
						|
		mask <<= 1;
 | 
						|
		p *= p;
 | 
						|
	}
 | 
						|
	return r;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_pow(v, w, z)
 | 
						|
	floatobject *v;
 | 
						|
	object *w;
 | 
						|
	floatobject *z;
 | 
						|
{
 | 
						|
	double iv, iw, ix;
 | 
						|
	long intw;
 | 
						|
 /* XXX Doesn't handle overflows if z!=None yet; it may never do so :(
 | 
						|
  * The z parameter is really only going to be useful for integers and
 | 
						|
  * long integers.  Maybe something clever with logarithms could be done.
 | 
						|
  * [AMK]
 | 
						|
  */
 | 
						|
	iv = v->ob_fval;
 | 
						|
	iw = ((floatobject *)w)->ob_fval;
 | 
						|
	intw = (long)iw;
 | 
						|
	if (iw == intw && -10000 < intw && intw < 10000) {
 | 
						|
		/* Sort out special cases here instead of relying on pow() */
 | 
						|
		if (intw == 0) { 		/* x**0 is 1, even 0**0 */
 | 
						|
		 	if ((object *)z!=None) {
 | 
						|
			 	ix=fmod(1.0, z->ob_fval);
 | 
						|
			 	if (ix!=0 && z->ob_fval<0) ix+=z->ob_fval;
 | 
						|
			}
 | 
						|
		 	else ix=1.0;
 | 
						|
	    		return newfloatobject(ix); 
 | 
						|
		}
 | 
						|
		errno = 0;
 | 
						|
		if (intw > 0)
 | 
						|
			ix = powu(iv, intw);
 | 
						|
		else
 | 
						|
			ix = 1./powu(iv, -intw);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		/* Sort out special cases here instead of relying on pow() */
 | 
						|
		if (iv == 0.0) {
 | 
						|
			if (iw < 0.0) {
 | 
						|
				err_setstr(ValueError,
 | 
						|
					   "0.0 to a negative power");
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
			return newfloatobject(0.0);
 | 
						|
		}
 | 
						|
		if (iv < 0.0) {
 | 
						|
			err_setstr(ValueError,
 | 
						|
				   "negative number to a float power");
 | 
						|
			return NULL;
 | 
						|
		}
 | 
						|
		errno = 0;
 | 
						|
		ix = pow(iv, iw);
 | 
						|
	}
 | 
						|
	CHECK(ix);
 | 
						|
	if (errno != 0) {
 | 
						|
		/* XXX could it be another type of error? */
 | 
						|
		err_errno(OverflowError);
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
 	if ((object *)z!=None) {
 | 
						|
	 	ix=fmod(ix, z->ob_fval);	/* XXX To Be Rewritten */
 | 
						|
	 	if ( ix!=0 &&
 | 
						|
		      ((iv<0 && z->ob_fval>0) || (iv>0 && z->ob_fval<0) )) {
 | 
						|
		     ix+=z->ob_fval;
 | 
						|
		    }
 | 
						|
	}
 | 
						|
	return newfloatobject(ix);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_neg(v)
 | 
						|
	floatobject *v;
 | 
						|
{
 | 
						|
	return newfloatobject(-v->ob_fval);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_pos(v)
 | 
						|
	floatobject *v;
 | 
						|
{
 | 
						|
	INCREF(v);
 | 
						|
	return (object *)v;
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_abs(v)
 | 
						|
	floatobject *v;
 | 
						|
{
 | 
						|
	if (v->ob_fval < 0)
 | 
						|
		return float_neg(v);
 | 
						|
	else
 | 
						|
		return float_pos(v);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
float_nonzero(v)
 | 
						|
	floatobject *v;
 | 
						|
{
 | 
						|
	return v->ob_fval != 0.0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
float_coerce(pv, pw)
 | 
						|
	object **pv;
 | 
						|
	object **pw;
 | 
						|
{
 | 
						|
	if (is_intobject(*pw)) {
 | 
						|
		long x = getintvalue(*pw);
 | 
						|
		*pw = newfloatobject((double)x);
 | 
						|
		INCREF(*pv);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	else if (is_longobject(*pw)) {
 | 
						|
		*pw = newfloatobject(dgetlongvalue(*pw));
 | 
						|
		INCREF(*pv);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1; /* Can't do it */
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_int(v)
 | 
						|
	object *v;
 | 
						|
{
 | 
						|
	double x = getfloatvalue(v);
 | 
						|
	if (x < 0 ? (x = ceil(x)) < (double)LONG_MIN
 | 
						|
	          : (x = floor(x)) > (double)LONG_MAX) {
 | 
						|
		err_setstr(OverflowError, "float too large to convert");
 | 
						|
		return NULL;
 | 
						|
	}
 | 
						|
	return newintobject((long)x);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_long(v)
 | 
						|
	object *v;
 | 
						|
{
 | 
						|
	double x = getfloatvalue(v);
 | 
						|
	return dnewlongobject(x);
 | 
						|
}
 | 
						|
 | 
						|
static object *
 | 
						|
float_float(v)
 | 
						|
	object *v;
 | 
						|
{
 | 
						|
	INCREF(v);
 | 
						|
	return v;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static number_methods float_as_number = {
 | 
						|
	(binaryfunc)float_add, /*nb_add*/
 | 
						|
	(binaryfunc)float_sub, /*nb_subtract*/
 | 
						|
	(binaryfunc)float_mul, /*nb_multiply*/
 | 
						|
	(binaryfunc)float_div, /*nb_divide*/
 | 
						|
	(binaryfunc)float_rem, /*nb_remainder*/
 | 
						|
	(binaryfunc)float_divmod, /*nb_divmod*/
 | 
						|
	(ternaryfunc)float_pow, /*nb_power*/
 | 
						|
	(unaryfunc)float_neg, /*nb_negative*/
 | 
						|
	(unaryfunc)float_pos, /*nb_positive*/
 | 
						|
	(unaryfunc)float_abs, /*nb_absolute*/
 | 
						|
	(inquiry)float_nonzero, /*nb_nonzero*/
 | 
						|
	0,		/*nb_invert*/
 | 
						|
	0,		/*nb_lshift*/
 | 
						|
	0,		/*nb_rshift*/
 | 
						|
	0,		/*nb_and*/
 | 
						|
	0,		/*nb_xor*/
 | 
						|
	0,		/*nb_or*/
 | 
						|
	(coercion)float_coerce, /*nb_coerce*/
 | 
						|
	(unaryfunc)float_int, /*nb_int*/
 | 
						|
	(unaryfunc)float_long, /*nb_long*/
 | 
						|
	(unaryfunc)float_float, /*nb_float*/
 | 
						|
	0,		/*nb_oct*/
 | 
						|
	0,		/*nb_hex*/
 | 
						|
};
 | 
						|
 | 
						|
typeobject Floattype = {
 | 
						|
	OB_HEAD_INIT(&Typetype)
 | 
						|
	0,
 | 
						|
	"float",
 | 
						|
	sizeof(floatobject),
 | 
						|
	0,
 | 
						|
	(destructor)float_dealloc, /*tp_dealloc*/
 | 
						|
	(printfunc)float_print, /*tp_print*/
 | 
						|
	0,			/*tp_getattr*/
 | 
						|
	0,			/*tp_setattr*/
 | 
						|
	(cmpfunc)float_compare, /*tp_compare*/
 | 
						|
	(reprfunc)float_repr, /*tp_repr*/
 | 
						|
	&float_as_number,	/*tp_as_number*/
 | 
						|
	0,			/*tp_as_sequence*/
 | 
						|
	0,			/*tp_as_mapping*/
 | 
						|
	(hashfunc)float_hash, /*tp_hash*/
 | 
						|
};
 |