Loops/With multiple ranges
You are encouraged to solve this task according to the task description, using any language you may know.
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 feasible, add commas to the two output numbers (being displayed).
Show all output here. <lang> A simple PL/I DO loop (incrementing or decrementing) has the construct of:
DO variable = start_expression {TO ending_expression] {BY increment_expression} ; ---or--- DO variable = start_expression {BY increment_expression} {TO ending_expression] ;
where it is understood that all expressions will have a value. The variable is normally a scaler variable, but need not be (but for this task, all variables and expressions are declared to be scaler integers). If the BY expression is omitted, a BY value of unity is used. All expressions are evaluated before the DO loop is executed, and those values are used throughout the DO loop execution (even though, for instance, the value of Z may be changed within the DO loop. This isn't the case here for this task.
A multiple-range DO loop can be constructed by using a comma (,) to separate additional ranges (the use of multiple TO and/or BY keywords). This is the construct used in this task. There are other forms of DO loops in PL/I involving the WHILE clause, but those won't be needed here. DO loops without a TO clause might need a WHILE clause or some other means of exiting the loop (such as LEAVE, RETURN, SIGNAL, GOTO, or STOP), or some other (possible error) condition that causes transfer of control outside the DO loop. Also, in PL/I, the check if the DO loop index value is outside the range is made at the "head" (start) of the DO loop, so it's possible that the DO loop isn't executed, but that isn't the case for any of the ranges used in this task.
In the example above, the clause: x to y by z will cause the variable J to have to following values (in this order): 5 3 1 -1 -3 -5
In the example above, the clause: -seven to +seven by x will cause the variable J to have to following values (in this order): -7 -2 3 </lang>
- Related tasks
- Loop over multiple arrays simultaneously
- Loops/Break
- Loops/Continue
- Loops/Do-while
- Loops/Downward for
- Loops/For
- Loops/For with a specified step
- Loops/Foreach
- Loops/Increment loop index within loop body
- Loops/Infinite
- Loops/N plus one half
- Loops/Nested
- Loops/While
- Loops/with multiple ranges
- Loops/Wrong ranges
11l
<lang 11l>V prod = 1 V s = 0
-V
x = +5 y = -5 z = -2 one = 1 three = 3 seven = 7
F body(j)
:s += abs(j) I abs(:prod) < 2 ^ 27 & j != 0 :prod *= j
L(j) (-three .. 3 ^ 3).step(three) {body(j)} L(j) (-seven .. seven).step(x) {body(j)} L(j) 555 .. 550 - y {body(j)} L(j) (22 .. -28).step(-three) {body(j)} L(j) 1927 .. 1939 {body(j)} L(j) (x .. y).step(z) {body(j)} L(j) 11 ^ x .. 11 ^ x + one {body(j)}
V ss = String(s) V ps = String(prod) V m = max(ss.len, ps.len) print(‘ sum = ’ss.rjust(m)) print(‘prod = ’ps.rjust(m))</lang>
- Output:
sum = 348173 prod = -793618560
AArch64 Assembly
<lang AArch64 Assembly> /* ARM assembly AARCH64 Raspberry PI 3B */ /* program loopnrange64.s */
/*******************************************/ /* Constantes file */ /*******************************************/ /* for this file see task include a file in language AArch64 assembly*/ .include "../includeConstantesARM64.inc"
/*********************************/ /* Initialized data */ /*********************************/ .data szMessResult: .asciz "@ \n" // message result szCarriageReturn: .asciz "\n" /*********************************/ /* UnInitialized data */ /*********************************/ .bss qSum: .skip 8 // this program store sum and product in memory qProd: .skip 8 // it is possible to use registers x22 and x28 sZoneConv: .skip 24 /*********************************/ /* code section */ /*********************************/ .text .global main main: // entry of program
ldr x0,qAdrqProd mov x1,1 str x1,[x0] // init product ldr x0,qAdrqSum mov x1,0 str x1,[x0] // init sum
mov x25,5 // x mov x24,-5 // y mov x26,-2 // z mov x21,1 // one mov x23,3 // three mov x27,7 // seven
// loop one mov x0,3 mov x1,3 bl computePow // compute 3 pow 3 mov x20,x0 // save result mvn x9,x23 // x9 = - three add x9,x9,1
1:
mov x0,x9 bl computeSumProd add x9,x9,x23 // increment with three cmp x9,x20 ble 1b // loop two mvn x9,x27 // x9 = - seven add x9,x9,1
2:
mov x0,x9 bl computeSumProd add x9,x9,x25 // increment with x cmp x9,x27 // compare to seven ble 2b
// loop three mov x9,#550 sub x20,x9,x24 // x20 = 550 - y mov x9,#555
3:
mov x0,x9 bl computeSumProd add x9,x9,#1 cmp x9,x20 ble 3b // loop four mov x9,#22
4:
mov x0,x9 bl computeSumProd sub x9,x9,x23 // decrement with three cmp x9,#-28 bge 4b // loop five mov x9,1927 mov x20,1939
5:
mov x0,x9 bl computeSumProd add x9,x9,1 cmp x9,x20 ble 5b // loop six mov x9,x25 // x9 = x mvn x20,x26 // x20 = - z add x20,x20,1
6:
mov x0,x9 bl computeSumProd sub x9,x9,x20 cmp x9,x24 bge 6b // loop seven mov x0,x25 mov x1,11 bl computePow // compute 11 pow x add x20,x0,x21 // + one mov x9,x0
7:
mov x0,x9 bl computeSumProd add x9,x9,1 cmp x9,x20 ble 7b // display result ldr x0,qAdrqSum ldr x0,[x0] ldr x1,qAdrsZoneConv // signed conversion value bl conversion10S // decimal conversion ldr x0,qAdrszMessResult ldr x1,qAdrsZoneConv bl strInsertAtCharInc // insert result at @ character bl affichageMess // display message ldr x0,qAdrszCarriageReturn bl affichageMess // display return line ldr x0,qAdrqProd ldr x0,[x0] ldr x1,qAdrsZoneConv // conversion value bl conversion10S // signed decimal conversion ldr x0,qAdrszMessResult ldr x1,qAdrsZoneConv bl strInsertAtCharInc // insert result at @ character bl affichageMess // display message ldr x0,qAdrszCarriageReturn bl affichageMess // display return line
100: // standard end of the program
mov x0,0 // return code mov x8,EXIT // request to exit program svc 0 // perform the system call
qAdrsZoneConv: .quad sZoneConv qAdrszMessResult: .quad szMessResult qAdrszCarriageReturn: .quad szCarriageReturn /******************************************************************/ /* compute the sum and prod */ /******************************************************************/ /* x0 contains the number */ computeSumProd:
stp x1,lr,[sp,-16]! // save registers asr x10,x0,#63 eor x12,x10,x0 sub x12,x12,x10 // compute absolue value ldr x13,qAdrqSum // load sum ldr x11,[x13] add x11,x11,x12 // add sum str x11,[x13] // store sum cmp x0,#0 // j = 0 ? beq 100f // yes ldr x13,qAdrqProd ldr x11,[x13] asr x12,x11,#63 // compute absolute value of prod eor x14,x11,x12 sub x12,x14,x12 ldr x10,qVal2P27 cmp x12,x10 // compare 2 puissance 27 bgt 100f mul x11,x0,x11 str x11,[x13] // store prod
100:
ldp x1,lr,[sp],16 // restaur 2 registers ret // return to address lr x230
qAdrqSum: .quad qSum qAdrqProd: .quad qProd qVal2P27: .quad 1<<27 /******************************************************************/ /* compute pow */ /******************************************************************/ /* x0 contains pow */ /* x1 contains number */ computePow:
stp x1,lr,[sp,-16]! // save registers mov x12,x0 mov x0,#1
1:
cmp x12,#0 ble 100f mul x0,x1,x0 sub x12,x12,#1 b 1b
100:
ldp x1,lr,[sp],16 // restaur 2 registers ret // return to address lr x230
/********************************************************/ /* File Include fonctions */ /********************************************************/ /* for this file see task include a file in language AArch64 assembly */ .include "../includeARM64.inc" </lang>
- Output:
+348173 -793618560
ALGOL 60
<lang algol60>begin
integer prod, sum, x, y, z, one, three, seven; integer j; prod := 1; sum := 0; x := 5; y := -5; z := -2; one := 1; three := 3; seven := 7;
for j := -three step three until 3^3 , -seven step x until seven , 555 step 1 until 550 - y, 22 step -three until -28 , 1927 step 1 until 1939 , x step z until y , 11^x step 1 until 11^x + one do begin sum := sum + iabs(j); if iabs(prod) < 2^27 & j != 0 then prod := prod*j end;
outstring(1, " sum= "); outinteger(1, sum); outstring(1, "\n"); outstring(1, "prod= "); outinteger(1, prod); outstring(1, "\n")
end </lang>
- Output:
sum= 348173 prod= -793618560
ALGOL 68
As with most of the other languages, Algol 68 doesn't support multiple loop ranges, so a sequence pf loops is used instead. <lang algol68>BEGIN
# translation of task PL/1 code, with minimal changes, semicolons required by # # PL/1 but not allowed in Algol 68 removed, unecessary rounding removed # # Note that in Algol 68, the loop counter is a local variable to the loop and # # the value of j is not available outside the loops # PROC loop body = ( INT j )VOID: #(below) ** is exponentiation: 4**3=64 # BEGIN sum +:= ABS j; #add absolute value of J.# IF ABS prod<2**27 AND j /= 0 THEN prod *:= j FI #PROD is small enough & J# # ABS(n) = absolute value# END; #not 0, then multiply it.# #SUM and PROD are used for verification of J incrementation.# INT prod := 1; #start with a product of unity. # INT sum := 0; # " " " sum " zero. # INT x := +5; INT y := -5; INT z := -2; INT one := 1; INT three := 3; INT seven := 7; FOR j FROM -three BY three TO ( 3**3 ) DO loop body( j ) OD; FOR j FROM -seven BY x TO +seven DO loop body( j ) OD; FOR j FROM 555 TO 550 - y DO loop body( j ) OD; FOR j FROM 22 BY -three TO -28 DO loop body( j ) OD; FOR j FROM 1927 TO 1939 DO loop body( j ) OD; FOR j FROM x BY z TO y DO loop body( j ) OD; FOR j FROM ( 11**x ) TO ( 11**x ) + one DO loop body( j ) OD; print((" sum= ", whole( sum,0), newline)); #display strings to term.# print(("prod= ", whole(prod,0), newline)) # " " " " #
END </lang>
- Output:
sum= 348173 prod= -793618560
ALGOL W
As with most of the other languages, Algol W doesn't support multiple loop ranges, so a sequence pf loops is used instead. <lang algolw>begin
% translation of task PL/1 code, with minimal changes, semicolons required by % % PL/1 but redundant in Algol W retained ( technically they introduce empty % % statements after the "if" in the loop body and before the final "end" ) % % Note that in Algol W, the loop counter is a local variable to the loop and % % the value of j is not available outside the loops % procedure loopBody ( integer value j ); %(below) ** is exponentiation: 4**3=64 % begin sum := sum + abs(j); %add absolute value of J.% if abs(prod)<2**27 and j not = 0 then prod := prod*j; %PROD is small enough & J% % ABS(n) = absolute value% end; %not 0, then multiply it.% %SUM and PROD are used for verification of J incrementation.% integer prod, sum, x, y, z, one, three, seven; prod := 1; %start with a product of unity. % sum := 0; % " " " sum " zero. % x := +5; y := -5; z := -2; one := 1; three := 3; seven := 7; for j := -three step three until round( 3**3 ) do loopBody( j ); for j := -seven step x until +seven do loopBody( j ); for j := 555 until 550 - y do loopBody( j ); for j := 22 step -three until -28 do loopBody( j ); for j := 1927 until 1939 do loopBody( j ); for j := x step z until y do loopBody( j ); for j := round( 11**x ) until round( 11**x ) + one do loopBody( j ); write(s_w := 0, " sum= ", sum); %display strings to term.% write(s_w := 0, "prod= ", prod); % " " " " %
end.</lang>
- Output:
sum= 348173 prod= -793618560
ARM Assembly
<lang ARM Assembly> /* ARM assembly Raspberry PI */ /* program loopnrange.s */
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly for the routine affichageMess conversion10 see at end of this program the instruction include */
/*********************************/ /* Constantes */ /*********************************/ .equ STDOUT, 1 @ Linux output console .equ EXIT, 1 @ Linux syscall .equ WRITE, 4 @ Linux syscall
/*********************************/ /* Initialized data */ /*********************************/ .data szMessResult: .ascii "" @ message result sMessValeur: .fill 11, 1, ' ' szCarriageReturn: .asciz "\n" /*********************************/ /* UnInitialized data */ /*********************************/ .bss iSum: .skip 4 @ this program store sum and product in memory iProd: .skip 4 @ it is possible to use registers r2 and r11 /*********************************/ /* code section */ /*********************************/ .text .global main main: @ entry of program
ldr r0,iAdriProd mov r1,#1 str r1,[r0] @ init product ldr r0,iAdriSum mov r1,#0 str r1,[r0] @ init sum
mov r5,#5 @ x mov r4,#-5 @ y mov r6,#-2 @ z mov r8,#1 @ one mov r3,#3 @ three mov r7,#7 @ seven
@ loop one mov r0,#3 mov r1,#3 bl computePow @ compute 3 pow 3 mov r10,r0 @ save result mvn r9,r3 @ r9 = - three add r9,#1
1:
mov r0,r9 bl computeSumProd add r9,r3 @ increment with three cmp r9,r10 ble 1b @ loop two mvn r9,r7 @ r9 = - seven add r9,#1
2:
mov r0,r9 bl computeSumProd add r9,r5 @ increment with x cmp r9,r7 @ compare to seven ble 2b
@ loop three mov r9,#550 sub r10,r9,r4 @ r10 = 550 - y mov r9,#555
3:
mov r0,r9 bl computeSumProd add r9,#1 cmp r9,r10 ble 3b @ loop four mov r9,#22
4:
mov r0,r9 bl computeSumProd sub r9,r3 @ decrement with three cmp r9,#-28 bge 4b @ loop five mov r9,#1927 ldr r10,iVal1939
5:
mov r0,r9 bl computeSumProd add r9,#1 cmp r9,r10 ble 5b @ loop six mov r9,r5 @ r9 = x mvn r10,r6 @ r10 = - z add r10,#1
6:
mov r0,r9 bl computeSumProd sub r9,r10 cmp r9,r4 bge 6b @ loop seven mov r0,r5 mov r1,#11 bl computePow @ compute 11 pow x add r10,r0,r8 @ + one mov r9,r0
7:
mov r0,r9 bl computeSumProd add r9,#1 cmp r9,r10 ble 7b @ display result ldr r0,iAdriSum ldr r0,[r0] ldr r1,iAdrsMessValeur @ signed conversion value bl conversion10S @ decimal conversion ldr r0,iAdrszMessResult bl affichageMess @ display message ldr r0,iAdrszCarriageReturn bl affichageMess @ display return line ldr r0,iAdriProd ldr r0,[r0] ldr r1,iAdrsMessValeur @ conversion value bl conversion10S @ signed decimal conversion ldr r0,iAdrszMessResult bl affichageMess @ display message ldr r0,iAdrszCarriageReturn bl affichageMess @ display return line
100: @ standard end of the program
mov r0, #0 @ return code mov r7, #EXIT @ request to exit program svc #0 @ perform the system call
iAdrsMessValeur: .int sMessValeur iAdrszMessResult: .int szMessResult iAdrszCarriageReturn: .int szCarriageReturn iVal1939: .int 1939 /******************************************************************/ /* compute the sum and prod */ /******************************************************************/ /* r0 contains the number */ computeSumProd:
push {r1-r4,lr} @ save registers asr r1,r0,#31 eor r2,r0,r1 sub r2,r2,r1 @ compute absolue value //vidregtit somme ldr r3,iAdriSum @ load sum ldr r1,[r3] add r1,r2 @ add sum str r1,[r3] @ store sum cmp r0,#0 @ j = 0 ? beq 100f @ yes ldr r3,iAdriProd ldr r1,[r3] asr r2,r1,#31 @ compute absolute value of prod eor r4,r1,r2 sub r2,r4,r2 cmp r2,#1<<27 @ compare 2 puissance 27 bgt 100f mul r1,r0,r1 str r1,[r3] @ store prod
100:
pop {r1-r4,lr} @ restaur registers bx lr @ return
iAdriSum: .int iSum iAdriProd: .int iProd /******************************************************************/ /* compute pow */ /******************************************************************/ /* r0 contains pow */ /* r1 contains number */ computePow:
push {r1-r2,lr} @ save registers mov r2,r0 mov r0,#1
1:
cmp r2,#0 ble 100f mul r0,r1,r0 sub r2,#1 b 1b
100:
pop {r1-r2,lr} @ restaur registers bx lr @ return
/***************************************************/ /* ROUTINES INCLUDE */ /***************************************************/ .include "../affichage.inc" </lang>
- Output:
+348173 -793618560
AutoHotkey
As with most of the other languages, AutoHotkey doesn't support multiple loop ranges, so a workaround function is used instead. <lang AutoHotkey>for_J(doFunction, start, stop, step:=1){ j := start while (j<=stop) && (start<=stop) && (step>0) %doFunction%(j), j+=step while (j>=stop) && (start>stop) && (step<0) %doFunction%(j), j+=step }</lang> Examples:<lang AutoHotkey>prod := 1 sum := 0 x := +5 y := -5 z := -2 one := 1 three := 3 seven := 7
for_J("doTHis", -three, 3**3, three) for_J("doTHis", -seven, +seven, x) for_J("doTHis", 555, 550-y) for_J("doTHis", 22, -28, -three) for_J("doTHis", 1927, 1939) for_J("doTHis", x, y, z) for_J("doTHis", 11**x, 11**x+one)
MsgBox % "sum = " RegExReplace(sum, "\B(?=(\d{3})+$)", ",") . "`nprod = " RegExReplace(prod, "\B(?=(\d{3})+$)", ",") return
- ----------------------------------------------
doThis(j){ global sum, prod sum += Abs(j) if (Abs(prod) < 2**27) && (j != 0) prod *= j } return</lang>
- Output:
sum = 348,173 prod = -793,618,560
AWK
<lang AWK>
- syntax: GAWK -f LOOPS_WITH_MULTIPLE_RANGES.AWK
BEGIN {
prod = 1 sum = 0 x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7 for (j=-three; j<=(3^3); j+=three) { main(j) } for (j=-seven; j<=seven; j+=x) { main(j) } for (j=555; j<=550-y; j++) { main(j) } for (j=22; j>=-28; j+=-three) { main(j) } for (j=1927; j<=1939; j++) { main(j) } for (j=x; j>=y; j+=z) { main(j) } for (j=(11^x); j<=(11^x)+1; j++) { main(j) } printf("sum = %d\n",sum) printf("prod = %d\n",prod) exit(0)
} function main(x) {
sum += abs(x) if (abs(prod) < (2^27) && x != 0) { prod *= x }
} function abs(x) { if (x >= 0) { return x } else { return -x } } </lang>
- Output:
sum = 348173 prod = -793618560
BASIC256
<lang BASIC256> global sum, prod
subroutine process(x) sum += abs(x) if abs(prod) < (2 ^ 27) and x <> 0 then prod *= x end subroutine
prod = 1 sum = 0 x = 5 : y = -5 : z = -2 one = 1 : three = 3 : seven = 7
for j = -three to (3 ^ 3) step three: call process(j): next j for j = -seven to seven step x: call process(j): next j for j = 555 to 550 - y: call process(j): next j for j = 22 to -28 step -three: call process(j): next j for j = 1927 to 1939: call process(j): next j for j = x to y step z: call process(j): next j for j = (11 ^ x) to (11 ^ x) + one: call process(j): next j
print " sum= "; int(sum) print "prod= "; int(prod) end </lang>
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- 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
C#
Multiple ranges don't exist in C# out-of-the-box but it is easy to make something. <lang csharp>using System; using System.Collections.Generic; using System.Linq;
public static class LoopsWithMultipleRanges {
public static void Main() { int prod = 1; int sum = 0; int x = 5; int y = -5; int z = -2; int one = 1; int three = 3; int seven = 7;
foreach (int j in Concat( For(-three, 3.Pow(3), three), For(-seven, seven, x), For(555, 550 - y), For(22, -28, -three), For(1927, 1939), For(x, y, z), For(11.Pow(x), 11.Pow(x) + one) )) { sum += Math.Abs(j); if (Math.Abs(prod) < (1 << 27) && j != 0) prod *= j; } Console.WriteLine($" sum = {sum:N0}"); Console.WriteLine($"prod = {prod:N0}"); }
static IEnumerable<int> For(int start, int end, int by = 1) { for (int i = start; by > 0 ? (i <= end) : (i >= end); i += by) yield return i; }
static IEnumerable<int> Concat(params IEnumerable<int>[] ranges) => ranges.Aggregate((acc, r) => acc.Concat(r)); static int Pow(this int b, int e) => (int)Math.Pow(b, e);
}</lang>
- Output:
sum = 348,173 prod = -793,618,560
Common Lisp
Using raw code and DO iterator <lang lisp> (let ((prod 1) ; Initialize aggregator
(sum 0) (x 5) ; Initialize variables (y -5) (z -2) (one 1) (three 3) (seven 7))
(flet ((loop-body (j) ; Set the loop function
(incf sum (abs j)) (if (and (< (abs prod) (expt 2 27)) (/= j 0)) (setf prod (* prod j)))))
(do ((i (- three) (incf i three))) ; Just a serie of individual loops
((> i (expt 3 3)))
(loop-body i)) (do ((i (- seven) (incf i x)))
((> i seven))
(loop-body i)) (do ((i 555 (incf i -1)))
((< i (- 550 y)))
(loop-body i)) (do ((i 22 (incf i (- three))))
((< i -28))
(loop-body i)) (do ((i 1927 (incf i)))
((> i 1939))
(loop-body i)) (do ((i x (incf i z)))
((< i y))
(loop-body i)) (do ((i (expt 11 x) (incf i)))
((> i (+ (expt 11 x) one)))
(loop-body i)))
(format t "~&sum = ~14<~:d~>" sum) (format t "~&prod = ~14<~:d~>" prod))
</lang> or with loop ranges and increments as list to dolist <lang lisp> (let ((prod 1)
(sum 0) (x 5) (y -5) (z -2) (one 1) (three 3) (seven 7))
(flet ((loop-body (j) ; Set the loop function
(incf sum (abs j)) (if (and (< (abs prod) (expt 2 27)) (/= j 0)) (setf prod (* prod j)))))
(dolist (lst `((,(- three) ,(expt 3 3) ,three)
(,(- seven) ,seven ,x) (555 ,(- 550 y) -1) (22 -28 ,(- three)) (1927 1939 1) (,x ,y ,z) (,(expt 11 x) ,(+ (expt 11 x) one) 1)))
(do ((i (car lst) (incf i (caddr lst))))
((if (plusp (caddr lst)) (> i (cadr lst)) (< i (cadr lst)))) (loop-body i))))
(format t "~&sum = ~14<~:d~>" sum) (format t "~&prod = ~14<~:d~>" prod))
</lang>
- Output:
sum = 348,173 prod = -793,618,560
Delphi
Delphi don't have for with multiples ranges and for with different increments (except +1 and -1). The workaround is using while loop. <lang Delphi> program with_multiple_ranges;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
var
prod: Int64 = 1; sum: Int64 = 0;
function labs(value: Int64): Int64; begin
Result := value; if value < 0 then Result := -Result;
end;
procedure process(j: Int64); begin
sum := sum + (abs(j)); if (labs(prod) < (1 shl 27)) and (j <> 0) then prod := prod * j;
end;
function ipow(n: Integer; e: Cardinal): Int64; var
pr: Int64; max, i: Cardinal;
begin
result := n; if e = 0 then Exit(1); max := e; for i := 2 to max do result := result * n;
end;
var
j: Int64; p: Int64;
const
x = 5; y = -5; z = -2; one = 1; three = 3; seven = 7;
begin
p := ipow(11, x);
j := -three; while j <= ipow(3, 3) do begin process(j); inc(j, three); end;
j := -seven; while j <= seven do begin process(j); inc(j, x); end;
j := 555; while j <= (550 - y) do begin process(j); inc(j, x); end;
j := 22; while j >= -28 do begin process(j); dec(j, three); end;
j := 1927; while j <= 1939 do begin process(j); inc(j); end;
j := x; while j >= y do begin process(j); dec(j, -z); end;
j := p; while j <= p + one do begin process(j); inc(j); end;
writeln(format('sum = %d ', [sum])); writeln(format('prod = %d ', [prod])); Readln;
end.</lang>
- Output:
sum = 348173 prod = -793618560
EasyLang
<lang>prod = 1 sum = 0 x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7 ranges[][] &= [ -three (pow 3 3) three ] ranges[][] &= [ -seven seven x ] ranges[][] &= [ 555 (550 - y) ] ranges[][] &= [ 22 -28 (-three) ] ranges[][] &= [ 1927 1939 ] ranges[][] &= [ x y z ] ranges[][] &= [ (pow 11 x) (pow 11 x + one) ]
for i range len ranges[][]
j = ranges[i][0] to = ranges[i][1] inc = 1 if len ranges[i][] = 3 inc = ranges[i][2] . repeat until inc > 0 and j > to or inc < 0 and j < to sum += abs j if abs prod < pow 2 27 and j <> 0 prod *= j . j += inc .
. print sum print prod</lang>
Eiffel
Eiffel does not support multiple ranges in the same fashion as PL/I. However, it does have an across loop, which does the trick, together with an inline agent (lambda function). <lang eiffel> class APPLICATION
create make
feature
prod, sum, x, y, z, one, three, seven: INTEGER
make local process: PROCEDURE do prod := 1; x := 5; y := -5; z := -2; one := 1; three := 3; seven := 7 process := (agent (j: INTEGER) do print (j.out + ", ") sum := sum + j.abs if prod.abs < 2^27 and j /= 0 then prod := prod * j end end)
across (-three |..| (3^3).truncated_to_integer).new_cursor + (three - 1) as ic loop process.call (ic.item) end across (-seven |..| seven).new_cursor + (x - 1) as ic loop process.call (ic.item) end across 555 |..| (550 - y) as ic loop process.call (ic.item) end across (-26 |..| 22).new_cursor + (three - 1) as ic loop process.call (ic.item) end across 1927 |..| 1939 as ic loop process.call (ic.item) end across (y |..| x).new_cursor + (-z - 1) as ic loop process.call (ic.item) end across (11^x).truncated_to_integer |..| ((11^x).truncated_to_integer + 1) as ic loop process.call (ic.item) end
print ("%N") print ("sum = " + sum.out + "%N") -- sum = 348,173 print ("prod = " + prod.out + "%N") -- prod = -793,618,560 end
end </lang>
Alternatively, there is the "symbolic form" of the across loop, which modifies the code as follows:
<lang eiffel> class APPLICATION
create make
feature
prod, sum, x, y, z, one, three, seven: INTEGER
make local process: PROCEDURE do prod := 1; x := 5; y := -5; z := -2; one := 1; three := 3; seven := 7 process := (agent (j: INTEGER) do print (j.out + ", ") sum := sum + j.abs if prod.abs < 2^27 and j /= 0 then prod := prod * j end end)
⟳ ic: (-three |..| (3^3).truncated_to_integer).new_cursor + (three - 1) ¦ process.call (ic) ⟲ ⟳ ic: (-seven |..| seven).new_cursor + (x - 1) ¦ process.call (ic) ⟲ ⟳ ic:555 |..| (550 - y) ¦ process.call (ic) ⟲ ⟳ ic: (-26 |..| 22).new_cursor + (three - 1) ¦ process.call (ic) ⟲ ⟳ ic: 1927 |..| 1939 ¦ process.call (ic) ⟲ ⟳ ic: (y |..| x).new_cursor + (-z - 1) ¦ process.call (ic) ⟲ ⟳ ic: (11^x).truncated_to_integer |..| ((11^x).truncated_to_integer + 1) ¦ process.call (ic) ⟲
print ("%N") print ("sum = " + sum.out + "%N") -- sum = 348,173 print ("prod = " + prod.out + "%N") -- prod = -793,618,560 end
end </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
FreeBASIC
<lang freebasic> Dim Shared As Long prod, sum
Sub process(x As Long)
sum += Abs(x) If Abs(prod) < (2 ^ 27) And x <> 0 Then prod *= x
End Sub
Dim j As Long prod = 1 sum = 0 Dim As Integer x = 5, y = -5, z = -2 Dim As Integer one = 1, three = 3, seven = 7
For j = -three To (3 ^ 3) Step three: process(j): Next j For j = -seven To seven Step x: process(j): Next j For j = 555 To 550 - y: process(j): Next j For j = 22 To -28 Step -three: process(j): Next j For j = 1927 To 1939: process(j): Next j For j = x To y Step z: process(j): Next j For j = (11 ^ x) To (11 ^ x) + one: process(j): Next j
Print Using " sum= ###,###"; sum Print Using "prod= ####,###,###"; prod Sleep </lang>
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
Groovy
Solution: <lang groovy>def (prod, sum, x, y, z, one, three, seven) = [1, 0, +5, -5, -2, 1, 3, 7]
for (
j in ( ((-three) .. (3**3) ).step(three) + ((-seven) .. (+seven) ).step(x) + (555 .. (550-y) ) + (22 .. (-28) ).step(three) // This is correct! // Groovy interprets positive step size as stride through the LIST ELEMENTS as ordered // and negative step size as stride through the REVERSED LIST ELEMENTS as ordered // so step(-3) gives: -28, -25, -22, ... , 20 // while step(3) gives: 22, 19, 16, ... , -26 + (1927 .. 1939 ) + (x .. y ).step(z) + (11**x .. (11**x + one)) )
) {
sum = sum + j.abs() if ( prod.abs() < 2**27 && j != 0) prod *= j
}
println " sum= ${sum}" println "prod= ${prod}"</lang>
Output:
sum= 348177 prod= -793618560
Haskell
Haskell does not have loops. Programmers use either explicit recursion or recursive schemes (folds or unfolds) for looping. The following code mimics the PL/1 example using composition of left folds in order to handle multiple ranges:
<lang haskell>loop :: (b -> a -> b) -> b -> a -> b loop = foldl . foldl
example = let
x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7 in loop -- body ( \(sum, prod) j -> ( sum + abs j, if abs prod < 2^27 && j /= 0 then prod * j else prod ) ) -- initial state (0, 1) -- ranges [ [-three, -three + three .. 3^3] , [-seven, -seven + x .. seven] , [555 .. 550 - y] , [22, 22 - three .. -28] , [1927 .. 1939] , [x, x + z .. y] , [11^x .. 11^x + one] ]</lang>
J
J uses the names x, y, m, n, u, v to pass arguments into explicit definitions. Treating these as reserved names is reasonable practice. Originally these had been x. , y. etceteras however the dots must have been deemed "noisy".
We've passed the range list argument literally for evaluation in local scope. Verb f evaluates and concatenates the ranges, then perhaps the ensuing for. loop looks somewhat like familiar code.
<lang j> NB. http://rosettacode.org/wiki/Loops/Wrong_ranges#J NB. define range as a linear polynomial start =: 0&{ stop =: 1&{ increment =: 2&{ :: 1: NB. on error use 1 range =: (start , increment) p. [: i. [: >: [: <. (stop - start) % increment
f =: 3 :0
input =. y 'prod sum x y z one three seven' =. 1 0 5 _5 _2 1 3 7 J =. ([: ; range&.>) ". input for_j. J do. sum =. sum + | j if. ((|prod)<2^27) *. (0 ~: j) do. prod =. prod * j end. end. sum , prod
) </lang>
] A =: f '((-three), (3^3), three); ((-seven),seven,x); (555 , 550-y); (22 _28, -three); 1927 1939; (x,y,z); (0 1 + 11^x)' 348173 _7.93619e8 20j0 ": A 348173 _793618560
Java
Java does not support multiple ranges. Use list to simulate multiple ranges. Accumulate values in a list, then iterate over the list.
With Java 8, streams are available. Streams can be concatenated. However, the Java 9 feature takeWhile
is important to this task to specify the iteration limit.
Maintain formatting similar to the original code.
<lang java> import java.util.ArrayList; import java.util.List;
public class LoopsWithMultipleRanges {
private static long sum = 0; private static long prod = 1; public static void main(String[] args) { long x = 5; long y = -5; long z = -2; long one = 1; long three = 3; long seven = 7; List<Long> jList = new ArrayList<>(); for ( long j = -three ; j <= pow(3, 3) ; j += three ) jList.add(j); for ( long j = -seven ; j <= seven ; j += x ) jList.add(j); for ( long j = 555 ; j <= 550-y ; j += 1 ) jList.add(j); for ( long j = 22 ; j >= -28 ; j += -three ) jList.add(j); for ( long j = 1927 ; j <= 1939 ; j += 1 ) jList.add(j); for ( long j = x ; j >= y ; j += z ) jList.add(j); for ( long j = pow(11, x) ; j <= pow(11, x) + one ; j += 1 ) jList.add(j);
List<Long> prodList = new ArrayList<>(); for ( long j : jList ) { sum += Math.abs(j); if ( Math.abs(prod) < pow(2, 27) && j != 0 ) { prodList.add(j); prod *= j; } } System.out.printf(" sum = %,d%n", sum); System.out.printf("prod = %,d%n", prod); System.out.printf("j values = %s%n", jList); System.out.printf("prod values = %s%n", prodList); } private static long pow(long base, long exponent) { return (long) Math.pow(base, exponent); }
} </lang>
- Output:
sum = 348,173 prod = -793,618,560 j values = [-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] prod values = [-3, 3, 6, 9, 12, 15, 18, 21, 24]
jq
Works with gojq, the Go implementation of jq
jq is stream-oriented, and so the "multiple ranges" feature comes for free, that is, it just involves stream concatenation with the "," operator.
The only wrinkle is that jq's `range` filters exclude the "right-hand" limit; to facilitate comparison with the PL/I code, the adjustment (e.g. "1 + ...") has been made explicit.
Since the only variables that are updated within the body of the loop are "sum" and "prod", the others could be defined as constants (i.e. as $-variables), but again to facilitate comparison with the PL/I code, this has not been done.
<lang jq>
- If using gojq, one may want to preserve integer precision, so:
def power($b): . as $in | reduce range(0;$b) as $i (1; . * $in);
{ prod: 1, # start with a product of unity.
sum: 0, # henceforth skip redundant comments. x: 5, y: -5, z: -2, one: 1, three: 3, seven: 7 }
| .x as $x | reduce (range(-.three; 1 + 3|power(3); .three),
range(-.seven; 1 + .seven; .x), range( 555; 1 + 550 - .y), range( 22; -1 -28; -.three), range(1927 ; 1 + 1939), range(.x ; .y; .z), range(11|power($x); 1 + ( 11 | power($x)) + .one)) as $j (.; .sum += ($j|length) # add absolute value of $j (!) | if (.prod|length) < (2|power(27)) and $j != 0
then .prod *= $j else . end ) | "sum= \(.sum)",
"prod= \(.prod)"
</lang>
- Output:
sum= 348726 prod= -793618560
Julia
Julia allows concatenation of iterators with the ; iterator within a vector. An attempt was made to preserve the shape of the PL/1 code. <lang julia>using Formatting
function PL1example()
# 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 for j in [ -three : three : 3^3 ; -seven : x : +seven ; 555 : 550 - y ; 22 : -three : -28 ; 1927 : 1939 ; x : z : y ; 11^x : 11^x + one ] # ABS(n) = absolute value sum = sum + abs(j); # add absolute value of J. if abs(prod) < 2^27 && j !=0 prod = prod*j # PROD is small enough & J end; # not 0, then multiply it. end # SUM and PROD are used for verification of J incrementation. println(" sum = $(format(sum, commas=true))"); # display strings to term. println("prod = $(format(prod, commas=true))"); # " " " "
end
PL1example()
</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
M2000 Interpreter
Using lambda functions and a final While End While to perform a multiple range.
Values by default are double, but we can make them Long (32 bit integer), or Decimal or Currency or single (prod for single has less accuracy here), but not integer (16 bit) because we get overflow.
In M2000 expressions can change numeric type to hold the produced value. Variables take once the type, so we get overflow if we pass a value frome an expression which can't convert to variable's type.
<lang M2000 Interpreter>Module MultipleLoop { def long prod=1, sum=0, x=+5,y=-5, z=-2, one=1, three=3, seven=7, j Range=lambda (a, b, c=1) ->{ =lambda a, b, c (&f)-> { if compare(a,b)=sgn(c) then =false else =true: f=a: a+=c } } MultipleRange=Lambda -> { a=array([]) ' convert stack items in current stack [] to an array of items =lambda a, k=0 (&f) ->{ do : if k<len(a) Else exit if a#eval(k, &f) then =true: exit k++ : always } } Exec=MultipleRange(Range(-three, 3**3, three), Range(-seven, +seven, x), Range(555, 550-y), Range(22, -28, -three), Range(1927, 1939), Range(x,y,z), Range(11**x, 11**x+one)) j=0 while Exec(&j) sum+=abs(j) if abs(prod) < 2^27 And j <> 0 then prod*=j End While
Print "sum=";sum Print "prod=";prod } MultipleLoop </lang>
- Output:
sum=348173 prod=-793618560
Mathematica / Wolfram Language
<lang Mathematica>prod = 1; sum = 0; x = 5; y = -5; z = -2; one = 1; three = 3; seven = 7; Do[
sum += Abs[j]; If[Abs[prod] < 2^27 \[And] j != 0, prod *= j]; , {j, Join[ Range[-three, 3^3, three], Range[-seven, seven, x], Range[555, 550 - y], Range[22, -28, -three], Range[1927, 1939], Range[x, y, z], Range[11^x, 11^x + one] ] } ]
sum prod</lang>
- Output:
348173 -793618560
Nim
Nim doesn’t provide loops with multiple ranges. There are several ways to translate the PL/1 program: using a sequence of for loops, using a sequence of while loops, using an iterator and, probably, too, some way using macros.
Using a sequence of loops
This solution is the obvious one, but it supposes that the direction of the loop is known (i.e. the sign of the step is known) as we have to choose between iterators “countup” and “countdown”. Using this method, the PL/1 example can be translated the following way:
<lang Nim> import math, strutils
var
prod = 1 sum = 0
let
x = +5 y = -5 z = -2 one = 1 three = 3 seven = 7
proc body(j: int) =
sum += abs(j) if abs(prod) < 2^27 and j != 0: prod *= j
for j in countup(-three, 3^3, three): body(j)
for j in countup(-seven, seven, x): body(j)
for j in countup(555, 550 - y): body(j)
for j in countdown(22, -28, three): body(j)
for j in countup(1927, 1939): body(j)
for j in countdown(x, y, -z): body(j)
for j in countup(11^x, 11^x + one): body(j)
let s = ($sum).insertSep(',') let p = ($prod).insertSep(',') let m = max(s.len, p.len) echo " sum = ", s.align(m) echo "prod = ", p.align(m)</lang>
Note that for “countdown” we must change the sign of the step to insure that it is positive.
- Output:
sum = 348,173 prod = -793,618,560
Using an iterator
If the sign of the step is not known (or may vary), it is no longer possible to use the previous method. One could use a while loop but it seems better to use an iterator.
<lang Nim>import math, strutils
var
prod = 1 sum = 0
let
x = +5 y = -5 z = -2 one = 1 three = 3 seven = 7
type Range = tuple[first, last, step: int]
func initRange(first, last, step = 1): Range = (first, last, step)
iterator loop(ranges: varargs[Range]): int =
for r in ranges: if r.step > 0: for i in countup(r.first, r.last, r.step): yield i elif r.step < 0: for i in countdown(r.first, r.last, -r.step): yield i else: raise newException(ValueError, "step cannot be zero")
for j in loop(initRange(-three, 3^3, three),
initRange(-seven, seven, x), initRange(555, 550 - y), initRange(22, -28, three), initRange(1927, 1939), initRange(x, y, -z), initRange(11^x, 11^x + one)): sum += abs(j) if abs(prod) < 2^27 and j != 0: prod *= j
let s = ($sum).insertSep(',') let p = ($prod).insertSep(',') let m = max(s.len, p.len) echo " sum = ", s.align(m) echo "prod = ", p.align(m)</lang>
Note that we have defined a function “initRange” to create the ranges. This is needed to make the step optional. If we suppressed this requirement (i.e. we required the step to be always specified), we could get ride of “initRange” and write the loop this way:
<lang Nim>for j in loop((-three, 3^3, three),
(-seven, seven, x), (555, 550 - y), (22, -28, three), (1927, 1939, 1), (x, y, -z), (11^x, 11^x + one)): sum += abs(j) if abs(prod) < 2^27 and j != 0: prod *= j</lang>
Perl
<lang perl>use constant one => 1; use constant three => 3; use constant seven => 7; use constant x => 5; use constant yy => -5; # 'y' conflicts with use as equivalent to 'tr' operator (a carry-over from 'sed') use constant z => -2;
my $prod = 1;
sub from_to_by {
my($begin,$end,$skip) = @_; my $n = 0; grep{ !($n++ % abs $skip) } $begin <= $end ? $begin..$end : reverse $end..$begin;
}
sub commatize {
(my $s = reverse shift) =~ s/(.{3})/$1,/g; $s =~ s/,(-?)$/$1/; $s = reverse $s;
}
for my $j (
from_to_by(-three,3**3,three), from_to_by(-seven,seven,x), 555 .. 550 - yy, from_to_by(22,-28,-three), 1927 .. 1939, from_to_by(x,yy,z), 11**x .. 11**x+one, ) { $sum += abs($j); $prod *= $j if $j and abs($prod) < 2**27;
}
printf "%-8s %12s\n", 'Sum:', commatize $sum; printf "%-8s %12s\n", 'Product:', commatize $prod;</lang>
- Output:
Sum: 348,173 Product: -793,618,560
Phix
integer prod = 1, total = 0, -- (renamed as sum is a Phix builtin) x = +5, y = -5, z = -2, one = 1, three = 3, seven = 7 sequence loopset = {{ -three, power(3,3), three }, { -seven, +seven, x }, { 555, 550 - y, 1 }, { 22, -28, -three}, { 1927, 1939, 1 }, { x, y, z }, {power(11,x), power(11,x) + one, 1 }} for i=1 to length(loopset) do integer {f,t,s} = loopset[i] for j=f to t by s do total += abs(j) if abs(prod)<power(2,27) and j!=0 then prod *= j end if end for end for printf(1," sum = %,d\n",total) printf(1,"prod = %,d\n",prod)
- Output:
sum = 348,173 prod = -793,618,560
Prolog
Prolog does not have the richness of some other languages where it comes to loops, variables and the like, but does have some rather interesting features such as difference lists and backtracking for generating solutions. <lang prolog>for(Lo,Hi,Step,Lo) :- Step>0, Lo=<Hi. for(Lo,Hi,Step,Val) :- Step>0, plus(Lo,Step,V), V=<Hi, !, for(V,Hi,Step,Val). for(Hi,Lo,Step,Hi) :- Step<0, Lo=<Hi. for(Hi,Lo,Step,Val) :- Step<0, plus(Hi,Step,V), Lo=<V, !, for(V,Lo,Step,Val).
sym(x,5). % symbolic lookups for values sym(y,-5). sym(z,-2). sym(one,1). sym(three,3). sym(seven,7).
range(-three,3^3,three). % as close as we can syntactically get range(-seven,seven,x). range(555,550-y,1). range(22,-28, -three). range(1927,1939,1). range(x,y,z). range(11^x,11^x+one,1).
translate(V, V) :- number(V), !. % difference list based parser translate(S, V) :- sym(S,V), !. translate(-S, V) :- translate(S,V0), !, V is -V0. translate(A+B, V) :- translate(A,A0), translate(B, B0), !, V is A0+B0. translate(A-B, V) :- translate(A,A0), translate(B, B0), !, V is A0-B0. translate(A^B, V) :- translate(A,A0), translate(B, B0), !, V is A0^B0.
range_value(Val) :- % enumerate values for all ranges in order range(From,To,Step), translate(From,F), translate(To,T), translate(Step,S), for(F,T,S,Val).
calc_values([], S, P, S, P). % calculate all values in generated order calc_values([J|Js], S, P, Sum, Product) :-
S0 is S + abs(J), ((abs(P)< 2^27, J \= 0) -> P0 is P * J; P0=P), !, calc_values(Js, S0, P0, Sum, Product).
calc_values(Sum, Product) :- % Find the sum and product findall(V, range_value(V), Values), calc_values(Values, 0, 1, Sum, Product).</lang>
?- calc_values(Sum, Product). Sum = 348173, Product = -793618560.
PureBasic
<lang purebasic>#X = 5 : #Y = -5 : #Z = -2
- ONE = 1 : #THREE = 3 : #SEVEN = 7
Define j.i Global prod.i = 1, sum.i = 0
Macro ipow(n, e)
Int(Pow(n, e))
EndMacro
Macro ifn(x)
FormatNumber(x,0,".",",")
EndMacro
Macro loop_for(start, stop, step_for=1)
For j = start To stop Step step_for proc(j) Next
EndMacro
Procedure proc(j.i)
sum + Abs(j) If (Abs(prod) < ipow(2 , 27)) And (j<>0) prod * j EndIf
EndProcedure
loop_for(-#THREE, ipow(3, 3), #THREE) loop_for(-#SEVEN, #SEVEN, #X) loop_for(555, 550 - #Y) loop_for(22, -28, -#THREE) loop_for(1927, 1939) loop_for(#X, #Y, #Z) loop_for(ipow(11, #X), ipow(11, #X) + 1)
If OpenConsole("Loops/with multiple ranges")
PrintN("sum = " + ifn(sum)) PrintN("prod = " + ifn(prod)) Input()
EndIf</lang>
- Output:
sum = 348,173 prod = -793,618,560
Python
Pythons range function does not include the second argument hence the definition of _range() <lang python>from itertools import chain
prod, sum_, x, y, z, one,three,seven = 1, 0, 5, -5, -2, 1, 3, 7
def _range(x, y, z=1):
return range(x, y + (1 if z > 0 else -1), z)
print(f'list(_range(x, y, z)) = {list(_range(x, y, z))}') print(f'list(_range(-seven, seven, x)) = {list(_range(-seven, seven, x))}')
for j in chain(_range(-three, 3**3, three), _range(-seven, seven, x),
_range(555, 550 - y), _range(22, -28, -three), _range(1927, 1939), _range(x, y, z), _range(11**x, 11**x + 1)): sum_ += abs(j) if abs(prod) < 2**27 and (j != 0): prod *= j
print(f' sum= {sum_}\nprod= {prod}')</lang>
- Output:
list(_range(x, y, z)) = [5, 3, 1, -1, -3, -5] list(_range(-seven, seven, x)) = [-7, -2, 3] sum= 348173 prod= -793618560
Raku
(formerly Perl 6)
This task is really conflating two separate things, (at least in Raku). Sequences and loops are two different concepts and may be considered / implemented separately from each other.
Yes, you can generate a sequence with a loop, and a loop can use a sequence for an iteration value, but the two are somewhat orthogonal and don't necessarily overlap.
Sequences are first class objects in Raku. You can (and typically do) generate a sequence using the (appropriately enough) sequence operator and can assign it to a variable and/or pass it as a parameter; the entire sequence, not just it's individual values. It may be used in a looping construct, but it is not necessary to do so.
Various looping constructs often do use sequences as their iterator but not exclusively, possibly not even in the majority.
Displaying the j sequence as well since it isn't very large.
<lang perl6>sub comma { ($^i < 0 ?? '-' !! ) ~ $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²⁷;
- Or, 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.
- Note that these operators will only work for monotonic sequences.
sub infix:<to> { $^a ... $^b } sub infix:<by> { $^a[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
Red
As "to" has another meaning in Red, we name "->" the range operator. <lang>Red ["For loop with multiple ranges"]
->: make op! function [start end][
res: copy [] repeat n 1 + absolute to-integer end - start [ append res start + either start > end [1 - n][n - 1] ]
] by: make op! function [s w] [extract s absolute w]
for: function ['word ranges body][
inp: copy [] foreach c reduce ranges [append inp c] foreach i inp [set word i do body]
]
prod: 1 sum: 0 x: +5 y: -5 z: -2 one: 1
three: 3 seven: 7
for j [
0 - three -> (3 ** 3) by three 0 - seven -> seven by x 555 -> (550 - y) 22 -> -28 by (0 - three) 1927 -> 1939 x -> y by z 11 ** x -> (11 ** x + one)
] [
sum: sum + absolute j; if all [(absolute prod) < power 2 27 j <> 0] [prod: prod * j]
] print ["sum: " sum "^/prod:" prod]</lang>
- Output:
sum: 348173 prod: -793618560
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
Ring
<lang ring> prod = 1 total = 0 x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7
loopset = [[-three,pow(3,3),three],
[-seven,seven,x], [555,550 - y,1], [22,-28,-three], [1927,1939,1], [x,y,z], [pow(11,x),pow(11,x) + one,1]]
for i=1 to len(loopset)
f = loopset[i][1] t = loopset[i][2] s = loopset[i][3] for j=f to t step s total += fabs(j) if fabs(prod)<pow(2,27) and j!=0 prod *= j ok next
next
see "total = " + total + nl see "product = " + prod + nl </lang>
- Output:
total = 348173 product = -793618560
Ruby
Uses chaining of enumerables, which was introduced with Ruby 2.6 <lang Ruby>x, y, z, one, three, seven = 5, -5, -2, 1, 3, 7
enums = (-three).step(3**3, three) +
(-seven).step(seven, x) + 555 .step(550-y, -1) + 22 .step(-28, -three) + (1927..1939) + # just toying, 1927.step(1939) is fine too x .step(y, z) + (11**x) .step(11**x + one)
- enums is an enumerator, consisting of a bunch of chained enumerators,
- none of which has actually produced a value.
puts "Sum of absolute numbers: #{enums.sum(&:abs)}" prod = enums.inject(1){|prod, j| ((prod.abs < 2**27) && j!=0) ? prod*j : prod} puts "Product (but not really): #{prod}" </lang>
- Output:
Sum of absolute numbers: 348173 Product (but not really): -793618560
Smalltalk
Ranges (called Interval in Smalltalk) are collections, which - like all collections - can be concatenated with the , (comma) message. Intervals are created by sending a to: or to:by: message to a magnitude-like thingy (i.e. other than numbers are possible): <lang smalltalk>prod := 1. sum := 0. x := 5. y := -5. z := -2. one := 1. three := 3. seven := 7.
(three negated to: 3**3 by: three ) , (seven negated to: seven by: x ) , (555 to: 550-y ) , (22 to: -28 by: three negated) , (1927 to: 1939 ) , (x to: y by:z ) , (11**x to: 11**x + one )
do:[:j | sum := sum + j abs. ((prod abs < (2**27)) and:[ j ~= 0 ]) ifTrue:[ prod := prod*j ]. ].
Transcript show:' sum = '; showCR:sum.
Transcript show:'prod = '; showCR:prod</lang>
The above creates a temporary "collection of ranges" and enumerates that, which might be inconvenient, if the collections are huge.
One alternative is to loop over each individually.
Of course, we definitely don't want to retype the loop body
and we usually don't want to the code to be non-local (i.e. define another method for it).
That's what blocks (aka lambdas or anonymous functions) are perfect for:
<lang smalltalk>prod := 1.
sum := 0.
x := 5.
y := -5.
z := -2.
one := 1.
three := 3.
seven := 7.
action :=
[:j | sum := sum + j abs. ((prod abs < (2**27)) and:[ j ~= 0 ]) ifTrue:[ prod := prod*j ]. ].
(three negated to: 3**3 by: three ) do:action. (seven negated to: seven by: x ) do:action. (555 to: 550-y ) do:action. (22 to: -28 by: three negated) do:action. (1927 to: 1939 ) do:action. (x to: y by:z ) do:action. (11**x to: 11**x + one ) do:action. Transcript show:' sum = '; showCR:sum. Transcript show:'prod = '; showCR:prod</lang>
As another alternative to the first solution above, we can loop over the ranges. This avoids the concatenations and generation of the intermediate big collection (which does not really make a difference here, but would, if each collection consisted of millions of objects):
<lang smalltalk>...
{
(three negated to: 3**3 by: three ) . (seven negated to: seven by: x ) . (555 to: 550-y ) . (22 to: -28 by: three negated) . (1927 to: 1939 ) . (x to: y by:z ) . (11**x to: 11**x + one ) .
} do:[:eachRange |
eachRange select:[:j | ((prod abs < (2**27)) and:[ j ~= 0 ]) ] thenDo:[:j | prod := prod*j ]. ]
]. ...</lang> Notice: this creates only 8 objects and also demonstrates an alternative element selection scheme, which may be more readable.
- Output:
sum = 348173 prod = -793618560
Note) Dialects with no **-method should use raisedTo:, or else define an alias for it in Number as: <lang smalltalk>** arg
^ self raisedTo: arg</lang>
True BASIC
<lang qbasic> SUB process(x)
LET sum = sum + abs(x) IF abs(prod) < (2 ^ 27) and x <> 0 then LET prod = prod * x
END SUB
LET prod = 1 LET sum = 0 LET x = 5 LET y = -5 LET z = -2 LET one = 1 LET three = 3 LET seven = 7
FOR j = -three to (3 ^ 3) step three
CALL process(j)
NEXT j FOR j = -seven To seven Step x
CALL process(j)
NEXT j FOR j = 555 to 550 - y
CALL process(j)
NEXT j FOR j = 22 to -28 step -three
CALL process(j)
NEXT j FOR j = 1927 to 1939
CALL process(j)
NEXT j FOR j = x to y step z
CALL process(j)
NEXT j FOR j = (11 ^ x) to (11 ^ x) + one
CALL process(j)
NEXT j PRINT " sum= "; sum PRINT "prod= "; prod END </lang>
Vala
<lang vala>const int CHARBIT = 8; long prod = 1; long sum = 0;
long labs(long n) {
long mask = n >> ((long)sizeof(long) * CHARBIT - 1); return ((n + mask) ^ mask);
}
long lpow(long base_num, long exp) {
long result = 1; while (true) { if ((exp & 1) != 0) result *= base_num; exp >>= 1; if (exp == 0) break; base_num *= base_num; } return result;
}
void process(long j) {
sum += labs(j); if (labs(prod) < (1 << 27) && j != 0) prod *= j;
}
void main() {
const int x = 5; const int y = -5; const int z = -2; const int one = 1; const int three = 3; const int seven = 11; long p = lpow(11, x); for (int j = -three; j <= lpow(3, 3); j += three ) process(j); for (int j = -seven; j <= seven; j += x) process(j); for (int j = 555; j <= 550 - y; ++j) process(j); for (int j = 22; j >= -28; j -= three) process(j); for (int j = 1928; j <= 1939; ++j) process(j); for (int j = x; j >= y; j -= -z) process(j); for (long j = p; j <= p + one; ++j) process(j); stdout.printf("sum = %10ld\n", sum); stdout.printf("prod = %10ld\n", prod);
}</lang>
- Output:
sum = 346265 prod = -793618560
VBA
<lang VB>Dim prod As Long, sum As Long Public Sub LoopsWithMultipleRanges()
Dim x As Integer, y As Integer, z As Integer, one As Integer, three As Integer, seven As Integer, j As Long prod = 1 sum = 0 x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7 For j = -three To pow(3, 3) Step three: Call process(j): Next j For j = -seven To seven Step x: Call process(j): Next j For j = 555 To 550 - y: Call process(j): Next j For j = 22 To -28 Step -three: Call process(j): Next j For j = 1927 To 1939: Call process(j): Next j For j = x To y Step z: Call process(j): Next j For j = pow(11, x) To pow(11, x) + one: Call process(j): Next j Debug.Print " sum= " & Format(sum, "#,##0") Debug.Print "prod= " & Format(prod, "#,##0")
End Sub Private Function pow(x As Long, y As Integer) As Long
pow = WorksheetFunction.Power(x, y)
End Function Private Sub process(x As Long)
sum = sum + Abs(x) If Abs(prod) < pow(2, 27) And x <> 0 Then prod = prod * x
End Sub</lang>
- Output:
sum= 348.173 prod= -793.618.560
Visual Basic .NET
VB.NET loops can't have multiple ranges, so this implementation will use the For Each loop and demonstrate various functions that produce concatenated ranges.
Composite formatting is used to add digit separators.
Using the following to provide the functionality of the For loop as a function, <lang vbnet>Partial Module Program
' Stop and Step are language keywords and must be escaped with brackets. Iterator Function Range(start As Integer, [stop] As Integer, Optional [step] As Integer = 1) As IEnumerable(Of Integer) For i = start To [stop] Step [step] Yield i Next End Function
End Module</lang>
and Enumerable.Concat (along with extension method syntax) to splice the ranges, the program ends up looking like this:
<lang vbnet>Imports System.Globalization
Partial Module Program
Sub Main() ' All variables are inferred to be of type Integer. Dim prod = 1, sum = 0, x = +5, y = -5, z = -2, one = 1, three = 3, seven = 7
' The exponent operator compiles to a call to Math.Pow, which returns Double, and so must be converted back to Integer. For Each j In Range(-three, CInt(3 ^ 3), 3 ). Concat(Range(-seven, +seven, x )). Concat(Range(555, 550 - y )). Concat(Range(22, -28, -three)). Concat(Range(1927, 1939 )). Concat(Range(x, y, z )). Concat(Range(CInt(11 ^ x), CInt(11 ^ x) + one ))
sum = sum + Math.Abs(j) If Math.Abs(prod) < 2 ^ 27 AndAlso j <> 0 Then prod = prod * j Next
' The invariant format info by default has two decimal places. Dim format As New NumberFormatInfo() With { .NumberDecimalDigits = 0 }
Console.WriteLine(String.Format(format, " sum= {0:N}", sum)) Console.WriteLine(String.Format(format, "prod= {0:N}", prod)) End Sub
End Module</lang>
To improve the program's appearance, a ConcatRange method can be defined to combine the two method calls, <lang vbnet> <Runtime.CompilerServices.Extension>
Function ConcatRange(source As IEnumerable(Of Integer), start As Integer, [stop] As Integer, Optional [step] As Integer = 1) As IEnumerable(Of Integer) Return source.Concat(Range(start, [stop], [step])) End Function</lang>
which results in a loop that looks like this: <lang vbnet> For Each j In Range(-three, CInt(3 ^ 3), 3 ).
ConcatRange(-seven, +seven, x ). ConcatRange(555, 550 - y ). ConcatRange(22, -28, -three). ConcatRange(1927, 1939 ). ConcatRange(x, y, z ). ConcatRange(CInt(11 ^ x), CInt(11 ^ x) + one ) Next</lang>
An alternative to avoid the repeated method calls would be to make a Range function that accepts multiple ranges, in this case as a parameter array of tuples. <lang vbnet> Function Range(ParamArray ranges() As (start As Integer, [stop] As Integer, [step] As Integer)) As IEnumerable(Of Integer)
' Note: SelectMany is equivalent to bind, flatMap, etc. Return ranges.SelectMany(Function(r) Range(r.start, r.stop, r.step)) End Function</lang>
resulting in: <lang vbnet> For Each j In Range((-three, CInt(3 ^ 3), 3 ),
(-seven, +seven, x ), (555, 550 - y, 1 ), (22, -28, -three ), (1927, 1939, 1 ), (x, y, z ), (CInt(11 ^ x), CInt(11 ^ x) + one, 1 )) Next</lang>
Note, however, that the inability to have a heterogenous array means that specifying the step is now mandatory. Using a parameter array of arrays is slightly less clear but results in the tersest loop. <lang vbnet> Function Range(ParamArray ranges As Integer()()) As IEnumerable(Of Integer)
Return ranges.SelectMany(Function(r) Range(r(0), r(1), If(r.Length < 3, 1, r(2)))) End Function</lang>
<lang vbnet> For Each j In Range({-three, CInt(3 ^ 3), 3 },
{-seven, +seven, x }, {555, 550 - y }, {22, -28, -three }, {1927, 1939 }, {x, y, z }, {CInt(11 ^ x), CInt(11 ^ x) + one }) Next</lang>
- Output (for all variations):
sum= 348,173 prod= -793,618,560
Wren
<lang ecmascript>import "/fmt" for Fmt
var prod = 1 var sum = 0 var x = 5 var y = -5 var z = -2 var one = 1 var three = 3 var seven = 7 var p = 11.pow(x) var j = 0
var process = Fn.new {
sum = sum + j.abs if (prod.abs < (1 << 27) && j != 0) prod = prod * j
}
j = -three while (j <= 3.pow(3)) {
process.call() j = j + three
}
j = -seven while (j <= seven) {
process.call() j = j + x
}
j = 555 while (j <= 550 - y) {
process.call() j = j + 1
}
j = 22 while (j >= -28) {
process.call() j = j - three
}
j = 1927 while (j <= 1939) {
process.call() j = j + 1
}
j = x while (j >= y) {
process.call() j = j - (-z)
}
j = p while (j <= p + one) {
process.call() j = j + 1
}
System.print("sum = %(Fmt.dc(sum))") System.print("prod = %(Fmt.dc(prod))")</lang>
- Output:
sum = 348,173 prod = -793,618,560
Yabasic
<lang yabasic> sub process(x) sum = sum + abs(x) if abs(prod) < (2 ^ 27) and x <> 0 then prod = prod * x : fi end sub
prod = 1 sum = 0 x = 5 : y = -5 : z = -2 one = 1 : three = 3 : seven = 7
for j = -three to (3 ^ 3) step three: process(j): next j for j = -seven to seven step x: process(j): next j for j = 555 to 550 - y: process(j): next j for j = 22 to -28 step -three: process(j): next j for j = 1927 to 1939: process(j): next j for j = x to y step z: process(j): next j for j = (11 ^ x) to (11 ^ x) + one: process(j): next j
print " sum= ", sum using "###,###" print "prod= ", prod using "####,###,###" end </lang>
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], // do these sequentially
[-seven..seven,x], [555..550 - y], [22..-28,-three], #[start..last,step] [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
- Loop modifiers
- Conditional loops
- Simple
- Programming Tasks
- Iteration
- 11l
- AArch64 Assembly
- ALGOL 60
- ALGOL 68
- ALGOL W
- ARM Assembly
- AutoHotkey
- AWK
- BASIC256
- C
- C sharp
- Common Lisp
- Delphi
- System.SysUtils
- EasyLang
- Eiffel
- Factor
- FreeBASIC
- Go
- Groovy
- Haskell
- J
- Java
- Jq
- Julia
- Kotlin
- M2000 Interpreter
- Mathematica
- Wolfram Language
- Nim
- Perl
- Phix
- Prolog
- PureBasic
- Python
- Raku
- Red
- REXX
- Ring
- Ruby
- Smalltalk
- True BASIC
- Vala
- VBA
- Visual Basic .NET
- Wren
- Yabasic
- Zkl