#include "lisp.h"
#include "syssignal.h"
+#include "ent.h"
+
#ifdef HAVE_FPFLOAT
/* The code uses emacs_rint, so that it works to undefine HAVE_RINT
}
#if defined(HAVE_FPFLOAT) || defined(HAVE_MPFR) && defined WITH_MPFR
-DEFUN("log", Flog, 1, 3, 0, /*
-Return the natural logarithm of NUMBER.
-If second optional argument BASE is given, return the logarithm of
-NUMBER using that base.
-If third optional argument PRECISION is given, use its value
+
+#define RETURN_WHEN_INDEF(number) \
+ if (INDEFP(number)) { \
+ if (XINDEF_DATA(number) == POS_INFINITY) { \
+ return number; \
+ } else if (XINDEF_DATA(number) == NEG_INFINITY) { \
+ return make_indef(NOT_A_NUMBER); \
+ } else { \
+ return number; \
+ } \
+ }
+
+DEFUN("log10", Flog10, 1, 2, 0, /*
+Return the logarithm base 10 of NUMBER.
+If second optional argument PRECISION is given, use its value
(an integer) as precision.
*/
- (number, base, precision))
+ (number, precision))
{
+ RETURN_WHEN_INDEF(number);
+
#if defined HAVE_MPFR && defined WITH_MPFR
Lisp_Object bfrnumber;
- if (!NILP(base)) {
- Lisp_Object _logn, _logb;
- _logn = Flog(number, Qnil, precision);
- if (UNLIKELY(INDEFP(_logn))) {
- return _logn;
- }
- _logb = Flog(base, Qnil, precision);
- return ent_binop(ASE_BINARY_OP_QUO, _logn, _logb);
- }
-
- if (INDEFP(number)) {
- if (XINDEF_DATA(number) == POS_INFINITY) {
- return number;
- } else if (XINDEF_DATA(number) == NEG_INFINITY) {
- return make_indef(NOT_A_NUMBER);
- } else {
- return number;
- }
- }
-
bigfr_set_prec(ent_scratch_bigfr,
internal_get_precision(precision));
bfrnumber = Fcoerce_number(number, Qbigfr, Qnil);
- bigfr_log(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
+ bigfr_log10(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
return make_bigfr_bfr(ent_scratch_bigfr);
#else /* !HAVE_MPFR */
- if (INDEFP(number)) {
- goto indefcase;
- }
-
number = ent_lift(number, FLOAT_T, NULL);
+ RETURN_WHEN_INDEF(number);
+
if (FLOATP(number)) {
fpfloat d;
- d = log(XFLOAT_DATA(number));
+#if HAVE_LOG10
+ d = log10(XFLOAT_DATA(number));
return make_float(d);
- } else if (INDEFP(number)) {
- indefcase:
- if (XINDEF_DATA(number) == POS_INFINITY) {
- return number;
- } else if (XINDEF_DATA(number) == NEG_INFINITY) {
- return make_indef(NOT_A_NUMBER);
- } else {
- return number;
- }
+#elif HAVE_LOG2
+ static const fpflot log2_10 = log2(10);
+ d = log2(XFLOAT_DATA(number));
+ RETURN_WHEN_INDEF(d);
+ return make_float(d/log2_10);
+#elif HAVE_LOG
+ static const fpflot log_10 - log(10);
+ d = log(XFLOAT_DATA(number));
+ RETURN_WHEN_INDEF(d);
+ return make_float(d/log_10);
+#else
+ return ase_unary_operation_undefined(number);
+#endif
}
Fsignal(Qarith_error, list1(number));
#endif /* HAVE_MPFR */
}
-DEFUN("log10", Flog10, 1, 2, 0, /*
-Return the logarithm base 10 of NUMBER.
+DEFUN("log2", Flog2, 1, 2, 0, /*
+Return the logarithm base 2 of NUMBER.
If second optional argument PRECISION is given, use its value
(an integer) as precision.
*/
(number, precision))
{
+ RETURN_WHEN_INDEF(number);
+
#if defined HAVE_MPFR && defined WITH_MPFR
- Lisp_Object bfrnumber;
+ Lisp_Object bfrnumber;
- if (INDEFP(number)) {
- if (XINDEF_DATA(number) == POS_INFINITY)
- return number;
- else if (XINDEF_DATA(number) == NEG_INFINITY)
- return make_indef(NOT_A_NUMBER);
- else
- return number;
+ bigfr_set_prec(ent_scratch_bigfr,
+ internal_get_precision(precision));
+
+ bfrnumber = Fcoerce_number(number, Qbigfr, Qnil);
+ bigfr_log2(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
+ return make_bigfr_bfr(ent_scratch_bigfr);
+#else
+ number = ent_lift(number, FLOAT_T, NULL);
+
+ RETURN_WHEN_INDEF(number);
+
+ if (FLOATP(number)) {
+ fpfloat d;
+#if HAVE_LOG2
+ d = log2(XFLOAT_DATA(number));
+ return make_float(d);
+#elif HAVE_LOG
+ static const fpflot log_2 - log(2);
+ d = log(XFLOAT_DATA(number));
+ RETURN_WHEN_INDEF(d);
+ return make_float(d/log_2);
+#else
+ return ase_unary_operation_undefined(number);
+#endif
+ }
+
+ Fsignal(Qarith_error, list1(number));
+ return Qnil;
+
+ if (NILP(precision));
+#endif /* HAVE_MPFR */
+}
+
+DEFUN("log", Flog, 1, 3, 0, /*
+Return the natural logarithm of NUMBER.
+If second optional argument BASE is given, return the logarithm of
+NUMBER using that base.
+If third optional argument PRECISION is given, use its value
+(an integer) as precision.
+*/
+ (number, base, precision))
+{
+ RETURN_WHEN_INDEF(number);
+
+ if (INTEGERP(base)) {
+ switch(XINT(base)) {
+ case 2 : return Flog2 (number, precision);
+ case 10: return Flog10(number, precision);
+ default: break; /* Intentional Fall through */
+ }
+ }
+
+
+#if defined HAVE_MPFR && defined WITH_MPFR
+ if (!NILP(base)) {
+ /* Not all bignumber libs optimize log2, for instance MPFR
+ implements log2 in function of log. */
+ Lisp_Object _logn, _logb;
+ _logn = Flog(number, Qnil, precision);
+ RETURN_WHEN_INDEF(_logn);
+ _logb = Flog(base, Qnil, precision);
+ return ent_binop(ASE_BINARY_OP_QUO, _logn, _logb);
}
+ Lisp_Object bfrnumber;
+
bigfr_set_prec(ent_scratch_bigfr,
- internal_get_precision(precision));
+ internal_get_precision(precision));
bfrnumber = Fcoerce_number(number, Qbigfr, Qnil);
- bigfr_log10(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
+ bigfr_log(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
return make_bigfr_bfr(ent_scratch_bigfr);
#else /* !HAVE_MPFR */
- if (INDEFP(number)) {
- goto indefcase;
+ if (!NILP(base)) {
+ /* Processor implementations tend to give an edge to log2 */
+ Lisp_Object _logn, _logb;
+ _logn = Flog2(number, precision);
+ RETURN_WHEN_INDEF(_logn);
+ _logb = Flog2(base, precision);
+ return ent_binop(ASE_BINARY_OP_QUO, _logn, _logb);
}
number = ent_lift(number, FLOAT_T, NULL);
+ RETURN_WHEN_INDEF(number);
+
if (FLOATP(number)) {
- fpfloat d;
- d = log10(XFLOAT_DATA(number));
- return make_float(d);
- } else if (INDEFP(number)) {
- indefcase:
- if (XINDEF_DATA(number) == POS_INFINITY)
- return number;
- else if (XINDEF_DATA(number) == NEG_INFINITY)
- return make_indef(NOT_A_NUMBER);
- else
- return number;
+ fpfloat d;
+ d = log(XFLOAT_DATA(number));
+ return make_float(d);
}
Fsignal(Qarith_error, list1(number));
#endif /* HAVE_MPFR */
}
-#if defined HAVE_MPFR && defined WITH_MPFR
-DEFUN("log2", Flog2, 1, 2, 0, /*
-Return the logarithm base 2 of NUMBER.
-If second optional argument PRECISION is given, use its value
-(an integer) as precision.
-*/
- (number, precision))
-{
- Lisp_Object bfrnumber;
-
- if (INDEFP(number)) {
- if (XINDEF_DATA(number) == POS_INFINITY)
- return number;
- else if (XINDEF_DATA(number) == NEG_INFINITY)
- return make_indef(NOT_A_NUMBER);
- else
- return number;
- }
-
- bigfr_set_prec(ent_scratch_bigfr,
- internal_get_precision(precision));
-
- bfrnumber = Fcoerce_number(number, Qbigfr, Qnil);
- bigfr_log2(ent_scratch_bigfr, XBIGFR_DATA(bfrnumber));
- return make_bigfr_bfr(ent_scratch_bigfr);
-}
-#endif /* HAVE_MPFR */
-
+#undef RETURN_WHEN_INDEF
DEFUN("sqrt", Fsqrt, 1, 2, 0, /*
Return the square root of NUMBER.
#endif
#if defined(HAVE_FPFLOAT) || defined(HAVE_MPFR) && defined WITH_MPFR
DEFSUBR(Flog);
-#if defined HAVE_MPFR && defined WITH_MPFR
DEFSUBR(Flog2);
-#endif /* HAVE_MPFR */
DEFSUBR(Flog10);
DEFSUBR(Fsqrt);
DEFSUBR(Fcube_root);