views:

150

answers:

4

Hi

i need a function that should give me a 10th or 100th array, for example

  • if i pass 5, it should return 1 to 10
  • if i pass 67, it should return 1 to 100
  • if i pass 126, it should return 101 to 200
  • if i pass 2524, it should return 2001 to 3000

Any guidance?

+1  A: 
p = floor(log10(N))
range = 10^p
base = floor(N/range) * range

for example

  log10(258) => 2.4
  floor(2.4) => 2
  range := 10^2 => 100
  base := floor(258/100)*100 => 200

(except this assumes that for 67, you really want 60..70)

AShelly
And to get the upper range, compute upper = (floor(N/range)+1) * range
mdma
+2  A: 

As commenters have mentioned, your ranges aren't entirely consistent. Here's my interpretation where 67 yields 61-70:

function range(n) {
    var digits = Math.ceil(Math.log(n) / Math.LN10);
    var spread = Math.max(Math.pow(10, digits - 1), 10);
    var low    = Math.floor((n - 1) / spread) * spread;
    var high   = low + spread;

    return [low + 1, high];
}

Results, including some edge cases:

5:    [1, 10]
67:   [61, 70]
126:  [101, 200]
2524: [2001, 3000]
100:  [91, 100]
1000: [901, 1000]
999:  [901, 1000]
John Kugelman
Thanks a lot John !
Max
+3  A: 

This gives you what you asked for:

function FunkyRange (TargNum)
{
    var OrderOfMag      = Math.floor (Math.log (TargNum-1) / Math.LN10);

    var NaturalLimLow   = Math.pow (10, OrderOfMag);
    var AdjustedLimLow  = Math.floor ((TargNum-1) / NaturalLimLow) * NaturalLimLow + 1;

    var AdjustedLimHigh = NaturalLimLow + AdjustedLimLow - 1;

    //-- Handle special cases For TargNum <= 10 and <= 100.

    if (AdjustedLimLow  <= 100)
        AdjustedLimLow  = 1;

    if (AdjustedLimHigh <= 10)
    {
        AdjustedLimHigh = 10;
    }
    else
    {
        if (AdjustedLimHigh < 100)
            AdjustedLimHigh = 100;
    }


    return [AdjustedLimLow, AdjustedLimHigh];
}

Which returns:

Input       Lim, Low     Lim, High
-----      ----------   -----------
   5             1           10
  67             1          100
  99             1          100
 100             1          100
 126           101          200
 200           101          200
 299           201          300
 473           401          500
2524          2001         3000
Brock Adams
Thanks a lot Brock, you are math guru :D
Max
+3  A: 

Other people are giving you good answers, but I'm not sure they're highlighting the important principle, which is:

You're looking for a function that depends on the "order of magnitude" of a given number. Logarithms are probably the easiest way of getting that information.

A log base 10 more or less answers the question "What's the largest power of 10 this number is divisible by?" or "How many times could I divide this number by 10 before it would be less than one?"

You could write a function which answers this question manually, of course:

function divsBy10(n) {
   var i = 0;
   while(n > 1) {
     n = n/10;
     i++;
   }
   return i-1;
}

And the overhead wouldn't be high. I'd guess it's a bit faster to use natively implemented math functions, though. Of course, it doesn't look like you get a native log base 10 in Actionscript... it appears Math.log is a natural log (log base e). There's a mathematical identity which says log_10 x = log_e x / log_e 10 ... and ActionScript does give you a log_e 10 as a constant (Math.LN10). So,

function log10(n) {
   return Math.log(n)/Math.LN10;
}

Now, log10 won't yield an integer answer to the questions I mentioned above ("How many times could I divide n by 10 before it's less than 1?"), because it's actually the inverse of 10^n, but the integral portion of the return value will be the answer to that question. So you'd want to do Math.floor on the value you get back from it, and from there, do the various computations you'll need in order to get the specific array ranges you need.

Weston C
v much Thanks Weston !
Max