/* -*- mode: c; c-basic-offset: 8 -*- */ /* num_co.c -- Operations on floating-point numbers. */ /* Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya. Copyright (c) 1990, Giuseppe Attardi. Copyright (c) 2001, Juan Jose Garcia Ripoll. ECL is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See file '../Copyright' for full details. */ /* IMPLEMENTATION-DEPENDENT This file contains those functions that know the representation of floating-point numbers. */ #define ECL_INCLUDE_MATH_H #include #include #ifndef HAVE_ISOC99 # define floorf floor # define ceilf ceil # define fabsf fabs # define frexpf frexp # define ldexpf ldexp # define cosf cos # define coshf cosh # define expf exp # define logf log # define sinf sin # define sqrtf sqrt # define tanf tan # define tanhf tanh #endif #include static cl_object number_remainder(cl_object x, cl_object y, cl_object q) { cl_object z; z = ecl_times(q, y); z = ecl_minus(x, z); return(z); } /* Coerce X to single-float if one arg, otherwise coerce to same float type as second arg */ @(defun float (x &optional (y OBJNULL)) cl_type ty, tx; @ if (y != OBJNULL) { ty = ecl_t_of(y); } else { ty = t_singlefloat; } switch (tx = ecl_t_of(x)) { case t_singlefloat: case t_doublefloat: #ifdef ECL_LONG_FLOAT case t_longfloat: #endif if (y == OBJNULL || ty == tx) break; case t_fixnum: case t_bignum: case t_ratio: switch (ty) { case t_singlefloat: x = ecl_make_single_float(ecl_to_double(x)); break; case t_doublefloat: x = ecl_make_double_float(ecl_to_double(x)); break; #ifdef ECL_LONG_FLOAT case t_longfloat: x = ecl_make_long_float(ecl_to_long_double(x)); break; #endif default: FEwrong_type_nth_arg(@[float],2,y,@[float]); } break; default: FEwrong_type_nth_arg(@[float],1,x,@[real]); } @(return x) @) cl_object cl_numerator(cl_object x) { switch (ecl_t_of(x)) { case t_ratio: x = x->ratio.num; break; case t_fixnum: case t_bignum: break; default: FEwrong_type_nth_arg(@[numerator],1,x,@[rational]); } @(return x) } cl_object cl_denominator(cl_object x) { switch (ecl_t_of(x)) { case t_ratio: x = x->ratio.den; break; case t_fixnum: case t_bignum: x = ecl_make_fixnum(1); break; default: FEwrong_type_nth_arg(@[numerator],1,x,@[rational]); } @(return x) } cl_object ecl_floor1(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: v0 = x; v1 = ecl_make_fixnum(0); break; case t_ratio: v0 = ecl_floor2(x->ratio.num, x->ratio.den); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), x->ratio.den); break; case t_singlefloat: { float d = ecl_single_float(x); float y = floorf(d); v0 = _ecl_float_to_integer(y); v1 = ecl_make_single_float(d - y); break; } case t_doublefloat: { double d = ecl_double_float(x); double y = floor(d); v0 = _ecl_double_to_integer(y); v1 = ecl_make_double_float(d - y); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); long double y = floorl(d); v0 = _ecl_long_double_to_integer(y); v1 = ecl_make_long_float(d - y); break; } #endif default: FEwrong_type_nth_arg(@[floor],1,x,@[real]); } ecl_return2(the_env, v0, v1); } cl_object ecl_floor2(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; cl_type ty; ty = ecl_t_of(y); if (ecl_unlikely(!ECL_REAL_TYPE_P(ty))) { FEwrong_type_nth_arg(@[floor],2,y,@[real]); } switch(ecl_t_of(x)) { case t_fixnum: switch(ty) { case t_fixnum: { /* FIX / FIX */ cl_fixnum a = ecl_fixnum(x), b = ecl_fixnum(y); cl_fixnum q = a / b, r = a % b; if ((r^b) < 0 && r) { /* opposite sign and some remainder*/ v0 = ecl_make_fixnum(q-1); v1 = ecl_make_fixnum(r+b); } else { v0 = ecl_make_fixnum(q); v1 = ecl_make_fixnum(r); } break; } case t_bignum: { /* FIX / BIG */ /* We must perform the division because there is the * pathological case * x = MOST_NEGATIVE_FIXNUM * y = - MOST_NEGATIVE_FIXNUM */ ECL_WITH_TEMP_BIGNUM(bx,4); _ecl_big_set_fixnum(bx, ecl_fixnum(x)); v0 = _ecl_big_floor(bx, y, &v1); break; } case t_ratio: /* FIX / RAT */ v0 = ecl_floor2(ecl_times(x, y->ratio.den), y->ratio.num); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), y->ratio.den); break; case t_singlefloat: { /* FIX / SF */ float n = ecl_single_float(y); float p = ecl_fixnum(x) / n; float q = floorf(p); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float((p - q)*n); break; } case t_doublefloat: { /* FIX / DF */ double n = ecl_double_float(y); double p = ecl_fixnum(x) / n; double q = floor(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float((p - q)*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* FIX / LF */ long double n = ecl_long_float(y); long double p = ecl_fixnum(x) / n; long double q = floorl(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float((p - q)*n); break; } #endif default: (void)0; /* Never reached */ } break; case t_bignum: switch(ty) { case t_fixnum: { /* BIG / FIX */ ECL_WITH_TEMP_BIGNUM(by,4); _ecl_big_set_fixnum(by, ecl_fixnum(y)); v0 = _ecl_big_floor(x, by, &v1); break; } case t_bignum: { /* BIG / BIG */ v0 = _ecl_big_floor(x, y, &v1); break; } case t_ratio: /* BIG / RAT */ v0 = ecl_floor2(ecl_times(x, y->ratio.den), y->ratio.num); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), y->ratio.den); break; case t_singlefloat: { /* BIG / SF */ float n = ecl_single_float(y); float p = _ecl_big_to_double(x) / n; float q = floorf(p); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float((p - q)*n); break; } case t_doublefloat: { /* BIG / DF */ double n = ecl_double_float(y); double p = _ecl_big_to_double(x) / n; double q = floor(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float((p - q)*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* BIG / LF */ long double n = ecl_long_float(y); long double p = _ecl_big_to_double(x) / n; long double q = floorl(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float((p - q)*n); break; } #endif default: (void)0; /* Never reached */ } break; case t_ratio: switch(ty) { case t_ratio: /* RAT / RAT */ v0 = ecl_floor2(ecl_times(x->ratio.num, y->ratio.den), ecl_times(x->ratio.den, y->ratio.num)); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), ecl_times(x->ratio.den, y->ratio.den)); break; default: /* RAT / ANY */ v0 = ecl_floor2(x->ratio.num, ecl_times(x->ratio.den, y)); v1 = ecl_divide(ecl_nth_value(the_env, 1), x->ratio.den); } break; case t_singlefloat: { /* SF / ANY */ float n = ecl_to_double(y); float p = ecl_single_float(x)/n; float q = floorf(p); v0 = _ecl_float_to_integer(q); /* We cannot factor these two multiplications because * if we have signed zeros (1 - 1) * (-1) = -0 while * 1*(-1) - 1*(-1) = +0 */ v1 = ecl_make_single_float(p*n - q*n); break; } case t_doublefloat: { /* DF / ANY */ double n = ecl_to_double(y); double p = ecl_double_float(x)/n; double q = floor(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float(p*n - q*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* LF / ANY */ long double n = ecl_to_long_double(y); long double p = ecl_long_float(x)/n; long double q = floorl(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float(p*n - q*n); break; } #endif default: FEwrong_type_nth_arg(@[floor], 1, x, @[real]); } ecl_return2(the_env, v0, v1); } @(defun floor (x &optional (y OBJNULL)) @ if (narg == 1) return ecl_floor1(x); else return ecl_floor2(x, y); @) cl_object ecl_ceiling1(cl_object x) { cl_object v0, v1; switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: v0 = x; v1 = ecl_make_fixnum(0); break; case t_ratio: { const cl_env_ptr the_env = ecl_process_env(); v0 = ecl_ceiling2(x->ratio.num, x->ratio.den); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), x->ratio.den); break; } case t_singlefloat: { float d = ecl_single_float(x); float y = ceilf(d); v0 = _ecl_float_to_integer(y); v1 = ecl_make_single_float(d - y); break; } case t_doublefloat: { double d = ecl_double_float(x); double y = ceil(d); v0 = _ecl_double_to_integer(y); v1 = ecl_make_double_float(d - y); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); long double y = ceill(d); v0 = _ecl_long_double_to_integer(y); v1 = ecl_make_long_float(d - y); break; } #endif default: FEwrong_type_nth_arg(@[ceiling],1,x,@[real]); } @(return v0 v1) } cl_object ecl_ceiling2(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; cl_type ty; ty = ecl_t_of(y); if (ecl_unlikely(!ECL_REAL_TYPE_P(ty))) { FEwrong_type_nth_arg(@[ceiling],2, y, @[real]); } switch(ecl_t_of(x)) { case t_fixnum: switch(ty) { case t_fixnum: { /* FIX / FIX */ cl_fixnum a = ecl_fixnum(x); cl_fixnum b = ecl_fixnum(y); cl_fixnum q = a / b; cl_fixnum r = a % b; if ((r^b) > 0 && r) { /* same signs and some remainder */ v0 = ecl_make_fixnum(q+1); v1 = ecl_make_fixnum(r-b); } else { v0 = ecl_make_fixnum(q); v1 = ecl_make_fixnum(r); } break; } case t_bignum: { /* FIX / BIG */ /* We must perform the division because there is the * pathological case * x = MOST_NEGATIVE_FIXNUM * y = - MOST_NEGATIVE_FIXNUM */ ECL_WITH_TEMP_BIGNUM(bx,4); _ecl_big_set_fixnum(bx, ecl_fixnum(x)); v0 = _ecl_big_ceiling(bx, y, &v1); break; } case t_ratio: /* FIX / RAT */ v0 = ecl_ceiling2(ecl_times(x, y->ratio.den), y->ratio.num); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), y->ratio.den); break; case t_singlefloat: { /* FIX / SF */ float n = ecl_single_float(y); float p = ecl_fixnum(x)/n; float q = ceilf(p); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float(p*n - q*n); break; } case t_doublefloat: { /* FIX / DF */ double n = ecl_double_float(y); double p = ecl_fixnum(x)/n; double q = ceil(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float(p*n - q*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* FIX / LF */ long double n = ecl_long_float(y); long double p = ecl_fixnum(x)/n; long double q = ceill(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float(p*n - q*n); break; } #endif default: (void)0; /*Never reached */ } break; case t_bignum: switch(ecl_t_of(y)) { case t_fixnum: { /* BIG / FIX */ ECL_WITH_TEMP_BIGNUM(by,4); _ecl_big_set_fixnum(by, ecl_fixnum(y)); v0 = _ecl_big_ceiling(x, by, &v1); break; } case t_bignum: { /* BIG / BIG */ v0 = _ecl_big_ceiling(x, y, &v1); break; } case t_ratio: /* BIG / RAT */ v0 = ecl_ceiling2(ecl_times(x, y->ratio.den), y->ratio.num); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), y->ratio.den); break; case t_singlefloat: { /* BIG / SF */ float n = ecl_single_float(y); float p = _ecl_big_to_double(x)/n; float q = ceilf(p); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float(p*n - q*n); break; } case t_doublefloat: { /* BIG / DF */ double n = ecl_double_float(y); double p = _ecl_big_to_double(x)/n; double q = ceil(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float(p*n - q*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* BIG / LF */ long double n = ecl_long_float(y); long double p = _ecl_big_to_double(x)/n; long double q = ceill(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float(p*n - q*n); break; } #endif default: (void)0; /*Never reached */ } break; case t_ratio: switch(ecl_t_of(y)) { case t_ratio: /* RAT / RAT */ v0 = ecl_ceiling2(ecl_times(x->ratio.num, y->ratio.den), ecl_times(x->ratio.den, y->ratio.num)); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), ecl_times(x->ratio.den, y->ratio.den)); break; default: /* RAT / ANY */ v0 = ecl_ceiling2(x->ratio.num, ecl_times(x->ratio.den, y)); v1 = ecl_divide(ecl_nth_value(the_env, 1), x->ratio.den); } break; case t_singlefloat: { /* SF / ANY */ float n = ecl_to_double(y); float p = ecl_single_float(x)/n; float q = ceilf(p); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float(p*n - q*n); break; } case t_doublefloat: { /* DF / ANY */ double n = ecl_to_double(y); double p = ecl_double_float(x)/n; double q = ceil(p); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float(p*n - q*n); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { /* LF / ANY */ long double n = ecl_to_long_double(y); long double p = ecl_long_float(x)/n; long double q = ceill(p); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float(p*n - q*n); break; } #endif default: FEwrong_type_nth_arg(@[ceiling], 1, x, @[real]); } ecl_return2(the_env, v0, v1); } @(defun ceiling (x &optional (y OBJNULL)) @ if (narg == 1) return ecl_ceiling1(x); else return ecl_ceiling2(x, y); @) cl_object ecl_truncate1(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: v0 = x; v1 = ecl_make_fixnum(0); break; case t_ratio: v0 = ecl_truncate2(x->ratio.num, x->ratio.den); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), x->ratio.den); break; case t_singlefloat: { float d = ecl_single_float(x); float y = d > 0? floorf(d) : ceilf(d); v0 = _ecl_float_to_integer(y); v1 = ecl_make_single_float(d - y); break; } case t_doublefloat: { double d = ecl_double_float(x); double y = d > 0? floor(d) : ceil(d); v0 = _ecl_double_to_integer(y); v1 = ecl_make_double_float(d - y); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); long double y = d > 0? floorl(d) : ceill(d); v0 = _ecl_long_double_to_integer(y); v1 = ecl_make_long_float(d - y); break; } #endif default: FEwrong_type_nth_arg(@[truncate],1,x,@[real]); } ecl_return2(the_env, v0, v1); } cl_object ecl_truncate2(cl_object x, cl_object y) { if (ecl_plusp(x) != ecl_plusp(y)) return ecl_ceiling2(x, y); else return ecl_floor2(x, y); } @(defun truncate (x &optional (y OBJNULL)) @ if (narg == 1) return ecl_truncate1(x); else return ecl_truncate2(x, y); @) static double round_double(double d) { if (d >= 0) { double q = floor(d += 0.5); if (q == d) { int i = (int)fmod(q, 10); if (i & 1) { return q-1; } } return q; } else { return -round_double(-d); } } #ifdef ECL_LONG_FLOAT static long double round_long_double(long double d) { if (d >= 0) { long double q = floorl(d += 0.5); if (q == d) { int i = (int)fmodl(q, 10); if (i & 1) { return q-1; } } return q; } else { return -round_long_double(-d); } } #endif cl_object ecl_round1(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: v0 = x; v1 = ecl_make_fixnum(0); break; case t_ratio: v0 = ecl_round2(x->ratio.num, x->ratio.den); v1 = ecl_make_ratio(ecl_nth_value(the_env, 1), x->ratio.den); break; case t_singlefloat: { float d = ecl_single_float(x); float q = round_double(d); v0 = _ecl_float_to_integer(q); v1 = ecl_make_single_float(d - q); break; } case t_doublefloat: { double d = ecl_double_float(x); double q = round_double(d); v0 = _ecl_double_to_integer(q); v1 = ecl_make_double_float(d - q); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); long double q = round_long_double(d); v0 = _ecl_long_double_to_integer(q); v1 = ecl_make_long_float(d - q); break; } #endif default: FEwrong_type_nth_arg(@[round],1,x,@[real]); } ecl_return2(the_env, v0, v1); } cl_object ecl_round2(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); cl_object v0, v1; cl_object q; q = ecl_divide(x, y); switch (ecl_t_of(q)) { case t_fixnum: case t_bignum: v0 = q; v1 = ecl_make_fixnum(0); break; case t_ratio: { cl_object q1 = ecl_integer_divide(q->ratio.num, q->ratio.den); cl_object r = ecl_minus(q, q1); if (ecl_minusp(r)) { int c = ecl_number_compare(cl_core.minus_half, r); if (c > 0 || (c == 0 && ecl_oddp(q1))) { q1 = ecl_one_minus(q1); } } else { int c = ecl_number_compare(r, cl_core.plus_half); if (c > 0 || (c == 0 && ecl_oddp(q1))) { q1 = ecl_one_plus(q1); } } v0 = q1; v1 = number_remainder(x, y, q1); break; } default: v0 = q = ecl_round1(q); v1 = number_remainder(x, y, q); } ecl_return2(the_env, v0, v1); } @(defun round (x &optional (y OBJNULL)) @ if (narg == 1) return ecl_round1(x); else return ecl_round2(x, y); @) cl_object cl_mod(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); /* INV: #'floor always outputs two values */ @floor(2, x, y); ecl_return1(the_env, the_env->values[1]); } cl_object cl_rem(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); @truncate(2, x, y); ecl_return1(the_env, the_env->values[1]); } cl_object cl_decode_float(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); int e, s; cl_type tx = ecl_t_of(x); float f; switch (tx) { case t_singlefloat: { f = ecl_single_float(x); if (f >= 0.0) { s = 1; } else { f = -f; s = 0; } f = frexpf(f, &e); x = ecl_make_single_float(f); break; } case t_doublefloat: { double d = ecl_double_float(x); if (d >= 0.0) { s = 1; } else { d = -d; s = 0; } d = frexp(d, &e); x = ecl_make_double_float(d); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); if (d >= 0.0) s = 1; else { d = -d; s = 0; } d = frexpl(d, &e); x = ecl_make_long_float(d); break; } #endif default: FEwrong_type_nth_arg(@[decode-float],1,x,@[float]); } ecl_return3(the_env, x, ecl_make_fixnum(e), ecl_make_single_float(s)); } cl_object cl_scale_float(cl_object x, cl_object y) { const cl_env_ptr the_env = ecl_process_env(); cl_fixnum k; if (ECL_FIXNUMP(y)) { k = ecl_fixnum(y); } else { FEwrong_type_nth_arg(@[scale-float],2,y,@[fixnum]); } switch (ecl_t_of(x)) { case t_singlefloat: x = ecl_make_single_float(ldexpf(ecl_single_float(x), k)); break; case t_doublefloat: x = ecl_make_double_float(ldexp(ecl_double_float(x), k)); break; #ifdef ECL_LONG_FLOAT case t_longfloat: x = ecl_make_long_float(ldexpl(ecl_long_float(x), k)); break; #endif default: FEwrong_type_nth_arg(@[scale-float],1,x,@[float]); } ecl_return1(the_env, x); } cl_object cl_float_radix(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); if (ecl_unlikely(cl_floatp(x) != ECL_T)) { FEwrong_type_nth_arg(@[float-radix],1,x,@[float]); } ecl_return1(the_env, ecl_make_fixnum(FLT_RADIX)); } int ecl_signbit(cl_object x) { switch (ecl_t_of(x)) { case t_singlefloat: return signbit(ecl_single_float(x)); case t_doublefloat: return signbit(ecl_double_float(x)); #ifdef ECL_LONG_FLOAT case t_longfloat: return signbit(ecl_long_float(x)); #endif default: FEwrong_type_nth_arg(@[float-sign],1,x,@[float]); } } @(defun float_sign (x &optional (y x yp)) int negativep; @ if (!yp) { y = cl_float(2, ecl_make_fixnum(1), x); } negativep = ecl_signbit(x); switch (ecl_t_of(y)) { case t_singlefloat: { float f = ecl_single_float(y); if (signbit(f) != negativep) y = ecl_make_single_float(-f); break; } case t_doublefloat: { double f = ecl_double_float(y); if (signbit(f) != negativep) y = ecl_make_double_float(-f); break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double f = ecl_long_float(y); if (signbit(f) != negativep) y = ecl_make_long_float(-f); break; } #endif default: FEwrong_type_nth_arg(@[float-sign],2,y,@[float]); } @(return y); @) cl_object cl_float_digits(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); switch (ecl_t_of(x)) { case t_singlefloat: x = ecl_make_fixnum(FLT_MANT_DIG); break; case t_doublefloat: x = ecl_make_fixnum(DBL_MANT_DIG); break; #ifdef ECL_LONG_FLOAT case t_longfloat: x = ecl_make_fixnum(LDBL_MANT_DIG); break; #endif default: FEwrong_type_nth_arg(@[float-digits],1,x,@[float]); } ecl_return1(the_env, x); } cl_object cl_float_precision(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); int precision; switch (ecl_t_of(x)) { case t_singlefloat: { float f = ecl_single_float(x); if (f == 0.0) { precision = 0; } else { int exp; frexpf(f, &exp); if (exp >= FLT_MIN_EXP) { precision = FLT_MANT_DIG; } else { precision = FLT_MANT_DIG - (FLT_MIN_EXP - exp); } } break; } case t_doublefloat: { double f = ecl_double_float(x); if (f == 0.0) { precision = 0; } else { int exp; frexp(f, &exp); if (exp >= DBL_MIN_EXP) { precision = DBL_MANT_DIG; } else { precision = DBL_MANT_DIG - (DBL_MIN_EXP - exp); } } break; } #ifdef ECL_LONG_FLOAT case t_longfloat: { long double f = ecl_long_float(x); if (f == 0.0) { precision = 0; } else { int exp; frexp(f, &exp); if (exp >= LDBL_MIN_EXP) { precision = LDBL_MANT_DIG; } else { precision = LDBL_MANT_DIG - (LDBL_MIN_EXP - exp); } } break; } #endif default: FEwrong_type_nth_arg(@[float-precision],1,x,@[float]); } ecl_return1(the_env, ecl_make_fixnum(precision)); } cl_object cl_integer_decode_float(cl_object x) { const cl_env_ptr the_env = ecl_process_env(); int e, s = 1; switch (ecl_t_of(x)) { #ifdef ECL_LONG_FLOAT case t_longfloat: { long double d = ecl_long_float(x); if (signbit(d)) { s = -1; d = -d; } if (d == 0.0) { e = 0; x = ecl_make_fixnum(0); } else { d = frexpl(d, &e); x = _ecl_long_double_to_integer(ldexpl(d, LDBL_MANT_DIG)); e -= LDBL_MANT_DIG; } break; } #endif case t_doublefloat: { double d = ecl_double_float(x); if (signbit(d)) { s = -1; d = -d; } if (d == 0.0) { e = 0; x = ecl_make_fixnum(0); } else { d = frexp(d, &e); x = _ecl_double_to_integer(ldexp(d, DBL_MANT_DIG)); e -= DBL_MANT_DIG; } break; } case t_singlefloat: { float d = ecl_single_float(x); if (signbit(d)) { s = -1; d = -d; } if (d == 0.0) { e = 0; x = ecl_make_fixnum(0); } else { d = frexpf(d, &e); x = _ecl_double_to_integer(ldexp(d, FLT_MANT_DIG)); e -= FLT_MANT_DIG; } break; } default: FEwrong_type_nth_arg(@[integer-decode-float],1,x,@[float]); } ecl_return3(the_env, x, ecl_make_fixnum(e), ecl_make_fixnum(s)); } @(defun complex (r &optional (i ecl_make_fixnum(0))) @ /* INV: ecl_make_complex() checks types */ @(return ecl_make_complex(r, i)) @) cl_object cl_realpart(cl_object x) { switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: case t_ratio: case t_singlefloat: case t_doublefloat: #ifdef ECL_LONG_FLOAT case t_longfloat: #endif break; case t_complex: x = x->complex.real; break; default: FEwrong_type_nth_arg(@[realpart],1,x,@[number]); } @(return x) } cl_object cl_imagpart(cl_object x) { switch (ecl_t_of(x)) { case t_fixnum: case t_bignum: case t_ratio: x = ecl_make_fixnum(0); break; case t_singlefloat: if (signbit(ecl_single_float(x))) x = cl_core.singlefloat_minus_zero; else x = cl_core.singlefloat_zero; break; case t_doublefloat: if (signbit(ecl_double_float(x))) x = cl_core.doublefloat_minus_zero; else x = cl_core.doublefloat_zero; break; #ifdef ECL_LONG_FLOAT case t_longfloat: if (signbit(ecl_long_float(x))) x = cl_core.longfloat_minus_zero; else x = cl_core.longfloat_zero; break; #endif case t_complex: x = x->complex.imag; break; default: FEwrong_type_nth_arg(@[imagpart],1,x,@[number]); } @(return x) }