Eban numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|Perl 6}}: Fix error in assumptions. e-ban numbers were correct, but the algorithm needed some tweaks for the general case.)
Line 301: Line 301:


===Algorithmically generate / count===
===Algorithmically generate / count===
Alternately, a translation of Perl 6. Allows for variable and multi character 'bans'. Does not need to actually generate the *-ban numbers to count them. Display counts up to 10**21.
Alternately, a partial translation of Perl 6. Does not need to actually generate the e-ban numbers to count them. Display counts up to 10**21.


<lang perl>use strict;
<lang perl>use strict;
Line 354: Line 354:
}
}


for my $t ('e', 't', 'subur') {
for my $t ('e') {
my @bans = enumerate($t, 4);
my @bans = enumerate($t, 4);
my @count = count($t, my $max = 21);
my @count = count($t, my $max = 21);
Line 407: Line 407:
Up to and including ten quintillion: 255,999,999
Up to and including ten quintillion: 255,999,999
Up to and including one hundred quintillion: 1,279,999,999
Up to and including one hundred quintillion: 1,279,999,999
Up to and including one sextillion: 1,279,999,999
Up to and including one sextillion: 1,279,999,999</pre>

============= t-ban: =============
t-ban numbers up to 1000: 56
[0 1 4 5 6 7 9 11 100 101 104 105 106 107 109 111 400 401 404 405 406 407 409 411 500 501 504 505 506 507 509 511 600 601 604 605 606 607 609 611 700 701 704 705 706 707 709 711 900 901 904 905 906 907 909 911]

t-ban numbers between 1,000 & 4,000 (inclusive): 0
[]

Counts of t-ban numbers up to one sextillion
Up to and including ten: 7
Up to and including one hundred: 9
Up to and including one thousand: 56
Up to and including ten thousand: 56
Up to and including one hundred thousand: 56
Up to and including one million: 57
Up to and including ten million: 392
Up to and including one hundred million: 393
Up to and including one billion: 2,745
Up to and including ten billion: 19,208
Up to and including one hundred billion: 19,209
Up to and including one trillion: 134,456
Up to and including ten trillion: 134,456
Up to and including one hundred trillion: 134,456
Up to and including one quadrillion: 134,457
Up to and including ten quadrillion: 941,192
Up to and including one hundred quadrillion: 941,193
Up to and including one quintillion: 6,588,344
Up to and including ten quintillion: 6,588,344
Up to and including one hundred quintillion: 6,588,344
Up to and including one sextillion: 6,588,344

============= subur-ban: =============
subur-ban numbers up to 1000: 35
[1 2 5 8 9 10 11 12 15 18 19 20 21 22 25 28 29 50 51 52 55 58 59 80 81 82 85 88 89 90 91 92 95 98 99]

subur-ban numbers between 1,000 & 4,000 (inclusive): 0
[]

Counts of subur-ban numbers up to one sextillion
Up to and including ten: 6
Up to and including one hundred: 35
Up to and including one thousand: 35
Up to and including ten thousand: 35
Up to and including one hundred thousand: 35
Up to and including one million: 36
Up to and including ten million: 216
Up to and including one hundred million: 1,295
Up to and including one billion: 1,295
Up to and including ten billion: 1,295
Up to and including one hundred billion: 1,295
Up to and including one trillion: 1,295
Up to and including ten trillion: 1,295
Up to and including one hundred trillion: 1,295
Up to and including one quadrillion: 1,295
Up to and including ten quadrillion: 1,295
Up to and including one hundred quadrillion: 1,295
Up to and including one quintillion: 1,295
Up to and including ten quintillion: 1,295
Up to and including one hundred quintillion: 1,295
Up to and including one sextillion: 1,295</pre>


=={{header|Perl 6}}==
=={{header|Perl 6}}==
Line 495: Line 435:


sub enumerate ($n, $upto) {
sub enumerate ($n, $upto) {
my @ban = nban(1 .. 99, $n);
my @ban = [nban(1 .. 99, $n)],;
my @orders = (2 .. $upto).map({ 10**$_ X* 1..9 }).map: *.&nban($n);
my @orders;
@orders.map: {
(2 .. $upto).map: -> $o {
given $o % 3 { # Compensate for irregulars: 11 - 19
next unless +$_;
when 0 { @orders.push: [[flat (10**$o X* 1..9).map: *.&nban($n)],
[flat (10**$o X* 11..19).map: *.&nban($n)]]}
when 1 { @orders.push: [flat (10**$o X* 2..9).map: *.&nban($n)] }
default { @orders.push: [flat (10**$o X* 1..9).map: *.&nban($n)] }
}
}
my @those;
^@orders .map: -> $o {
@ban.push: [] and next unless +@orders[$o];
my @these;
my @these;
.map: { @these.append: flat $_, flat @ban X+ $_ };
my @lower = |@orders[$o];
@ban.append: @these
my @upper = [];
if @orders[$o][0].^name eq 'Array' {
@lower = |@orders[$o][0];
@upper = |@orders[$o][1];
}
@lower.map: -> $m {
@these.push: $m;
for ^@ban -> $b {
next unless +@ban[$b];
@these.push: $_ for (flat @ban[$b]) »+» $m ;
}
}
@ban.push: @those.clone if +@those;
@those = ();
@upper.map: -> $m {
@those.push: $m;
for ^(@ban) -> $b {
next unless +@ban[$b];
@those.push: $_ for (flat @ban[$b]) »+» $m ;
}
}
@ban.push: @these;
}
}
@ban.push: @those.clone if +@those;
@ban.unshift(0) if nban(0, $n);
@ban.unshift(0) if nban(0, $n);
@ban
flat @ban.map: *.flat;
}
}


sub count ($n, $upto) {
sub count ($n, $upto) {
my @orders = (2 .. $upto).map({ 10**$_ X* 1..9 }).map: *.&nban($n);
my @orders;
(2 .. $upto).map: -> $o {
given $o % 3 { # Compensate for irregulars: 11 - 19
when 0 { @orders.push: [[flat (10**$o X* 1 .. 9).map: *.&nban($n)],
[flat (10**$o X* 11..19).map: *.&nban($n)]]}
when 1 { @orders.push: [flat (10**$o X* 2 .. 9).map: *.&nban($n)] }
default { @orders.push: [flat (10**$o X* 1 .. 9).map: *.&nban($n)] }
}
}
my @count = +nban(1 .. 99, $n);
my @count = +nban(1 .. 99, $n);
my $those;
@count.push: @count.sum * @orders[$_] + @orders[$_] for ^(+@orders - 1);
^@orders .map: -> $o {
@count.push: 0 and next unless +@orders[$o];
my @lower = |@orders[$o];
my @upper = [];
if @orders[$o][0].^name eq 'Array' {
@lower = |@orders[$o][0];
@upper = |@orders[$o][1];
}
my $prev = so (@lower.first( { $_ ~~ /^ '1' '0'+ $/ } ) // 0 );
my $sum = @count.sum;
my $these = +@lower * $sum + @lower;
@count[1 + $o] += $those if $those;
$those = +@upper * $sum + @upper;
$these-- if $prev;
@count[1 + $o] += $these;
++@count[$o] if $prev;
}
@count[*-1] += $those if $those and $upto % 3 == 1;
++@count[0] if nban(0, $n);
++@count[0] if nban(0, $n);
for ^(@count - 1) { if @orders[$_].contains(1) { @count[$_]++; @count[$_ + 1]-- } }
[\+] @count;
[\+] @count;
}
}
Line 532: Line 528:
"\nCounts of {$n}-ban numbers up to {cardinal 10**$upto}"
"\nCounts of {$n}-ban numbers up to {cardinal 10**$upto}"
;
;

my $s = max (1..$upto).map: { (10**$_).&cardinal.chars };
my $s = max (1..$upto).map: { (10**$_).&cardinal.chars };
@counts.unshift: @bans.first: * > 10, :k;
@counts.unshift: @bans.first: * > 10, :k;
for @counts.kv -> $k, $c {
for ^$upto -> $c {
printf "Up to and including %{$s}s: %s\n", cardinal(10**($k+1)), comma($c);
printf "Up to and including %{$s}s: %s\n", cardinal(10**($c+1)), comma(@counts[$c]);
}
}
}</lang>
}</lang>
Line 585: Line 582:
Up to and including ten million: 392
Up to and including ten million: 392
Up to and including one hundred million: 393
Up to and including one hundred million: 393
Up to and including one billion: 2,745
Up to and including one billion: 2,801
Up to and including ten billion: 19,208
Up to and including ten billion: 19,600
Up to and including one hundred billion: 19,209
Up to and including one hundred billion: 19,601
Up to and including one trillion: 134,456
Up to and including one trillion: 140,000
Up to and including ten trillion: 134,456
Up to and including ten trillion: 140,000
Up to and including one hundred trillion: 134,456
Up to and including one hundred trillion: 140,000
Up to and including one quadrillion: 134,457
Up to and including one quadrillion: 140,001
Up to and including ten quadrillion: 941,192
Up to and including ten quadrillion: 980,000
Up to and including one hundred quadrillion: 941,193
Up to and including one hundred quadrillion: 980,001
Up to and including one quintillion: 6,588,344
Up to and including one quintillion: 7,000,000
Up to and including ten quintillion: 6,588,344
Up to and including ten quintillion: 7,000,000
Up to and including one hundred quintillion: 6,588,344
Up to and including one hundred quintillion: 7,000,000
Up to and including one sextillion: 6,588,344
Up to and including one sextillion: 7,000,000


============= subur-ban: =============
============= subur-ban: =============
Line 613: Line 610:
Up to and including one hundred thousand: 35
Up to and including one hundred thousand: 35
Up to and including one million: 36
Up to and including one million: 36
Up to and including ten million: 216
Up to and including ten million: 215
Up to and including one hundred million: 1,295
Up to and including one hundred million: 1,259
Up to and including one billion: 1,295
Up to and including one billion: 1,259
Up to and including ten billion: 1,295
Up to and including ten billion: 1,259
Up to and including one hundred billion: 1,295
Up to and including one hundred billion: 1,259
Up to and including one trillion: 1,295
Up to and including one trillion: 1,259
Up to and including ten trillion: 1,295
Up to and including ten trillion: 1,259
Up to and including one hundred trillion: 1,295
Up to and including one hundred trillion: 1,259
Up to and including one quadrillion: 1,295
Up to and including one quadrillion: 1,259
Up to and including ten quadrillion: 1,295
Up to and including ten quadrillion: 1,259
Up to and including one hundred quadrillion: 1,295
Up to and including one hundred quadrillion: 1,259
Up to and including one quintillion: 1,295
Up to and including one quintillion: 1,259
Up to and including ten quintillion: 1,295
Up to and including ten quintillion: 1,259
Up to and including one hundred quintillion: 1,295
Up to and including one hundred quintillion: 1,259
Up to and including one sextillion: 1,295</pre>
Up to and including one sextillion: 1,259</pre>


Note that the limit to one sextillion is somewhat arbitrary and is just to match the task parameters.
Note that the limit to one sextillion is somewhat arbitrary and is just to match the task parameters.


This will quite happily count *-bans up to one hundred centillion. (10<sup>305</sup>) It takes longer, but still less than 10 seconds.
This will quite happily count *-bans up to one hundred centillion. (10<sup>305</sup>) It takes longer, but still on the order of seconds, not minutes.
<pre>Counts of e-ban numbers up to one hundred centillion
<pre>Counts of e-ban numbers up to one hundred centillion
...
...

Revision as of 17:34, 30 March 2019

Task
Eban numbers
You are encouraged to solve this task according to the task description, using any language you may know.


Definition

An   eban   number is a number that has no letter   e   in it when the number is spelled in ENglish.

Or more literally,   spelled numbers that contain the letter   e   are banned.


The American version of spelling numbers will be used here   (as opposed to the British).

2,000,000,000   is two billion,   not   two milliard.


Only numbers less than   one sextillion   (1021)   will be considered in/for this task.

This will allow optimizations to be used.


Task
  •   show all eban numbers   ≤   1,000   (in a horizontal format),   and a count
  •   show all eban numbers between   1,000   and   4,000   (inclusive),   and a count
  •   show a count of all eban numbers up and including           10,000
  •   show a count of all eban numbers up and including         100,000
  •   show a count of all eban numbers up and including      1,000,000
  •   show a count of all eban numbers up and including    10,000,000
  •   show all output here.


See also



Go

<lang go>package main

import "fmt"

type Range struct {

   start, end uint64
   print      bool

}

func main() {

   rgs := []Range{
       {2, 1000, true},
       {1000, 4000, true},
       {2, 1e4, false},
       {2, 1e5, false},
       {2, 1e6, false},
       {2, 1e7, false},
       {2, 1e8, false},
       {2, 1e9, false},
   }
   for _, rg := range rgs {
       if rg.start == 2 {
           fmt.Printf("eban numbers up to and including %d:\n", rg.end)
       } else {
           fmt.Printf("eban numbers between %d and %d (inclusive):\n", rg.start, rg.end)
       }
       count := 0
       for i := rg.start; i <= rg.end; i += 2 {
           b := i / 1000000000
           r := i % 1000000000
           m := r / 1000000
           r = i % 1000000
           t := r / 1000
           r %= 1000
           if m >= 30 && m <= 66 {
               m %= 10
           }
           if t >= 30 && t <= 66 {
               t %= 10
           }
           if r >= 30 && r <= 66 {
               r %= 10
           }
           if b == 0 || b == 2 || b == 4 || b == 6 {             
               if m == 0 || m == 2 || m == 4 || m == 6 {
                   if t == 0 || t == 2 || t == 4 || t == 6 {
                       if r == 0 || r == 2 || r == 4 || r == 6 {
                           if rg.print {
                               fmt.Printf("%d ", i)
                           }
                           count++
                       }
                   }
               }
           }
       }
       if rg.print {
           fmt.Println()
       }
       fmt.Println("count =", count, "\n")
   }

}</lang>

Output:
eban numbers up to and including 1000:
2 4 6 30 32 34 36 40 42 44 46 50 52 54 56 60 62 64 66 
count = 19 

eban numbers between 1000 and 4000 (inclusive):
2000 2002 2004 2006 2030 2032 2034 2036 2040 2042 2044 2046 2050 2052 2054 2056 2060 2062 2064 2066 4000 
count = 21 

eban numbers up to and including 10000:
count = 79 

eban numbers up to and including 100000:
count = 399 

eban numbers up to and including 1000000:
count = 399 

eban numbers up to and including 10000000:
count = 1599 

eban numbers up to and including 100000000:
count = 7999 

eban numbers up to and including 1000000000:
count = 7999 

J

<lang J> Filter =: (#~`)(`:6)

itemAmend =: (29&< *. <&67)`(,: 10&|)} iseban =: [: *./ 0 2 4 6 e.~ [: itemAmend [: |: (4#1000)&#:


  (;~ #) iseban Filter >: i. 1000

┌──┬─────────────────────────────────────────────────────┐ │19│2 4 6 30 32 34 36 40 42 44 46 50 52 54 56 60 62 64 66│ └──┴─────────────────────────────────────────────────────┘

  NB. INPUT are the correct integers, head and tail shown
  ({. , {:) INPUT =: 1000 + i. 3001

1000 4000

  (;~ #)  iseban Filter INPUT

┌──┬────────────────────────────────────────────────────────────────────────────────────────────────────────┐ │21│2000 2002 2004 2006 2030 2032 2034 2036 2040 2042 2044 2046 2050 2052 2054 2056 2060 2062 2064 2066 4000│ └──┴────────────────────────────────────────────────────────────────────────────────────────────────────────┘

  (, ([: +/ [: iseban [: >: i.))&> 10000 * 10 ^ i. +:2
10000   79

100000 399

  1e6  399
  1e7 1599

</lang>

Julia

I changed your program but not the output. You had used the common cut-n-paste error repeating the 10000 println("eban numbers up to and including 10000:

<lang Julia> function iseban(n::Integer)

   b, r = divrem(n, oftype(n, 10 ^ 9))
   m, r = divrem(r, oftype(n, 10 ^ 6))
   t, r = divrem(r, oftype(n, 10 ^ 3))
   m, t, r = (30 <= x <= 66 ? x % 10 : x for x in (m, t, r))
   return all(in((0, 2, 4, 6)), (b, m, t, r))

end

println("eban numbers up to and including 1000:") println(join(filter(iseban, 1:100), ", "))

println("eban numbers between 1000 and 4000 (inclusive):") println(join(filter(iseban, 1000:4000), ", "))

println("eban numbers up to and including 10000: ", count(iseban, 1:10000)) println("eban numbers up to and including 100000: ", count(iseban, 1:100000)) println("eban numbers up to and including 1000000: ", count(iseban, 1:1000000)) println("eban numbers up to and including 10000000: ", count(iseban, 1:10000000)) println("eban numbers up to and including 100000000: ", count(iseban, 1:100000000)) println("eban numbers up to and including 1000000000: ", count(iseban, 1:1000000000)) </lang>

Output:
eban numbers up to and including 1000:
2, 4, 6, 30, 32, 34, 36, 40, 42, 44, 46, 50, 52, 54, 56, 60, 62, 64, 66
eban numbers between 1000 and 4000 (inclusive):
2000, 2002, 2004, 2006, 2030, 2032, 2034, 2036, 2040, 2042, 2044, 2046, 2050, 2052, 2054, 2056, 2060, 2062, 2064, 2066, 4000

eban numbers up to and including 10000: 79
eban numbers up to and including 10000: 399
eban numbers up to and including 10000: 399
eban numbers up to and including 10000: 1599
eban numbers up to and including 10000: 7999
eban numbers up to and including 10000: 7999

Kotlin

Translation of: Go

<lang scala>// Version 1.3.21

typealias Range = Triple<Int, Int, Boolean>

fun main() {

   val rgs = listOf<Range>(
       Range(2, 1000, true),
       Range(1000, 4000, true),
       Range(2, 10_000, false),
       Range(2, 100_000, false),
       Range(2, 1_000_000, false),
       Range(2, 10_000_000, false),
       Range(2, 100_000_000, false),
       Range(2, 1_000_000_000, false)
   )
   for (rg in rgs) {
       val (start, end, prnt) = rg
       if (start == 2) {
           println("eban numbers up to and including $end:")
       } else {
           println("eban numbers between $start and $end (inclusive):")
       }
       var count = 0
       for (i in start..end step 2) {
           val b = i / 1_000_000_000
           var r = i % 1_000_000_000
           var m = r / 1_000_000
           r = i % 1_000_000
           var t = r / 1_000
           r %= 1_000
           if (m >= 30 && m <= 66) m %= 10
           if (t >= 30 && t <= 66) t %= 10
           if (r >= 30 && r <= 66) r %= 10
           if (b == 0 || b == 2 || b == 4 || b == 6) {
               if (m == 0 || m == 2 || m == 4 || m == 6) {
                   if (t == 0 || t == 2 || t == 4 || t == 6) {
                       if (r == 0 || r == 2 || r == 4 || r == 6) {
                           if (prnt) print("$i ")
                           count++
                       }
                   }
               }
           }
       }
       if (prnt) println()
       println("count = $count\n")
   }

}</lang>

Output:
Same as Go example.

Perl

Exhaustive search

A couple of 'e'-specific optimizations keep the running time reasonable. <lang perl>use strict; use warnings; use feature 'say'; use Lingua::EN::Numbers qw(num2en);

sub comma { reverse ((reverse shift) =~ s/(.{3})/$1,/gr) =~ s/^,//r }

sub e_ban {

   my($power) = @_;
   my @n;
   for (1..10**$power) {
       next unless 0 == $_%2;
       next if $_ =~ /[789]/ or /[12].$/ or /[135]..$/ or /[135]...$/ or /[135].....$/;
       push @n, $_ unless num2en($_) =~ /e/;
   }
   @n;

}

my @OK = e_ban(my $max = 7);

my @a = grep { $_ <= 1000 } @OK; say "Number of eban numbers up to and including 1000: @{[1+$#a]}"; say join(', ',@a); say ;

my @b = grep { $_ >= 1000 && $_ <= 4000 } @OK; say "Number of eban numbers between 1000 and 4000 (inclusive): @{[1+$#b]}"; say join(', ',@b); say ;

for my $exp (4..$max) {

   my $n = + grep { $_ <= 10**$exp } @OK;
   printf "Number of eban numbers and %10s: %d\n", comma(10**$exp), $n;

}</lang>

Output:
eban numbers up to and including 1000:
2, 4, 6, 30, 32, 34, 36, 40, 42, 44, 46, 50, 52, 54, 56, 60, 62, 64, 66

eban numbers between 1000 and 4000 (inclusive):
2000, 2002, 2004, 2006, 2030, 2032, 2034, 2036, 2040, 2042, 2044, 2046, 2050, 2052, 2054, 2056, 2060, 2062, 2064, 2066, 4000

Number of eban numbers up to     10,000: 79
Number of eban numbers up to    100,000: 399
Number of eban numbers up to  1,000,000: 399
Number of eban numbers up to 10,000,000: 1599

Algorithmically generate / count

Alternately, a partial translation of Perl 6. Does not need to actually generate the e-ban numbers to count them. Display counts up to 10**21.

<lang perl>use strict; use warnings; use bigint; use feature 'say'; use Lingua::EN::Nums2Words 'num2word'; use List::AllUtils 'sum';

sub comma { reverse ((reverse shift) =~ s/(.{3})/$1,/gr) =~ s/^,//r }

sub nban {

   my ($n, @numbers) = @_;
   grep { lc(num2word($_)) !~ /[$n]/i } @numbers;

}

sub enumerate {

   my ($n, $upto) = @_;
   my @ban = nban($n, 1 .. 99);
   my @orders;
   for my $o (2 .. $upto) {
       push @orders, [nban($n, map { $_ * 10**$o } 1 .. 9)];
   }
   for my $oom (@orders) {
       next unless +@$oom;
       my @these;
       for my $num (@$oom) {
           push @these, $num, map { $_ + $num } @ban;
       }
      push @ban, @these;
   }
   unshift @ban, 0 if nban($n, 0);
   @ban

}

sub count {

   my ($n, $upto) = @_;
   my @orders;
   for my $o (2 .. $upto) {
       push @orders, [nban($n, map { $_ * 10**$o } 1 .. 9)];
   }
   my @count = scalar nban($n, 1 .. 99);
   for my $o ( 0 .. $#orders - 1 ) {
       push @count, sum(@count) * (scalar @{$orders[$o]}) + (scalar @{$orders[$o]});
   }
   ++$count[0] if nban($n, 0);
   for my $m ( 0 .. $#count - 1 ) {
       next unless scalar $orders[$m];
       if (nban($n, 10**($m+2))) { $count[$m]++; $count[$m + 1]-- }
   }
   map { sum( @count[0..$_] ) } 0..$#count;

}

for my $t ('e') {

   my @bans  = enumerate($t, 4);
   my @count = count($t, my $max = 21);
   my @j = grep { $_ <= 10 } @bans;
   unshift @count, @{[1+$#j]};
   say "\n============= $t-ban: =============";
   my @a = grep { $_ <= 1000 } @bans;
   say "$t-ban numbers up to 1000: @{[1+$#a]}";
   say '[', join(' ',@a), ']';
   say ;
   my @b = grep { $_ >= 1000 && $_ <= 4000 } @bans;
   say "$t-ban numbers between 1,000 & 4,000 (inclusive): @{[1+$#b]}";
   say '[', join(' ',@b), ']';
   say ;
   say "Counts of $t-ban numbers up to ", lc(num2word(10**$max));
   for my $exp (1..$max) {
       my $nu = $count[$exp-1];
       printf "Up to and including %23s: %s\n", lc(num2word(10**$exp)), comma($nu);
   }

}</lang>

============= e-ban: =============
e-ban numbers up to 1000: 19
[2 4 6 30 32 34 36 40 42 44 46 50 52 54 56 60 62 64 66]

e-ban numbers between 1,000 & 4,000 (inclusive): 21
[2000 2002 2004 2006 2030 2032 2034 2036 2040 2042 2044 2046 2050 2052 2054 2056 2060 2062 2064 2066 4000]

Counts of e-ban numbers up to one sextillion
Up to and including                     ten: 3
Up to and including             one hundred: 19
Up to and including            one thousand: 19
Up to and including            ten thousand: 79
Up to and including    one hundred thousand: 399
Up to and including             one million: 399
Up to and including             ten million: 1,599
Up to and including     one hundred million: 7,999
Up to and including             one billion: 7,999
Up to and including             ten billion: 31,999
Up to and including     one hundred billion: 159,999
Up to and including            one trillion: 159,999
Up to and including            ten trillion: 639,999
Up to and including    one hundred trillion: 3,199,999
Up to and including         one quadrillion: 3,199,999
Up to and including         ten quadrillion: 12,799,999
Up to and including one hundred quadrillion: 63,999,999
Up to and including         one quintillion: 63,999,999
Up to and including         ten quintillion: 255,999,999
Up to and including one hundred quintillion: 1,279,999,999
Up to and including          one sextillion: 1,279,999,999

Perl 6

Works with: Rakudo version 2018.12

Modular approach, very little is hard coded. Change the $upto order-of-magnitude limit to adjust the search/display ranges. Change the letter(s) given to the enumerate / count subs to modify which letter(s) to disallow.

Will handle multi-character 'bans'. Demonstrate for e-ban, t-ban and subur-ban.

Directly find :

Considering numbers up to 1021, as the task directions suggest.

<lang perl6>use Lingua::EN::Numbers::Cardinal;

sub nban ($seq, $n = 'e') { ($seq).map: { next if .&cardinal.contains(any($n.lc.comb)); $_ } }

sub enumerate ($n, $upto) {

   my @ban = [nban(1 .. 99, $n)],;
   my @orders;
   (2 .. $upto).map: -> $o {
       given $o % 3 { # Compensate for irregulars: 11 - 19
           when 0  { @orders.push: [[flat (10**$o X* 1..9).map: *.&nban($n)],
                                    [flat (10**$o X* 11..19).map: *.&nban($n)]]}
           when 1  {  @orders.push: [flat (10**$o X* 2..9).map: *.&nban($n)]   }
           default {  @orders.push: [flat (10**$o X* 1..9).map: *.&nban($n)]    }
       }
   }
   my @those;
   ^@orders .map: -> $o {
       @ban.push: [] and next unless +@orders[$o];
       my @these;
       my @lower = |@orders[$o];
       my @upper = [];
       if @orders[$o][0].^name eq 'Array' {
           @lower = |@orders[$o][0];
           @upper = |@orders[$o][1];
       }
       @lower.map: -> $m {
           @these.push: $m;
           for ^@ban -> $b {
               next unless +@ban[$b];
               @these.push: $_ for (flat @ban[$b]) »+» $m ;
           }
       }
       @ban.push: @those.clone if +@those;
       @those = ();
       @upper.map: -> $m {
           @those.push: $m;
           for ^(@ban) -> $b {
               next unless +@ban[$b];
               @those.push: $_ for (flat @ban[$b]) »+» $m ;
           }
       }
       @ban.push: @these;
   }
   @ban.push: @those.clone if +@those;
   @ban.unshift(0) if nban(0, $n);
   flat @ban.map: *.flat;

}

sub count ($n, $upto) {

   my @orders;
   (2 .. $upto).map: -> $o {
       given $o % 3 { # Compensate for irregulars: 11 - 19
           when 0  { @orders.push: [[flat (10**$o X* 1 .. 9).map: *.&nban($n)],
                                    [flat (10**$o X* 11..19).map: *.&nban($n)]]}
           when 1  {  @orders.push: [flat (10**$o X* 2 .. 9).map: *.&nban($n)] }
           default {  @orders.push: [flat (10**$o X* 1 .. 9).map: *.&nban($n)] }
       }
   }
   my @count  = +nban(1 .. 99, $n);
   my $those;
   ^@orders .map: -> $o {
       @count.push: 0 and next unless +@orders[$o];
       my @lower = |@orders[$o];
       my @upper = [];
       if @orders[$o][0].^name eq 'Array' {
           @lower = |@orders[$o][0];
           @upper = |@orders[$o][1];
       }
       my $prev  = so (@lower.first( { $_ ~~ /^ '1' '0'+ $/ } ) // 0 );
       my $sum = @count.sum;
       my $these = +@lower * $sum + @lower;
       @count[1 + $o] += $those if $those;
       $those = +@upper * $sum + @upper;
       $these-- if $prev;
       @count[1 + $o] += $these;
       ++@count[$o]  if $prev;
   }
   @count[*-1] += $those if $those and $upto % 3 == 1;
   ++@count[0] if nban(0, $n);
   [\+] @count;

}

sub comma { $^i.flip.comb(3).join(',').flip }

  1. for < e o t tali subur tur ur cali i u > -> $n { # All of them

for < e t subur > -> $n { # An assortment for demonstration

   my $upto   = 21; # 1e21
   my @bans   = enumerate($n, 4);
   my @counts = count($n, $upto);
   # DISPLAY
   my @k = @bans.grep: * < 1000;
   my @j = @bans.grep: 1000 <= * <= 4000;
   put "\n============= {$n}-ban: =============\n" ~
       "{$n}-ban numbers up to 1000: {+@k}\n[{@k».&comma}]\n\n" ~
       "{$n}-ban numbers between 1,000 & 4,000: {+@j}\n[{@j».&comma}]\n" ~
       "\nCounts of {$n}-ban numbers up to {cardinal 10**$upto}"
       ;
   my $s = max (1..$upto).map: { (10**$_).&cardinal.chars };
   @counts.unshift: @bans.first: * > 10, :k;
   for ^$upto -> $c {
       printf "Up to and including %{$s}s: %s\n", cardinal(10**($c+1)), comma(@counts[$c]);
   }

}</lang>

Output:
============= e-ban: =============
e-ban numbers up to 1000: 19
[2 4 6 30 32 34 36 40 42 44 46 50 52 54 56 60 62 64 66]

e-ban numbers between 1,000 & 4,000: 21
[2,000 2,002 2,004 2,006 2,030 2,032 2,034 2,036 2,040 2,042 2,044 2,046 2,050 2,052 2,054 2,056 2,060 2,062 2,064 2,066 4,000]

Counts of e-ban numbers up to one sextillion
Up to and including                     ten: 3
Up to and including             one hundred: 19
Up to and including            one thousand: 19
Up to and including            ten thousand: 79
Up to and including    one hundred thousand: 399
Up to and including             one million: 399
Up to and including             ten million: 1,599
Up to and including     one hundred million: 7,999
Up to and including             one billion: 7,999
Up to and including             ten billion: 31,999
Up to and including     one hundred billion: 159,999
Up to and including            one trillion: 159,999
Up to and including            ten trillion: 639,999
Up to and including    one hundred trillion: 3,199,999
Up to and including         one quadrillion: 3,199,999
Up to and including         ten quadrillion: 12,799,999
Up to and including one hundred quadrillion: 63,999,999
Up to and including         one quintillion: 63,999,999
Up to and including         ten quintillion: 255,999,999
Up to and including one hundred quintillion: 1,279,999,999
Up to and including          one sextillion: 1,279,999,999

============= t-ban: =============
t-ban numbers up to 1000: 56
[0 1 4 5 6 7 9 11 100 101 104 105 106 107 109 111 400 401 404 405 406 407 409 411 500 501 504 505 506 507 509 511 600 601 604 605 606 607 609 611 700 701 704 705 706 707 709 711 900 901 904 905 906 907 909 911]

t-ban numbers between 1,000 & 4,000: 0
[]

Counts of t-ban numbers up to one sextillion
Up to and including                     ten: 7
Up to and including             one hundred: 9
Up to and including            one thousand: 56
Up to and including            ten thousand: 56
Up to and including    one hundred thousand: 56
Up to and including             one million: 57
Up to and including             ten million: 392
Up to and including     one hundred million: 393
Up to and including             one billion: 2,801
Up to and including             ten billion: 19,600
Up to and including     one hundred billion: 19,601
Up to and including            one trillion: 140,000
Up to and including            ten trillion: 140,000
Up to and including    one hundred trillion: 140,000
Up to and including         one quadrillion: 140,001
Up to and including         ten quadrillion: 980,000
Up to and including one hundred quadrillion: 980,001
Up to and including         one quintillion: 7,000,000
Up to and including         ten quintillion: 7,000,000
Up to and including one hundred quintillion: 7,000,000
Up to and including          one sextillion: 7,000,000

============= subur-ban: =============
subur-ban numbers up to 1000: 35
[1 2 5 8 9 10 11 12 15 18 19 20 21 22 25 28 29 50 51 52 55 58 59 80 81 82 85 88 89 90 91 92 95 98 99]

subur-ban numbers between 1,000 & 4,000: 0
[]

Counts of subur-ban numbers up to one sextillion
Up to and including                     ten: 6
Up to and including             one hundred: 35
Up to and including            one thousand: 35
Up to and including            ten thousand: 35
Up to and including    one hundred thousand: 35
Up to and including             one million: 36
Up to and including             ten million: 215
Up to and including     one hundred million: 1,259
Up to and including             one billion: 1,259
Up to and including             ten billion: 1,259
Up to and including     one hundred billion: 1,259
Up to and including            one trillion: 1,259
Up to and including            ten trillion: 1,259
Up to and including    one hundred trillion: 1,259
Up to and including         one quadrillion: 1,259
Up to and including         ten quadrillion: 1,259
Up to and including one hundred quadrillion: 1,259
Up to and including         one quintillion: 1,259
Up to and including         ten quintillion: 1,259
Up to and including one hundred quintillion: 1,259
Up to and including          one sextillion: 1,259

Note that the limit to one sextillion is somewhat arbitrary and is just to match the task parameters.

This will quite happily count *-bans up to one hundred centillion. (10305) It takes longer, but still on the order of seconds, not minutes.

Counts of e-ban numbers up to one hundred centillion
 ...
Up to and including one hundred centillion: 35,184,372,088,831,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999

REXX

Programming note:   REXX has no shortcuts for   if   statements, so the multiple   if   statements weren't combined into one. <lang rexx>/*REXX program to display eban numbers (those that don't have an "e" their English name)*/ numeric digits 20 /*support some gihugic numbers for pgm.*/ parse arg $ /*obtain optional arguments from the cL*/ if $= then $= '1 1000 1000 4000 1 -10000 1 -100000 1 -1000000 1 -10000000'

     do k=1  by 2  to words($)                  /*step through the list of numbers.    */
     call banE  word($, k),  word($, k+1)       /*process the numbers, from low──►high.*/
     end   /*k*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ banE: procedure; parse arg x,y,_; z= reverse(x) /*obtain the number to be examined. */

     tell= y>=0                                 /*Is HI non-negative?  Display eban #s.*/
     #= 0                                       /*the count of  eban  numbers (so far).*/
          do j=x  to abs(y)                     /*probably process a range of numbers. */
          if hasE(j)  then iterate              /*determine if the number has an  "e". */
          #= # + 1                              /*bump the counter of  eban  numbers.  */
          if tell  then _= _  j                 /*maybe add to a list of eban numbers. */
          end   /*j*/
     if _\==  then say strip(_)               /*display the list  (if there is one). */
     say;     say #   ' eban numbers found for: '   x   " "   y;     say copies('═', 105)
     return

/*──────────────────────────────────────────────────────────────────────────────────────*/ hasE: procedure; parse arg x; z= reverse(x) /*obtain the number to be examined. */

       do k=1  by 3                             /*while there're dec. digit to examine.*/
       @= reverse( substr(z, k, 3) )            /*obtain 3 dec. digs (a period) from Z.*/
       if @=='   '           then return 0      /*we have reached the "end" of the num.*/
       uni= right(@, 1)                         /*get units dec. digit of this period. */
       if uni//2==1          then return 1      /*if an odd digit, then not an eban #. */
       if uni==8             then return 1      /*if an  eight,      "   "   "   "  "  */
       tens=substr(@, 2, 1)                     /*get tens  dec. digit of this period. */
       if tens==1            then return 1      /*if teens,        then not an eban #. */
       if tens==2            then return 1      /*if twenties,       "   "   "   "  "  */
       if tens>6             then return 1      /*if 70s, 80s, 90s,  "   "   "   "  "  */
       hun= left(@, 1)                          /*get hundreds dec. dig of this period.*/
       if hun==0             then iterate       /*if zero, then there is more of number*/
       if hun\==' '          then return 1      /*any hundrEd (not zero) has an  "e".  */
       end   /*k*/                              /*A "period" is a group of 3 dec. digs */
    return 0                                    /*in the number, grouped from the right*/</lang>
output   when using the default inputs:
2 4 6 30 32 34 36 40 42 44 46 50 52 54 56 60 62 64 66

19  eban numbers found for:  1   1000
═════════════════════════════════════════════════════════════════════════════════════════════════════════
2000 2002 2004 2006 2030 2032 2034 2036 2040 2042 2044 2046 2050 2052 2054 2056 2060 2062 2064 2066 4000

21  eban numbers found for:  1000   4000
═════════════════════════════════════════════════════════════════════════════════════════════════════════

79  eban numbers found for:  1   -10000
═════════════════════════════════════════════════════════════════════════════════════════════════════════

399  eban numbers found for:  1   -100000
═════════════════════════════════════════════════════════════════════════════════════════════════════════

399  eban numbers found for:  1   -1000000
═════════════════════════════════════════════════════════════════════════════════════════════════════════

1599  eban numbers found for:  1   -10000000
═════════════════════════════════════════════════════════════════════════════════════════════════════════

Yabasic

Translation of: Go

<lang Yabasic>data 2, 100, true data 1000, 4000, true data 2, 1e4, false data 2, 1e5, false data 2, 1e6, false data 2, 1e7, false data 2, 1e8, false REM data 2, 1e9, false // it takes a lot of time data 0, 0, false

do

   read start, ended, printable
   if not start break 
   
   if start = 2 then
       Print "eban numbers up to and including ", ended
   else
       Print "eban numbers between ", start, " and ", ended, " (inclusive):"
   endif
   count = 0
   for i = start to ended step 2
       b = int(i / 1000000000)
       r = mod(i, 1000000000)
       m = int(r / 1000000)
       r = mod(i, 1000000)
       t = int(r / 1000)
       r = mod(r, 1000)
       if m >= 30 and m <= 66 m = mod(m, 10)
       if t >= 30 and t <= 66 t = mod(t, 10)
       if r >= 30 and r <= 66 r = mod(r, 10)
       if b = 0 or b = 2 or b = 4 or b = 6 then             
           if m = 0 or m = 2 or m = 4 or m = 6 then
               if t = 0 or t = 2 or t = 4 or t = 6 then
                   if r = 0 or r = 2 or r = 4 or r = 6 then
                       if printable Print i;
                       count = count + 1
                   endif
               endif
           endif
       endif
   next
   if printable Print
   Print "count = ", count, "\n"

loop</lang>