Make log also accept a base. (#1667)
Make `log` in `racket/base` optionally accept a second argument. The second argument is the log `base`. The docs also recommend `fllogb` when precision is important. * Error message when base is 1 * Added docs. * Add tests.
This commit is contained in:
parent
6492226411
commit
922b5f06e9
|
@ -35,7 +35,9 @@
|
|||
"planet-doc"
|
||||
"mzscheme-doc"
|
||||
"compiler-lib"
|
||||
"drracket"))
|
||||
"drracket"
|
||||
"math-doc"
|
||||
"math-lib"))
|
||||
|
||||
(define pkg-desc "Base Racket documentation")
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
racket/unsafe/ops
|
||||
racket/require
|
||||
racket/random
|
||||
racket/list))
|
||||
racket/list
|
||||
math/flonum))
|
||||
|
||||
@(define math-eval (make-base-eval))
|
||||
@examples[#:hidden #:eval math-eval (require racket/math)]
|
||||
|
@ -606,19 +607,29 @@ integer.}
|
|||
|
||||
Returns Euler's number raised to the power of @racket[z]. The result
|
||||
is normally inexact, but it is exact @racket[1] when @racket[z] is an
|
||||
exact @racket[0].
|
||||
exact @racket[0]. See also @racket[expt].
|
||||
|
||||
@mz-examples[(exp 1) (exp 2+3i) (exp 0)]}
|
||||
|
||||
|
||||
@defproc[(log [z number?]) number?]{
|
||||
@defproc[(log [z number?] [b number? (exp 1)]) number?]{
|
||||
|
||||
Returns the natural logarithm of @racket[z]. The result is normally
|
||||
inexact, but it is exact @racket[0] when @racket[z] is an exact
|
||||
@racket[1]. When @racket[z] is exact @racket[0],
|
||||
@exnraise[exn:fail:contract:divide-by-zero].
|
||||
|
||||
@mz-examples[(log (exp 1)) (log 2+3i) (log 1)]}
|
||||
If @racket[b] is provided, it serves as an alternative
|
||||
base. It is equivalent to @racket[(/ (log z) (log b))], but
|
||||
can potentially run faster. If @racket[b] is exact
|
||||
@racket[1], @exnraise[exn:fail:contract:divide-by-zero].
|
||||
|
||||
Consider using @racket[fllogb] instead when accuracy is
|
||||
important.
|
||||
|
||||
@mz-examples[(log (exp 1)) (log 2+3i) (log 1) (log 100 10) (log 8 2) (log 5 5)]
|
||||
|
||||
@history[#:changed "6.9.0.1" @elem{Added second argument for arbitrary bases.}]}
|
||||
|
||||
|
||||
@; ------------------------------------------------------------------------
|
||||
|
|
|
@ -2119,7 +2119,11 @@
|
|||
(test +inf.0 real-part (log -inf.0))
|
||||
(test +3142.0 round (* 1000 (imag-part (log -inf.0))))
|
||||
(test +nan.0 log +nan.0)
|
||||
(test 2.0 log 100 10)
|
||||
(test 3.0 log 8 2)
|
||||
(test 1.0 log 5 5)
|
||||
(err/rt-test (log 0) exn:fail:contract:divide-by-zero?)
|
||||
(err/rt-test (log 5 1) exn:fail:contract:divide-by-zero?)
|
||||
|
||||
(test 1 cos 0)
|
||||
(test 1.0 cos 0.0)
|
||||
|
@ -3386,6 +3390,12 @@
|
|||
(test -4882.526517254422 real->double-flonum -13737024017780747/2813507303900)
|
||||
(test -9.792844933246106e-14 real->double-flonum -1656/16910305547451097)
|
||||
|
||||
;; Arbitrary base log
|
||||
(test (/ (log 5) (log 20)) log 5 20)
|
||||
(test (/ (log 5) (log -8)) log 5 -8)
|
||||
(test (/ (log 7) (log 3+5i)) log 7 3+5i)
|
||||
(test (/ (log -5+2i) (log 12)) log -5+2i 12)
|
||||
|
||||
;; Hack to use the "math" package when it's available:
|
||||
(when (collection-file-path "base.rkt" "math" #:fail (lambda (x) #f))
|
||||
(eval
|
||||
|
|
|
@ -101,6 +101,7 @@ static Scheme_Object *numerator (int argc, Scheme_Object *argv[]);
|
|||
static Scheme_Object *denominator (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *exp_prim (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *log_prim (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *log_e_prim (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *sin_prim (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *cos_prim (int argc, Scheme_Object *argv[]);
|
||||
static Scheme_Object *tan_prim (int argc, Scheme_Object *argv[]);
|
||||
|
@ -649,12 +650,12 @@ scheme_init_number (Scheme_Env *env)
|
|||
scheme_add_global_constant("exp",
|
||||
scheme_make_folding_prim(exp_prim,
|
||||
"exp",
|
||||
1, 1, 1),
|
||||
1, 1, 1),
|
||||
env);
|
||||
scheme_add_global_constant("log",
|
||||
scheme_make_folding_prim(log_prim,
|
||||
scheme_make_folding_prim(log_prim,
|
||||
"log",
|
||||
1, 1, 1),
|
||||
1, 2, 1),
|
||||
env);
|
||||
scheme_add_global_constant("sin",
|
||||
scheme_make_folding_prim(sin_prim,
|
||||
|
@ -2754,7 +2755,7 @@ static Scheme_Object *un_exp(Scheme_Object *o)
|
|||
|
||||
static Scheme_Object *un_log(Scheme_Object *o)
|
||||
{
|
||||
return log_prim(1, &o);
|
||||
return log_e_prim(1, &o);
|
||||
}
|
||||
|
||||
static Scheme_Object *numerator(int argc, Scheme_Object *argv[])
|
||||
|
@ -2791,7 +2792,8 @@ static Scheme_Object *complex_log(Scheme_Object *c)
|
|||
m = magnitude(1, &c);
|
||||
theta = angle(1, &c);
|
||||
|
||||
return scheme_bin_plus(log_prim(1, &m), scheme_bin_mult(scheme_plus_i, theta));
|
||||
return scheme_bin_plus(log_e_prim(1, &m),
|
||||
scheme_bin_mult(scheme_plus_i, theta));
|
||||
}
|
||||
|
||||
static Scheme_Object *bignum_log(Scheme_Object *b)
|
||||
|
@ -3027,13 +3029,31 @@ static Scheme_Object *scheme_single_inf_plus_pi()
|
|||
#endif
|
||||
|
||||
GEN_UNARY_OP(exp_prim, exp, exp, scheme_inf_object, scheme_single_inf_object, scheme_zerod, scheme_zerof, scheme_nan_object, scheme_single_nan_object, complex_exp, GEN_ZERO_IS_ONE, NEVER_RESORT_TO_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
GEN_UNARY_OP(log_prim, log, SCH_LOG, scheme_inf_object, scheme_single_inf_object, scheme_inf_plus_pi(), scheme_single_inf_plus_pi(), scheme_nan_object, scheme_single_nan_object, complex_log, GEN_ONE_IS_ZERO_AND_ZERO_IS_ERR, NEGATIVE_USES_COMPLEX, BIGNUM_LOG)
|
||||
GEN_UNARY_OP(log_e_prim, log, SCH_LOG, scheme_inf_object, scheme_single_inf_object, scheme_inf_plus_pi(), scheme_single_inf_plus_pi(), scheme_nan_object, scheme_single_nan_object, complex_log, GEN_ONE_IS_ZERO_AND_ZERO_IS_ERR, NEGATIVE_USES_COMPLEX, BIGNUM_LOG)
|
||||
GEN_UNARY_OP(sin_prim, sin, SCH_SIN, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, complex_sin, GEN_ZERO_IS_ZERO, NEVER_RESORT_TO_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
GEN_UNARY_OP(cos_prim, cos, SCH_COS, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, complex_cos, GEN_ZERO_IS_ONE, NEVER_RESORT_TO_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
GEN_UNARY_OP(tan_prim, tan, SCH_TAN, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, complex_tan, GEN_ZERO_IS_ZERO, NEVER_RESORT_TO_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
GEN_UNARY_OP(asin_prim, asin, SCH_ASIN, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, complex_asin, GEN_ZERO_IS_ZERO, OVER_ONE_MAG_USES_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
GEN_UNARY_OP(acos_prim, acos, acos, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, scheme_nan_object, scheme_single_nan_object, complex_acos, GEN_ONE_IS_ZERO, OVER_ONE_MAG_USES_COMPLEX, BIGNUMS_AS_DOUBLES)
|
||||
|
||||
static Scheme_Object *
|
||||
log_prim (int argc, Scheme_Object *argv[])
|
||||
{
|
||||
if (argc == 1) {
|
||||
return log_e_prim(argc, argv);
|
||||
} else {
|
||||
Scheme_Object *a, *b;
|
||||
a = argv[0];
|
||||
b = argv[1];
|
||||
if(SAME_OBJ(b, scheme_make_integer(1))){
|
||||
scheme_raise_exn(MZEXN_FAIL_CONTRACT_DIVIDE_BY_ZERO,
|
||||
"log: undefined for base 1");
|
||||
ESCAPED_BEFORE_HERE;
|
||||
}
|
||||
return scheme_bin_div(un_log(a), un_log(b));
|
||||
}
|
||||
}
|
||||
|
||||
static Scheme_Object *
|
||||
atan_prim (int argc, Scheme_Object *argv[])
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user