I'd like to get exactly 5 divisions from x to y on a log scale. Can FindDivisions
do this?
5 Answers
EDIT:
After 3 years, it has been discovered that this oft-linked-to answer doesn't truly space logarithmically. It's close, which was all I was going for at the time (and handles zeros), but it's not quite right. Anyway, thanks to @Pickett's careful moderation, here's a better version...
logspace[increments_, start_?Positive, end_?Positive] :=
Exp@Range[Log@start, Log@end, Log[end/start]/increments]
This one, by the stodgy nature of Logs, won't handle non-positive numbers, so I'll leave the old answer. Sorry to all that lost millions in the stock market using the old function. :)
OLD FUNCTION
I built a function that calculates log spaced increments for a job at work. I've added a catch where it will handle log spacing from 0 to a number.
logspace [increments_, start_, end_] := Module[{a}, (
a = Range[0, increments];
Exp[a/increments*Log[(end - start) + 1]] - 1 + start
)]
To try it out:
N@logspace[5,1,1000]
(*{1., 3.98107, 15.8489, 63.0957, 251.189, 1000.}*)
To view it on a number line:
a = N@logspace[10, 0, 10];
Graphics[Point@Transpose[{a, ConstantArray[.5, 11]}], Axes -> {True, False},
AxesStyle -> Arrowheads[.05]]
And if you want to find the distances between divisions, use Differences
:
Differences[a]
(*{0.270982, 0.344413, 0.437742, 0.556362, 0.707126, 0.898744, 1.14229, 1.45183, 1.84524, 2.34527}*)
-
-
$\begingroup$ @Pickett Oh dear. I wrote that 3 years ago (about the amount of time I've used MMA).... eek. Yeah, it log-ish spaces, but isn't a "true" logspace. Let me work on that... $\endgroup$– kaleCommented Sep 15, 2015 at 0:13
-
$\begingroup$ Thanks for the quick response! :) $\endgroup$– C. E. ♦Commented Sep 15, 2015 at 8:41
-
$\begingroup$ So how to get the logspace from -1 to 2? $\endgroup$– yodeCommented Mar 7, 2016 at 8:23
Writing one wouldn't be that hard. You can convert it to Log10
and then let FindDivisions
do all the work in log space before converting it back. For example:
findLogDivisions[{xmin_, xmax_}, n_Integer] := 10^FindDivisions[Log10@{xmin, xmax}, n]
Then, to find 4 "nice" divisions in log space between 1 and 1000, you simply need to do:
findLogDivisions[{1, 1000}, 5]
(* {1, 10, 100, 1000} *)
Here's a mathematically simple approach, assuming that exactly n
divisions are sought, no matter how nice or not.
This produces exactly n
intervals:
Clear[logDiv];
logDiv[{x_?Positive, y_?Positive}, n_Integer /; n > 0] :=
x (y/x)^Range[0, 1, 1/n]
logDiv[{10, 10000}, 3]
(* {10, 100, 1000, 10000} *)
If you want n
"fence posts", use
Clear[logDiv];
logDiv[{x_?Positive, y_?Positive}, n_Integer /; n > 1] :=
x (y/x)^Range[0, 1, 1/(n-1)]
If you want n
interior division points, change n
to n+1
in the first version.
Comparisons. Kuba's method produces the same output as logDiv
mutatis mutandis*. Below I use the first version of logDiv
and omit Kuba's output.
Comparison 1:
N @ logDiv[{1/10, 100000}, 3] (* same output as Kuba *)
N @ logspace[3, 1/10, 100000] (* kale *)
N @ findLogDivisions[{1/10, 100000}, 3] (* rm -rf *)
(*
{0.1, 10., 1000., 100000.}
{0.1, 45.516, 2153.55, 100000.}
{0.01, 1., 100., 10000., 1.*10^6}
*)
Comparison 2:
N @ logDiv[{10, 100000}, 5]
N @ logspace[5, 10, 100000]
N @ findLogDivisions[{10, 100000}, 5]
(*
{10., 63.0957, 398.107, 2511.89, 15848.9, 100000.}
{10., 18.9998, 108.996, 1008.95, 10008.3, 100000.}
{10., 100., 1000., 10000., 100000.}
*)
Note the outputs vary; in particular logspace
does something quite different than the others when start
is different than 1
. Depending on the application, one or the other might be desired.
*In honor of the language survey.
-
$\begingroup$ +1, what do you think about editing the question. Now the answer
RandomReal[{start, end}, 5]
fits quite well. $\endgroup$– KubaCommented Mar 18, 2014 at 13:10 -
$\begingroup$ +1 to you, too. I'm assuming
RandomReal
is a joke :) However the question could more clearly state what exactly counts as a division. It seems to me the OP should decide, but it's not a big deal. I wish the OP had accepted or commented on the other answers, though. $\endgroup$ Commented Mar 18, 2014 at 13:17 -
$\begingroup$ Yes it is a joke but it fits :) Maybe it's better with it's vague form, more answers are valid. $\endgroup$– KubaCommented Mar 18, 2014 at 13:20
I do a lot of work where I need to have function evaluations at equal logarithmic spacings. The code I use is
GeometricRange[imin_, imax_, perRange[n_]] := GeometricRange[imin, imax,
(imax/imin)^(1/(n - 1))];
GeometricRange[imin_, imax_, r_] := Exp[Range @@ Log[N[{imin, imax, r}]]];
perDecade[n_] := 10^(1/(n - 1));
perOctave[n_] := 2^(1/(n - 1));
GeometricRange
has the same calling syntax as Range
, where the increment (in this case, the ratio r
) is given as an argument, but also has the option of specifying the total number of samples in the range with perRange
or commonly used log resolutions with perDecade
or perOctave
. The calling syntax is
In[10]:= GeometricRange[10, 1000, 10]
Out[10]= {10., 100., 1000.}
or
In[9]:=GeometricRange[10, 1000, 10 // perRange]
Out[9]= {10., 16.681, 27.8256, 46.4159, 77.4264, 129.155, 215.443, 359.381, 599.484, 1000.}
or
In[6]:= GeometricRange[10, 1000, 10 // perDecade]
Out[6]= {10., 12.9155, 16.681, 21.5443, 27.8256, 35.9381, 46.4159,
59.9484, 77.4264, 100., 129.155, 166.81, 215.443, 278.256, 359.381,
464.159, 599.484, 774.264, 1000.}
Here is the complete code for Version 10 and up, using PowerRange
perDecade[(n_)?Positive] := 10^(1/(n - 1));
perOctave[(n_)?Positive] := 2^(1/(n - 1));
perRange /: PowerRange[imin_, imax_, perRange[(n_Integer)?Positive]] :=
PowerRange[imin, imax, (imax/imin)^(1/(n - 1))];
-
4$\begingroup$ As of version 10.0, GeometricRange can be replaced by the built-in function PowerRange. $\endgroup$– Daniel WCommented Sep 15, 2015 at 12:04
Array
may be used just like here by rm -rf but only for V9 or later version: see this post
10^Array[# &, 6, Log10@{1., 1000}]
{1., 3.98107, 15.8489, 63.0957, 251.189, 1000.}