1
\$\begingroup\$

I'm looking for a way to have an logarithmic incremental counter. The counter goal is related to a numeric value than goes from 1 to Infinity. The counter maximum value should be 1000. The sequence looks like this:

  • number is below 10, increment by 1:

    1,2,3...7,8,9,10

  • number is above 10, increment by ^10 when the number reaches the counter

    100, 1000 stop at 1000

This is what I wrote so far (javascript):

let i = 0
let mod = 10
let result = document.getElementById('result')
result.innerText = ''

while (++i < 7322) {
  mod *= mod < 1000 && i === mod * 10 ? 10 : 1

  if (i < 10 || i % mod === 0) {
    //the further the `i` value is, the less this will be called
    result.innerText += i + ' pass the test. Mod is ' + mod + '.\n'
  }
}
<span id="result"></span>

I'm sure there is a more elegant way of doing this but can't get my hand on it. Do you have ideas on how to simplify the algorithm?

\$\endgroup\$
4
  • \$\begingroup\$ Are you looking for elegance in providing values for i or mod? \$\endgroup\$
    – greybeard
    Dec 20, 2016 at 16:17
  • \$\begingroup\$ For mod, i is just a random number \$\endgroup\$
    – soyuka
    Dec 20, 2016 at 16:18
  • \$\begingroup\$ (The repetition of 10-in the title is distracting: can you explain or remove it?) \$\endgroup\$
    – greybeard
    Dec 20, 2016 at 16:24
  • \$\begingroup\$ Done, I kinda had a hard time trying to explain. Finding a good title was even harder... \$\endgroup\$
    – soyuka
    Dec 20, 2016 at 16:25

2 Answers 2

1
\$\begingroup\$

Your solution is a bit wasteful by generating and testing all integers in the desired range while you actually only need a handful of them.

A big improvement in terms of performance is to avoid modulo arithmetic and increase the step-size tenfold whenever you finished iterating a sub-range 1-9, 10-99, 100-999 and so on:

let max = 7322;
let step = 1;
let next = 10;

while (step < 1000 && next < max) {
  for (let i = step; i < next; i += step) {
    console.log(i);
  }
  step = next;
  next *= 10;
}

for (let i = step; i < max; i += step) {
  console.log(i);
}

Of course, you might want to encapsulate above code in a function or even more versatile, a generator function and replace console.log(i); with yield i;.

However, since you only have four different step-sizes of 1, 10, 100, and 1000 you can encode them manually and come up with an even simpler generator function as follows:

// Generate logarithmic range from 1 to max (excluded):
function* logRange(max) {
  for (let i = 1; i < max && i < 10; i += 1) yield i;
  for (let i = 10; i < max && i < 100; i += 10) yield i;
  for (let i = 100; i < max && i < 1000; i += 100) yield i;
  for (let i = 1000; i < max; i += 1000) yield i;
}

// Example:
for (let i of logRange(7322)) console.log(i);

This avoids modulo arithmetic, computes only the desired numbers and is pretty easy to understand.

\$\endgroup\$
0
\$\begingroup\$

Your changes of mod coincide with the condition of "the if":

mod = 1;
while (++i < 12345) {
    if (i % mod === 0) {
        //the further the `i` value is, the less this will be called
        result.innerText += i + ' pass the test. Mod is ' + mod + '.\n'
        if (mod < 1000 && i === mod * 10)
            mod = i
  }
}

(Can't seem to get the snippets to work in firefox 50.1?!)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.