Loops/With multiple ranges

From Rosetta Code
Revision as of 19:58, 15 September 2018 by Thundergnat (talk | contribs) (→‎{{header|Perl 6}}: Combine code blocks to make complete, runnable examples, twiddle whitespace)


Loops/With multiple ranges 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.

Maintenance

This category lists articles requiring maintenance of some sort. Please read the directions for the category and apply them.

These tasks require clarification. Please participate in their talk pages, or implement the consensus found therein.

Some languages allow multiple loop ranges, such as the PL/I example (snippet) below.

<lang pli> /* all variables are DECLARED as integers. */

         prod=  1;                    /*start with a product of unity.           */
          sum=  0;                    /*  "     "  "   sum    " zero.            */
            x= +5;
            y= -5;
            z= -2;
          one=  1;
        three=  3;
        seven=  7;
                                      /*(below)  **  is exponentiation:  4**3=64 */
          do j=   -three  to     3**3        by three   ,
                  -seven  to   +seven        by   x     ,
                     555  to      550 - y               ,
                      22  to      -28        by -three  ,
                    1927  to     1939                   ,
                       x  to        y        by   z     ,
                   11**x  to    11**x + one;
                                                       /* ABS(n) = absolute value*/
          sum= sum + abs(j);                           /*add absolute value of J.*/
          if abs(prod)<2**27 & j¬=0  then prod=prod*j; /*PROD is small enough & J*/
          end;                                         /*not 0, then multiply it.*/
                    /*SUM and PROD are used for verification of J incrementation.*/
        display (' sum= ' ||  sum);                    /*display strings to term.*/
        display ('prod= ' || prod);                    /*   "       "     "   "  */</lang>


Task

Simulate/translate the above PL/I program snippet as best as possible in your language,   with particular emphasis on the   do   loop construct.

The   do   index must be incremented/decremented in the same order shown.

If possible, add commas to the two output numbers.

Show all output here.


Related tasks



C

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <locale.h>

long prod = 1L, sum = 0L;

void process(int j) {

   sum += abs(j);
   if (labs(prod) < (1 << 27) && j) prod *= j;

}

long ipow(int n, uint e) {

   long pr = n;
   int i;
   if (e == 0) return 1L;
   for (i = 2; i <= e; ++i) pr *= n;
   return pr;

}

int main() {

   int j;
   const int x = 5, y = -5, z = -2;
   const int one = 1, three = 3, seven = 7;
   long p = ipow(11, x);
   for (j = -three; j <= ipow(3, 3); j += three) process(j);
   for (j = -seven; j <= seven; j += x) process(j);
   for (j = 555; j <= 550 - y; ++j) process(j);
   for (j = 22; j >= -28; j -= three) process(j);
   for (j = 1927; j <= 1939; ++j) process(j);
   for (j = x; j >= y; j -= -z) process(j);
   for (j = p; j <= p + one; ++j) process(j);
   setlocale(LC_NUMERIC, "");
   printf("sum  = % 'ld\n", sum);
   printf("prod = % 'ld\n", prod);
   return 0;

}</lang>

Output:
sum  =  348,173
prod = -793,618,560

Factor

Factor doesn't have any special support for this sort of thing, but we can store iterable range objects in a collection and loop over them. <lang factor>USING: formatting kernel locals math math.functions math.ranges sequences sequences.generalizations tools.memory.private ;

[let  ! Allow lexical variables.

    1 :> prod!                 ! Start with a product of unity.
    0 :> sum!                  !   "     "  "   sum    " zero.
    5 :> x
   -5 :> y
   -2 :> z
    1 :> one
    3 :> three
    7 :> seven
   three neg 3 3 ^ three <range>              ! Create array
   seven neg seven x     <range>              ! of 7 ranges.
   555 550 y -             [a,b]
   22 -28 three neg      <range>
   1927 1939               [a,b]
   x y z                 <range>
   11 x ^ 11 x ^ 1 +       [a,b] 7 narray
   [
       [
           :> j j abs sum + sum!
           prod abs 2 27 ^ < j zero? not and
           [ prod j * prod! ] when
       ] each                      ! Loop over range.
   ] each                          ! Loop over array of ranges.
   
   ! SUM and PROD are used for verification of J incrementation.
   sum prod [ commas ] bi@ " sum=  %s\nprod= %s\n" printf

]</lang>

Output:
 sum=  348,173
prod= -793,618,560

Go

Nothing fancy from Go here (is there ever?), just a series of individual for loops. <lang go>package main

import "fmt"

func pow(n int, e uint) int {

   if e == 0 {
       return 1
   }
   prod := n
   for i := uint(2); i <= e; i++ {
       prod *= n
   }
   return prod

}

func abs(n int) int {

   if n >= 0 {
       return n
   }
   return -n

}

func commatize(n int) string {

   s := fmt.Sprintf("%d", n)
   if n < 0 {
       s = s[1:]
   }
   le := len(s)
   for i := le - 3; i >= 1; i -= 3 {
       s = s[0:i] + "," + s[i:]
   }
   if n >= 0 {
       return " " + s
   }
   return "-" + s

}

func main() {

   prod := 1
   sum := 0
   const (
       x     = 5
       y     = -5
       z     = -2
       one   = 1
       three = 3
       seven = 7
   )
   p := pow(11, x)
   var j int
   process := func() {
       sum += abs(j)
       if abs(prod) < (1<<27) && j != 0 {
           prod *= j
       }
   }
   for j = -three; j <= pow(3, 3); j += three {
       process()
   }
   for j = -seven; j <= seven; j += x {
       process()
   }
   for j = 555; j <= 550-y; j++ {
       process()
   }
   for j = 22; j >= -28; j -= three {
       process()
   }
   for j = 1927; j <= 1939; j++ {
       process()
   }
   for j = x; j >= y; j -= -z {
       process()
   }
   for j = p; j <= p+one; j++ {
       process()
   }
   fmt.Println("sum  = ", commatize(sum))
   fmt.Println("prod = ", commatize(prod))

}</lang>

Output:
sum  =   348,173
prod =  -793,618,560

Kotlin

Nothing special here, just a series of individual for loops. <lang scala>// Version 1.2.70

import kotlin.math.abs

infix fun Int.pow(e: Int): Int {

   if (e == 0) return 1
   var prod = this
   for (i in 2..e) {
       prod *= this
   }
   return prod

}

fun main(args: Array<String>) {

   var prod = 1
   var sum = 0
   val x = 5
   val y = -5
   val z = -2
   val one = 1
   val three = 3
   val seven = 7
   val p = 11 pow x
   fun process(j: Int) {
       sum += abs(j)
       if (abs(prod) < (1 shl 27) && j != 0) prod *= j
   }
   for (j in -three..(3 pow 3) step three) process(j)
   for (j in -seven..seven step x) process(j)
   for (j in 555..550-y) process(j)
   for (j in 22 downTo -28 step three) process(j)
   for (j in 1927..1939) process(j)
   for (j in x downTo y step -z) process(j)
   for (j in p..p + one) process(j)
   System.out.printf("sum  = % ,d\n", sum)
   System.out.printf("prod = % ,d\n", prod)

}</lang>

Output:
sum  =  348,173
prod = -793,618,560

Perl 6

Also displaying the j sequence since it isn't very large.

<lang perl6>sub comma ($i) {

   my $sign = $i < 0 ?? '-' !! ;
   $sign ~ $i.abs.flip.comb(3).join(',').flip

}

my \x = 5; my \y = -5; my \z = -2; my \one = 1; my \three = 3; my \seven = 7;

my $j = flat

 ( -three, *+three …  3³        ),
 ( -seven, *+x     …^ * > seven ),
 ( 555   .. 550 - y             ),
 ( 22,     *-three …^ * < -28   ),
 ( 1927  .. 1939                ),
 ( x,      *+z     …^ * < y     ),
 ( 11**x .. 11**x + one         );

put 'j sequence: ', $j; put ' Sum: ', comma [+] $j».abs; put ' Product: ', comma ([\*] $j.grep: so +*).first: *.abs > 2²⁷;

  1. Or, an alternate method for generating the 'j' sequence, employing user-defined
  2. operators to more closely mimic the 'X to Y by Z' layout of the example code.

sub infix:<to> { $^a...$^b } sub infix:<by> { ($^a.split(' '))[0,$^b.abs ... *] }

$j = cache flat

   -three  to       3**3  by  three,
   -seven  to      seven  by      x ,
      555  to   (550 - y)           ,
       22  to        -28  by -three ,
     1927  to       1939  by    one ,
        x  to          y  by      z ,
    11**x  to (11**x + one);

put "\nLiteral minded variant:"; put ' Sum: ', comma [+] $j».abs; put ' Product: ', comma ([\*] $j.grep: so +*).first: *.abs > 2²⁷;</lang>

Output:
j sequence: -3 0 3 6 9 12 15 18 21 24 27 -7 -2 3 555 22 19 16 13 10 7 4 1 -2 -5 -8 -11 -14 -17 -20 -23 -26 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 5 3 1 -1 -3 -5 161051 161052
       Sum: 348,173
   Product: -793,618,560

Literal minded variant:
       Sum: 348,173
   Product: -793,618,560

REXX

Programming note:   the (sympathetic) trailing semicolons (;) after each REXX statement are optional,   they are only there to mimic what the PL/I language requires after each statement.

The technique used by this REXX version is to "break up" the various   do   iterating clauses (ranges) into separate   do   loops,   and have them invoke a subroutine to perform the actual computations. <lang rexx>/*REXX program emulates a multiple─range DO loop (all variables can be any numbers). */

prod=  1;
 sum=  0;
   x= +5;
   y= -5;
   z= -2;
 one=  1;

three= 3; seven= 7;

     do j=   -three  to      3**3      by three  ;      call meat;      end;
     do j=   -seven  to    seven       by   x    ;      call meat;      end;
     do j=      555  to      550 - y             ;      call meat;      end;
     do j=       22  to      -28       by -three ;      call meat;      end;
     do j=     1927  to     1939                 ;      call meat;      end;
     do j=        x  to        y       by   z    ;      call meat;      end;
     do j=    11**x  to    11**x + one           ;      call meat;      end;

say ' sum= ' || commas( sum); /*display SUM with commas. */ say 'prod= ' || commas(prod); /* " PROD " " */ exit; /*stick a fork in it, we're done.*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: procedure; parse arg _; n= _'.9'; #= 123456789; b= verify(n, #, "M")

                                   e= verify(n, #'0', , verify(n, #"0.", 'M') )  - 4
         do j=e  to b  by -3;      _= insert(',', _, j);   end;                  return _

/*──────────────────────────────────────────────────────────────────────────────────────*/ meat: sum= sum + abs(j);

      if abs(prod)<2**27 & j\==0  then prod= prod * j;
      return;</lang>
output   when using the same variable values:
 sum= 348,173
prod= -793,618,560

zkl

<lang zkl>prod,sum := 1,0; /* start with a product of unity, sum of 0 */ x,y,z := 5, -5, -2; one,three,seven := 1,3,7; foreach j in (Walker.chain([-three..(3).pow(3),three],

              [-seven..seven,x], [555..550 - y], [22..-28,-three],
              [1927..1939], [x..y,z], [(11).pow(x)..(11).pow(x) + one])){
  sum+=j.abs();	/* add absolute value of J */
  if(prod.abs()<(2).pow(27) and j!=0) prod*=j; /* PROD is small enough & J */

} /* SUM and PROD are used for verification of J incrementation */ println("sum = %,d\nprod = %,d".fmt(sum,prod));</lang>

Output:
sum  = 348,173
prod = -793,618,560