Loops/With multiple ranges

From Rosetta Code
Revision as of 19:19, 15 September 2018 by rosettacode>Paddy3118 (Flagged for clarification.)


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.

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²⁷;</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 variation

An alternate method for generating the 'j' sequence, employing user-defined operators to preserve the 'X to Y by Z' layout of the example code. <lang perl6>sub infix:<to> { $^a...$^b } sub infix:<by> { ($^a.split(' '))[0,$^b.abs ... *] }

$j = 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);</lang>

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