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\$
  • \$\begingroup\$ Are you looking for elegance in providing values for i or mod? \$\endgroup\$ – greybeard Dec 20 '16 at 16:17
  • \$\begingroup\$ For mod, i is just a random number \$\endgroup\$ – soyuka Dec 20 '16 at 16:18
  • \$\begingroup\$ (The repetition of 10-in the title is distracting: can you explain or remove it?) \$\endgroup\$ – greybeard Dec 20 '16 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 '16 at 16:25
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, privacy policy and cookie policy

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