Eban numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Perl 6}}: I twiddle because I can...)
m (→‎{{header|Perl 6}}: update description to match)
Line 129: Line 129:
=={{header|Perl 6}}==
=={{header|Perl 6}}==
{{works with|Rakudo|2018.12}}
{{works with|Rakudo|2018.12}}
Modular approach, very little is hard coded. Change the order of magnitude limits to adjust the search/display ranges. Change the letter given to the nban sub to change which letter to disallow.
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 nban sub to modify which letter(s) to disallow.


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


Directly find :
Directly find :
Line 177: Line 177:
"{$n}-ban numbers between 1,000 & 4,000: {+@j}\n{@j.gist}\n";
"{$n}-ban numbers between 1,000 & 4,000: {+@j}\n{@j.gist}\n";


for (1 .. $upto).map: { 10**$_ } -> $e {
for (1 .. $upto).map: { 10**$_ } -> $e {
my $f = @bans.first( * > $e, :k );
my $f = @bans.first( * > $e, :k );
printf "Up to %14s: %d\n",comma($e), $f ?? +@bans[^$f] !! +@bans;
printf "Up to %14s: %d\n",comma($e), $f ?? +@bans[^$f] !! +@bans;

Revision as of 23:13, 20 February 2019

Eban numbers is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.


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 

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 nban sub to modify which letter(s) to disallow.

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

Directly find :

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

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

sub filter ($n, $upto) {

   my @ban    = flat ((1 .. 99),).map: *.&nban($n);
   my @orders = (2 .. $upto).map({ 10**$_ X* 1..9 }).map: *.&nban($n);
   for @orders -> @order {
       next unless +@order;
       my @these;
       @these.append: flat $_, flat @ban X+ $_ for @order;
       @ban.append: @these
   }
   @ban.unshift(0) if 0.&nban($n);
   @ban

}

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

for 'e', 't', 'subur' -> $n {

   my $upto = 10; # 1e10
   my @bans = filter($n, $upto);
   # DISPLAY
   my @k = @bans.grep: * <= 100;
   my @j = @bans.grep: 1000 <= * <= 4000;
   put "\n============= {$n}-ban: =============\n" ~
       "{$n}-ban numbers up to 100: {+@k}\n {@k}\n\n" ~
       "{$n}-ban numbers between 1,000 & 4,000: {+@j}\n{@j.gist}\n";
   for (1 .. $upto).map: { 10**$_ } -> $e {
       my $f = @bans.first( * > $e, :k );
       printf "Up to %14s: %d\n",comma($e), $f ?? +@bans[^$f] !! +@bans;
   }

}</lang>

Output:
============= e-ban: =============
e-ban numbers up to 100: 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
[2000 2002 2004 2006 2030 2032 2034 2036 2040 2042 2044 2046 2050 2052 2054 2056 2060 2062 2064 2066 4000]

Up to             10: 3
Up to            100: 19
Up to          1,000: 19
Up to         10,000: 79
Up to        100,000: 399
Up to      1,000,000: 399
Up to     10,000,000: 1599
Up to    100,000,000: 7999
Up to  1,000,000,000: 7999
Up to 10,000,000,000: 31999

============= t-ban: =============
t-ban numbers up to 100: 9
 0 1 4 5 6 7 9 11 100

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

Up to             10: 7
Up to            100: 9
Up to          1,000: 56
Up to         10,000: 56
Up to        100,000: 56
Up to      1,000,000: 57
Up to     10,000,000: 392
Up to    100,000,000: 393
Up to  1,000,000,000: 2745
Up to 10,000,000,000: 19208

============= subur-ban: =============
subur-ban numbers up to 100: 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
[]

Up to             10: 6
Up to            100: 35
Up to          1,000: 35
Up to         10,000: 35
Up to        100,000: 35
Up to      1,000,000: 36
Up to     10,000,000: 216
Up to    100,000,000: 1295
Up to  1,000,000,000: 1295
Up to 10,000,000,000: 1295

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
═════════════════════════════════════════════════════════════════════════════════════════════════════════