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


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.


IsLuhn := function(n)
	local c, d, i, j, r;
	d := "0123456789";
	j := 1;
	r := 0;
	for c in Reversed(String(n)) do
		i := Position(d, c);
		if i = fail then
			continue;
		fi;
		i := j*(i - 1);
		r := r + QuoInt(i, 10) + RemInt(i, 10);
		j := 3 - j;
	od;
	return RemInt(r, 10) = 0;
end;

List([49927398716, 49927398717, 1234567812345678, 1234567812345670], IsLuhn);
# [ true, false, false, true ]

# Will also work on strings, and will skip non-digits
IsLuhn("4-992-739-871-6");
# true


package main

import (
    "fmt"
    "strings"
)

const input = `49927398716
49927398717
1234567812345678
1234567812345670`

var t = [...]int{0, 2, 4, 6, 8, 1, 3, 5, 7, 9}

func luhn(s string) bool {
    odd := len(s) & 1
    var sum int
    for i, c := range s {
        if c < '0' || c > '9' {
            return false
        }
        if i&1 == odd {
            sum += t[c-'0']
        } else {
            sum += int(c - '0')
        }
    }
    return sum%10 == 0
}

func main() {
    for _, s := range strings.Split(input, "\n") {
        fmt.Println(s, luhn(s))
    }
}


100    ::::::::: REMALL VARIABLES ARE DECLARED AS INTEGERS.
110   PROD=  1 : REMSTART WITH A PRODUCT OF UNITY.
120    SUM=  0:: REM  "     "  "   SUM    " ZERO.
130      X= +5
140      Y= -5
150      Z= -2
160    UNO=  1
170  THREE=  3
180  SEVEN=  7
190 REM(BELOW)  ^  IS EXPONENTIATION:  4^3=64
200 DO(0) = -THREE : T0(0) = 3^3          : BY(0) = THREE
210 DO(1) = -SEVEN : T0(1) = +SEVEN       : BY(1) = X
220 DO(2) =    555 : T0(2) =    550 - Y
230 DO(3) =     22 : T0(3) =    -28       : BY(3) = -THREE
240 DO(4) =   1927 : T0(4) =   1939
250 DO(5) =      X : T0(5) =      Y       : BY(5) = Z
260 DO(6) =   11^X : T0(6) =   11^X + UNO
270 FOR I = 0 TO 6 : FINISH= T0(I)        : BY = BY(I)
280  START = DO(I) :         IF NOT BY THEN BY = 1
290  FOR J = START TO FINISH STEP BY
300      REM ABS(N) = ABSOLUTE VALUE
310      SUM= SUM + ABS(J) : REMADD ABSOLUTE VALUE OF J.
320      IF ABS(PROD)<2^27 AND J<>0  THEN PROD=PROD*J:REMPROD IS SMALL ENOUGH AND J NOT 0, THEN MULTIPLY IT.
330 NEXT J, I
340 REMSUM AND PROD ARE USED FOR VERIFICATION OF J INCREMENTATION.
350 PRINT " SUM= ";:N=SUM :GOSUB400:REMDISPLAY STRINGS TO TERM.
360 PRINT "PROD= ";:N=PROD:GOSUB400:REM   "        "    "   "
370 END
400 N$ =  STR$ ( ABS ( INT (N))):O$ = "":D = -1: FOR I =  LEN (N$) TO 1 STEP  - 1:C$ =  MID$ (N$,I,1) : O$ = MID$ (",",1 + (D  < 2)) + O$ : D = (D + 1) * (D < 2) : O$ = C$ + O$: NEXT I: PRINT  MID$ ("-",1 + (N >  = 0))O$: RETURN


def checkLuhn(number) {
    int total
    (number as String).reverse().eachWithIndex { ch, index ->
        def digit = Integer.parseInt(ch)
        total += (index % 2 ==0) ? digit : [0, 2, 4, 6, 8, 1, 3, 5, 7, 9][digit]
    }
    total % 10 == 0
}


/* 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"


import Data.Char (digitToInt)
luhn = (0 ==) . (`mod` 10) . sum . map (uncurry (+) . (`divMod` 10)) .
       zipWith (*) (cycle [1,2]) . map digitToInt . reverse


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
}


# 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 } }


CHARACTER numbers="49927398716 49927398717 1234567812345678 1234567812345670 "

DO nr = 1, 4
   EDIT(Text=numbers, ITeM=nr, Parse=number)
   sum_odds = 0
   sum_even = 0
   DO i = LEN(number), 1, -2
      sum_odds = sum_odds + ICHAR(number(i)) - 48
      IF(i > 1) THEN
         even2 = 2 * (ICHAR(number(i-1)) - 48)
         sum_even = sum_even + MOD(even2, 10) + INT(even2/10)
      ENDIF
   ENDDO
   valid = (0 == MOD(sum_odds + sum_even, 10))
   WRITE() number, " is ", "invalid"(1 + 2*valid:)
ENDDO


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


#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;
}


procedure main(aL)
every write(i := !aL ," - ", ((\isluhn10(i),"valid")|"invalid") \ 1)
end

procedure isluhn10(i)  #: isluhn10(i) returns i (if i passes luhn10) or fails
local sum

sum :=0
reverse(integer(i)) ? while not pos(0) do {
      sum +:= move(1)
      sum +:= map(move(1),"0123456789","0246813579")
   }

return (sum % 10 = 0,i)
end


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);
}


#include <iostream>
#include <cmath>
#include <vector>

using std::abs;
using std::cout;
using std::pow;
using std::vector;

int main()
{
    int prod  = 1,
        sum   = 0,
        x     = 5,
        y     = -5,
        z     = -2,
        one   = 1,
        three = 3,
        seven = 7;

    auto summingValues = vector<int>{};

    for(int n = -three; n <= pow(3, 3); n += three)
        summingValues.push_back(n);
    for(int n = -seven; n <= seven; n += x)
        summingValues.push_back(n);
    for(int n = 555; n <= 550 - y; ++n)
        summingValues.push_back(n);
    for(int n = 22; n >= -28; n -= three)
        summingValues.push_back(n);
    for(int n = 1927; n <= 1939; ++n)
        summingValues.push_back(n);
    for(int n = x; n >= y; n += z)
        summingValues.push_back(n);
    for(int n = pow(11, x); n <= pow(11, x) + one; ++n)
        summingValues.push_back(n);

    for(auto j : summingValues)
    {
        sum += abs(j);
        if(abs(prod) < pow(2, 27) && j != 0)
            prod *= j;
    }

    cout << "sum = " << sum << "\n";
    cout << "prod = " << prod << "\n";
}


100 PROGRAM "CredCard.bas"
110 DO
120   PRINT :PRINT "Credit card number:":INPUT PROMPT ">":CCN$
130   IF CCN$="" THEN EXIT DO
140   IF LUHN(TRIM$(CCN$)) THEN
150     PRINT "Card number is valid."
160   ELSE
170     SET #102:INK 3:PRINT "Card number is invalid.":SET #102:INK 1
180   END IF
190 LOOP
200 DEF LUHN(CCN$)
210   LET L=LEN(CCN$):LET S=0
220   FOR I=1 TO L
230     LET N=VAL(CCN$(L-I+1))
240     IF I BAND 1 THEN
250       LET S=S+N
260     ELSE
270       LET N=N*2:LET S=S+MOD(N,10)+INT(N/10)
280     END IF
290   NEXT
300   LET LUHN=MOD(S,10)=0
310 END DEF
320 DEF TRIM$(S$)
330   LET T$=""
340   FOR I=1 TO LEN(S$)
350     IF S$(I)>CHR$(47) AND S$(I)<CHR$(58) THEN LET T$=T$&S$(I)
360   NEXT
370   LET TRIM$=T$
380 END DEF


(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))


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.


public class Luhn {
    public static void main(String[] args) {
        System.out.println(luhnTest("49927398716"));
        System.out.println(luhnTest("49927398717"));
        System.out.println(luhnTest("1234567812345678"));
        System.out.println(luhnTest("1234567812345670"));
    }

    public static boolean luhnTest(String number){
        int s1 = 0, s2 = 0;
        String reverse = new StringBuffer(number).reverse().toString();
        for(int i = 0 ;i < reverse.length();i++){
            int digit = Character.digit(reverse.charAt(i), 10);
            if(i % 2 == 0){//this is for odd digits, they are 1-indexed in the algorithm
                s1 += digit;
            }else{//add 2 * digit for 0-4, add 2 * digit - 9 for 5-9
                s2 += 2 * digit;
                if(digit >= 5){
                    s2 -= 9;
                }
            }
        }
        return (s1 + s2) % 10 == 0;
    }
}


prod = 1
sum = 0
x = 5
y = -5
z = -2
one = 1
three = 3
seven = 7
ranges[][] = [ [ -three (pow 3 3) three ] [ -seven seven x ] [ 555 (550 - y) ] [ 22 -28 (-three) ] [ 1927 1939 ] [ x y z ] [ (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


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


// Loops/With multiple ranges. Nigel Galloway: June 13th., 2022
let x,y,z,one,three,seven=5,-5,-2,1,3,7
let Range=[-three..three..pown 3 3]@[-7..x..seven]@[555..550-y]@[22..-three.. -28]@[1927..1939]@[x..z..y]@[pown 11 x..(pown 11 x)+1]
printfn "Sum=%d Product=%d" (Range|>Seq.sumBy(abs)) (Range|>Seq.filter((<>)0)|>Seq.fold(fun n g->if abs n<pown 2 27 then n*g else n) 1)


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 ] [email protected] " sum=  %s\nprod= %s\n" printf
]


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


def luhn:
  def odds: . as $in | reduce range(0; length) as $i
    ([]; if ($i % 2) == 0 then . + [$in[$i]] else . end);
  def evens: . as $in | reduce range(1; length) as $i
    ([]; if ($i % 2) == 1 then . + [$in[$i]] else . end);
  def digits: map([.]|implode|tonumber);
  def sumdigits: tostring | explode | digits | add;

  (tostring | explode | reverse ) as $reverse
  | ($reverse | odds  | digits | add) as $s1
  | ($reverse | evens | digits | map(. * 2 | sumdigits) | add) as $s2
  | 0 == ($s1 + $s2) % 10 ;


luhntest(x::Integer) = (sum(digits(x)[1:2:end]) + sum(map(x -> sum(digits(x)), 2 * digits(x)[2:2:end]))) % 10 == 0


window 1, @"Loops with Ranges", ( 0, 0, 400, 400 )

begin globals
NSInteger sum  = 0
float     prod = 1
end globals

local fn process( x as float )
sum += abs(x)
if abs(prod) < (2 ^ 27) and x <> 0 then prod = prod * x
end fn

NSInteger j
NSInteger x = 5, y = -5, z = -2
NSInteger one = 1, three = 3, seven = 7

for j = -three to (3 ^ 3) step three: fn process(j): next j
for j = -seven to seven step x: fn process(j): next j
for j = 555 to 550 - y: fn process(j): next j
for j = 22 to -28 step -three: fn process(j): next j
for j = 1927 to 1939: fn process(j): next j
for j = x to y step z: fn process(j): next j
for j = (11 ^ x) to (11 ^ x) + one: fn process(j): next j

print using " sum = ###,###"; sum
print using "prod =-####,###,###"; prod

HandleEvents


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))
}


// version 1.0

fun checkLuhn(number: String): Boolean {
    var isOdd = true
    var sum = 0

    for (index in number.indices.reversed()) {
        val digit = number[index] - '0'
        sum += if (isOdd) digit else (digit * 2).let { (it / 10) + (it % 10) }
        isOdd = !isOdd
    }

    return (sum % 10) == 0
}

fun main(args: Array<String>) {
    val numbers = arrayOf("49927398716", "49927398717", "1234567812345678", "1234567812345670")
    for (number in numbers)
        println("${number.padEnd(16)} is ${if(checkLuhn(number)) "valid" else "invalid"}")
}


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}"


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


val .luhntest = f(.s) {
    val .t = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
    val .numbers = s2n .s
    val .oddeven = len(.numbers) rem 2

    for[=0] .i of .numbers {
        _for += if(.i rem 2 == .oddeven: .numbers[.i]; .t[.numbers[.i]+1])
    } div 10
}

val .tests = h{
    "49927398716": true,
    "49927398717": false,
    "1234567812345678": false,
    "1234567812345670": true,
}

for .key of .tests {
    val .pass = .luhntest(.key)
    write .key, ": ", .pass
    writeln if(.pass == .tests[.key]: ""; " (LUHN TEST FAILED)")
}


#!/usr/bin/lasso9

define luhn_check(number) => {
  local(
    rev = #number->asString,
    checksum = 0
  )
  #rev->reverse
  iterate(#rev, local(digit)) => {
    if((loop_count % 2) == 0) => {
      #checksum += (2 * integer(#digit))
      integer(#digit) >= 5 ? #checksum -= 9
    else
      #checksum += integer(#digit)
    }
  }
  (#checksum % 10) != 0 ? return false
  return true
}

stdoutnl(luhn_check(49927398716))       // true
stdoutnl(luhn_check(49927398717))       // false
stdoutnl(luhn_check(1234567812345678))  // false
stdoutnl(luhn_check(1234567812345670))  // true


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
)


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);
    }

}


' [RC] Luhn test

card$(1)="49927398716"
card$(2)="49927398717"
card$(3)="1234567812345678"
card$(4)="1234567812345670"

for test = 1 to 4
    odd=1
    sum = 0
    for n = len(card$(test)) to 1 step -1
        num=val(mid$(card$(test),n,1))
        if odd then
            sum = sum + num
            odd=0
        else
            num=num*2
            if num<=9 then
                sum = sum + num
            else
                sum = sum + val(left$(str$(num),1)) + val(right$(str$(num),1))
            end if
            odd=1
        end if
    next
    if sum mod 10 = 0 then
        print card$(test),"True"
    else
        print card$(test),"False"
    end if
next


# 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)"


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()


// 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)
}


function LuhnTest cc
    local s1,evens, s2
    repeat with n = 1 to len(cc)
        if n mod 2 is not 0 then
            add (char -n of cc) to s1
        else
            put (char -n of cc) * 2 into evens
            if evens > 9 then subtract 9 from evens
            add evens to s2
        end if
    end repeat
    return the last char of (s1 + s2) is 0
end LuhnTest

-- test
repeat for each item ccno in "49927398716,49927398717,1234567812345678,1234567812345670"
    put ccno && LuhnTest(ccno) & cr after luhncheck
end repeat
put luhncheck

49927398716 true
49927398717 false
1234567812345678 false
1234567812345670 true


to small? :list
  output or [empty? :list] [empty? bf :list]
end
to every.other :list
  if small? :list [output :list]
  output fput first :list every.other bf bf :list
end
to wordtolist :word
  output map.se [?] :word
end

to double.digit :digit
  output item :digit {0 2 4 6 8 1 3 5 7 9}@0
  ; output ifelse :digit < 5 [2*:digit] [1 + modulo 2*:digit 10]
end

to luhn :credit
  localmake "digits reverse filter [number? ?] wordtolist :credit
  localmake "s1 apply "sum every.other :digits
  localmake "s2 apply "sum map "double.digit every.other bf :digits
  output equal? 0 last sum :s1 :s2
end

show luhn "49927398716          ; true
show luhn "49927398717          ; false
show luhn "1234-5678-1234-5678  ; false
show luhn "1234-5678-1234-5670  ; true


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


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


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)


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;


function luhn(n)
  n=string.reverse(n)
  print(n)
  local s1=0
  --sum odd digits
  for i=1,n:len(),2 do
    s1=s1+n:sub(i,i)
  end
  --evens
  local s2=0
  for i=2,n:len(),2 do
    local doubled=n:sub(i,i)*2
    doubled=string.gsub(doubled,'(%d)(%d)',function(a,b)return a+b end)
    s2=s2+doubled
  end
  print(s1)
  print(s2)
  local total=s1+s2
  if total%10==0 then
    return true
  end
  return false
end

-- Note that this function takes strings, not numbers.
-- 16-digit numbers tend to be problematic
-- when looking at individual digits.
print(luhn'49927398716')
print(luhn'49927398717')
print(luhn'1234567812345678')
print(luhn'1234567812345670')


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)


foreach(I in 1..3, J in 4..6, K in 7..9)
  % ...
end


Module Checkit {
      Function luhntest(cardnr$) {

            cardnr$ = Trim$(cardnr$) ' we don't want spaces
            if len(cardnr$)=0 then exit
            Dim Base 0,  reverse_nr$(Len(cardnr$))
            Def integer  i, j, s1, s2, l , l2
            Let l=Len(cardnr$)-1, l2=l+1

            ' reverse string
            For i = 0 To l
                reverse_nr$(i) = mid$(cardnr$,l2-i,1)
            Next i
            ' sum odd numbers
            For i = 0 To l Step 2
                s1 = s1 + (Asc(reverse_nr$(i)) - Asc("0"))
            Next i
            ' sum even numbers
            For i = 1 To l Step 2
                j = Asc(reverse_nr$(i)) - Asc("0")
                j = j * 2
                If j > 9 Then j = j Mod 10 + 1
                s2 = s2 + j
            Next i

            If (s1 + s2) Mod 10 = 0 Then
                = 1=1
            Else
                = 1=0
            End If
      }
      Flush
      Data "49927398716",  "49927398717", "1234567812345678", "1234567812345670"
      while not empty
            over
            print letter$;" = ";luhntest(letter$)
      end while
}
Checkit


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).


function passed = luhn(num)
if nargin == 0 % evaluate test cases
  testnum = [49927398716 49927398717 1234567812345678 1234567812345670];
  for num = testnum
    disp([int2str(num) ': ' int2str(luhn(num))])
  end
  return
end
% luhn function starts here
d = int2str(num) - '0';	% convert number into vector of digits
m = [2:2:8,1:2:9];	% rule 3: maps 1:9 to [2 4 6 8 1 3 5 7 9]
passed = ~mod(sum(d(end:-2:1)) + sum(m(d(end-1:-2:1))), 10);
end


#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


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}')


((dup 10 <) 'quote (((10 mod) (10 div)) cleave) 'cons linrec) :digits
((0 0) dip (pop 'succ dip over even?) partition ((pop pop) dip) dip) :evens/odds
((2 * digits sum) map sum) :evens-sum
(digits evens/odds ('evens-sum 'sum) => spread + 10 mod 0 ==) :luhn?

(49927398716 49927398717 1234567812345678 1234567812345670)
(dup print! " " print! luhn? puts!) foreach


isValid = function(s)
    sum = 0
    odd = true
    for i in range(s.len-1)
        d = val(s[i])
        sum = sum + d * (2 - odd)
        if not odd and d > 4 then sum = sum - 9
        odd = not odd
    end for
    return sum % 10 == 0
end function

test = function(s)
    if isValid(s) then print s + ": valid" else print s + ": invalid"
end function

test "49927398716"
test "49927398717"
test "1234567812345678"
test "1234567812345670"


'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.

'Unknown DO multiple conditions behaviour:
' this code implements a sequential/serial set of ranges mode for DO condition

Dim As Integer prod, sum, x, y, z, one, three, seven
Dim As _Integer64 Count(1 To 7)
Dim As Integer Index, IndexCondition

prod = 1
sum = 0
x = 5
y = -5
z = -2
one = 1
three = 3
seven = 7
Count(1) = -three
Count(2) = -seven
Count(3) = 555
Count(4) = 22
Count(5) = 1927
Count(6) = x
Count(7) = 11 ^ x
IndexCondition = 1
Do
    If IndexCondition = 1 Then
        If Count(1) + three < 3 ^ 3 Then Count(1) = Count(1) + three Else IndexCondition = 2
    ElseIf IndexCondition = 2 Then
        If Count(2) + x < seven Then Count(2) = Count(2) + x Else IndexCondition = 3
    ElseIf IndexCondition = 3 Then
        If Count(3) - 1 > 550 - y Then Count(3) = Count(3) - 1 Else IndexCondition = 4
    ElseIf IndexCondition = 4 Then
        If Count(4) - three > -28 Then Count(4) = Count(4) - three Else IndexCondition = 5
    ElseIf IndexCondition = 5 Then
        If Count(5) + 1 < 1939 Then Count(5) = Count(5) + 1 Else IndexCondition = 6
    ElseIf IndexCondition = 6 Then
        If Count(6) + z < y Then Count(6) = Count(6) + z Else IndexCondition = 7
    ElseIf IndexCondition = 7 Then
        If Count(7) + 1 < 11 ^ (x + one) Then Count(7) = Count(7) + 1 Else Exit Do
    End If

    sum = sum + Abs(Count(IndexCondition))
    If Abs(prod) < 2 ^ 27 And (j <> 0) Then prod = prod * Count(IndexCondition)
    Print sum
    Print prod

Loop


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


LUHN(C)
 NEW ODD,EVEN,S
 SET S=$REVERSE(C)
 SET ODD=0 FOR I=1:2:$LENGTH(S) SET ODD=ODD+$EXTRACT(S,I)
 SET EVEN=0 FOR I=2:2:$LENGTH(S) SET T=$EXTRACT(S,I)*2 SET EVEN=EVEN+$SELECT(T<=9:T,T>9:$EXTRACT(T,1)+$EXTRACT(T,2))
 QUIT '((ODD+EVEN)#10)


def reverse_str(string)
    to_return = ""

    for i in range(len(string) - 1, 0, -1)
        to_return += string[i]
    end for

    return to_return
end reverse_str

def luhnTest(number)
    s1 = 0; s2 = 0
    reversed = reverse_str(number)
    for i in range(0, len(reversed) - 1)
        digit = int(reversed[i])
        if (i % 2) = 0
            s1 += digit
        else
            s2 += 2 * digit
            if digit >= 5
                s2 -= 9
            end if
        end if
    end for

    return ((s1 + s2) % 10) = 0
end luhnTest

println luhnTest("49927398716")
println luhnTest("49927398717")
println luhnTest("1234567812345678")
println luhnTest("1234567812345670")


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]


/*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;


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


class LuhnTest

  method main(args=String[]) static
    cc	  = 0
    cc[1] = '49927398716'
    cc[2] = '49927398717'
    cc[3] = '1234567812345678'
    cc[4] = '1234567812345670'

    loop k=1 while cc[k] <> 0
      r = checksum(cc[k])
      if r==0 then say cc[k].right(20) 'passed'
      else say cc[k].right(20) 'failed'
    end

    -- Luhn algorithm checksum for credit card numbers
  method checksum(t) static
    if t.length()//2 then t = '0't  --pad # on left with 0
    t = t.reverse()
    s = 0
    loop j = 1 to t.length()-1 by 2
      q = 2*t.substr(j+1,1)
      if q>9 then q = q.left(1) + q.right(1)
      s= s+t.substr(j,1)+q
    end
    return s//10\==0


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}"


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


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


proc luhn(cc: string): bool =
  const m = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
  var sum = 0
  var odd = true
  for i in countdown(cc.high, 0):
    let digit = ord(cc[i]) - ord('0')
    sum += (if odd: digit else: m[digit])
    odd = not odd
  result = sum mod 10 == 0

for cc in ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]:
  echo cc, ' ', luhn(cc)


bundle Default {
  class Luhn {
    function : IsValid(cc : String) ~ Bool {
      isOdd := true;
      oddSum := 0;
      evenSum := 0;

      for(i := cc->Size() - 1; i >= 0; i -= 1;) {
        digit : Int := cc->Get(i) - '0';
        if(isOdd) {
          oddSum += digit;
        }
        else {
          evenSum += digit / 5 + (2 * digit) % 10;
        };
        isOdd := isOdd <> true;
      };

      return (oddSum + evenSum) % 10 = 0;
    }

    function : Main(args : String[]) ~ Nil {
      IsValid("49927398716")->PrintLine();
      IsValid("49927398717")->PrintLine();
      IsValid("1234567812345678")->PrintLine();
      IsValid("1234567812345670")->PrintLine();
    }
  }
}


p =  1                                 ' product
s =  0                                 ' sum

x =  5
y = -5
z = -2

o =  1                                 ' one
t =  3                                 ' three
v =  7                                 ' seVen

For j =   -t To (3 ^ 3) Step t:   Proc _Process(j) : Next
For j =   -v To v       Step x:   Proc _Process(j) : Next
For j =  555 To 550 - y:          Proc _Process(j) : Next
For j =   22 To -28     Step -t:  Proc _Process(j) : Next
For j = 1927 To 1939:             Proc _Process(j) : Next
For j =    x To y       Step z:   Proc _Process(j) : Next
For j = (11 ^ x) To (11 ^ x) + o: Proc _Process(j) : Next

Print Using " sum= +###,###"; s
Print Using "prod= +###,###,###"; p
End

_Process
  Param (1)

  s = s + Abs([email protected])
  If (Abs(p) < (2 ^ 27)) * ([email protected] # 0) Then p = p * [email protected]
Return


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);
}


- (NSArray *) toCharArray {

	NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[self length]];
	for (int i=0; i < [self length]; i++) {
		NSString *ichar  = [NSString stringWithFormat:@"%C", [self characterAtIndex:i]];
		[characters addObject:ichar];
	}

	return characters;
}

+ (BOOL) luhnCheck:(NSString *)stringToTest {

	NSArray *stringAsChars = [stringToTest toCharArray];

	BOOL isOdd = YES;
	int oddSum = 0;
	int evenSum = 0;

	for (int i = [stringToTest length] - 1; i >= 0; i--) {

		int digit = [(NSString *)stringAsChars[i] intValue];

		if (isOdd)
			oddSum += digit;
		else
			evenSum += digit/5 + (2*digit) % 10;

		isOdd = !isOdd;
	}

	return ((oddSum + evenSum) % 10 == 0);
}

BOOL test0 = [self luhnCheck:@"49927398716"]; //Result = YES
BOOL test1 = [self luhnCheck:@"49927398717"]; //Result = NO
BOOL test2 = [self luhnCheck:@"1234567812345678"]; //Result = NO
BOOL test3 = [self luhnCheck:@"1234567812345670"]; //Result = YES


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


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


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))")


let luhn s =
  let rec g r c = function
  | 0 -> r
  | i ->
      let d = c * ((int_of_char s.[i-1]) - 48) in
      g (r + (d/10) + (d mod 10)) (3-c) (i-1)
  in
  (g 0 1 (String.length s)) mod 10 = 0
;;


   function y = isluhn(s);
	if isnumeric(s) s = mat2str(s); end; 	% make sure s is a string
	d = s-'0';	% convert string into vector of digits
	m = [2:2:8,1:2:9];	% rule 3: maps [1:9] -> i
	y = ~mod(sum(d(end:-2:1)) + sum(m(d(end-1:-2:1))),10);
   end;


func IPow(A, B);        \Return A**B
int  A, B;
return fix(Pow(float(A), float(B)));

int Prod, Sum, X, Y, Z, One, Three, Seven, J;

           proc Block;
           begin                                        \ABS(n) = absolute value
           Sum:= Sum + abs(J);                          \add absolute value of J.
           if abs(Prod)<1<<27 & J#0  then Prod:=Prod*J; \PROD is small enough & J
           end;                                         \not 0, then multiply it.

begin                                  \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;

           for J:= -Three  to     3*3*3          do [Block;  J:= J+Three-1];
           for J:= -Seven  to   +Seven           do [Block;  J:= J+X-1];
           for J:=    555  to      550 - Y       do  Block;
           for J:=     22  downto  -28           do [Block;  J:= J-Three+1];
           for J:=   1927  to     1939           do  Block;
           for J:=      X  downto    Y           do [Block;  J:= J+Z+1];
           for J:=  IPow(11,X) to IPow(11,X)+One do  Block;

                     \SUM and PROD are used for verification of J incrementation.
Text(0, " Sum= ");  IntOut(0, Sum);   CrLf(0);          \display strings to term.
Text(0, "Prod= ");  IntOut(0, Prod);  CrLf(0);          \  "       "     "   "
end


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


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));


: luhnTest(n)
| s i |
   n asString reverse ->s
   0 s size loop: i [
      i s at asDigit
      i isEven ifTrue: [ 2 * dup 10 >= ifTrue: [ 9 - ] ] +
      ]
   10 mod ==0 ;


FUNCTION fnLuhnAlgorithm RETURNS LOGICAL
  (INPUT pcNumber AS CHARACTER):
/*------------------------------------------------------------------------------
  Purpose:  Applies Luhn Algorithm to check a Number
    Notes:  Returns True/False Validation based on check digit
------------------------------------------------------------------------------*/
    DEFINE VARIABLE cNum        AS CHARACTER NO-UNDO.
    DEFINE VARIABLE iCheck      AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iLength     AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iLoopCnt    AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iNum        AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iNum1       AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iNum2       AS INTEGER   NO-UNDO.
    DEFINE VARIABLE iTestLength AS INTEGER   NO-UNDO.

    ASSIGN
      iLength     = LENGTH(pcNumber)
      iTestLength = iLength - 1
        iCheck = 1. /* 1 for the check digit we skip */

    DO iLoopCnt = iTestLength TO 1 BY -1:
      ASSIGN
          iNum = INTEGER(SUBSTR(pcNumber,iLoopCnt,1))
          iCheck = iCheck + 1.

      IF iCheck MODULO 2 = 1 THEN
          ASSIGN iNum1 = iNum1 + iNum.
      ELSE
      DO:
          ASSIGN iNum2 = iNum * 2.
          IF iNum2 < 10 THEN
              ASSIGN iNum1 = iNum1 + iNum2.
          ELSE
              ASSIGN
                cNum  = STRING(iNum2)
                iNum1 = iNum1 + INTEGER(SUBSTR(cNum,1,1)) + INTEGER(SUBSTR(cNum,2,1)).
      END.
    END.

    ASSIGN
        iNum2 = iNum1 * 9
        iNum = iNum2 MODULO 10.

    IF iNum = INTEGER(SUBSTR(pcNumber,iLength,1)) THEN
      RETURN TRUE.
    ELSE
      RETURN FALSE.

END FUNCTION. /* fnLuhnAlgorithm  */


#include <order/interpreter.h>

#define ORDER_PP_DEF_8luhn ORDER_PP_FN( \
8fn(8N, 8if(8is_seq(8N), 8luhn_wk(8num_to_seq(8N)), 8false)) )

#define ORDER_PP_DEF_8num_to_seq ORDER_PP_FN( \
8fn(8N, 8seq_push_back(8seq(8seq_last(8N)), 8seq_pop_back(8N))) )

#define ORDER_PP_DEF_8luhn_wk ORDER_PP_FN(                      \
8fn(8N,                                                         \
    8lets((8P, 8unzip(8N, 8nil, 8nil, 8true))                   \
          (8O, 8seq_fold(8plus, 0, 8tuple_at_0(8P)))            \
          (8E, 8seq_fold(8plus, 0,                              \
                         8seq_map(8dig_map, 8tuple_at_1(8P)))), \
          8is_0(8remainder(8plus(8O, 8E), 10)))) )

#define ORDER_PP_DEF_8dig_map ORDER_PP_FN( \
8fn(8X, 8tuple_at(8X, 8tuple(0,2,4,6,8,1,3,5,7,9))) )

#define ORDER_PP_DEF_8unzip ORDER_PP_FN(                             \
8fn(8S, 8L, 8R, 8O,                                                  \
    8if(8is_nil(8S),                                                 \
        8pair(8L, 8R),                                               \
        8if(8O,                                                      \
            8unzip(8seq_tail(8S), 8seq_push_back(8seq_head(8S), 8L), \
                   8R, 8false),                                      \
            8unzip(8seq_tail(8S), 8L,                                \
                   8seq_push_back(8seq_head(8S), 8R), 8true)))) )

ORDER_PP(8seq_to_tuple(
  8seq_map(8luhn, 8seq(8nat(4,9,9,2,7,3,9,8,7,1,6),
                       8nat(4,9,9,2,7,3,9,8,7,1,7),
                       8nat(1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8),
                       8nat(1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,0)))
))


declare
  fun {Luhn N}
     {Sum {List.mapInd {Reverse {Digits N}}
           fun {$ Idx Dig}
              if {IsEven Idx} then {Sum {Digits 2*Dig}}
              else Dig
              end
           end}}
     mod 10 == 0
  end

  fun {Digits N}
     {Map {Int.toString N} fun {$ D} D - &0 end}
  end

  fun {Sum Xs}
     {FoldL Xs Number.'+' 0}
  end
in
  {Show
   {Map
    [49927398716 49927398717 1234567812345678 1234567812345670]
    Luhn}}


program luhnTestOfCreditCardNumbers(input, output);

type
	{
		`string(…)` is an Extended Pascal, ISO 10206, extension.
		`string(64)` discriminates the “schema” data type `string`
		to contain at most 64 `char` values.
	}
	creditCardNumber = string(64);

{
	\brief determines whether a string contains digits only

	\param sample the string to inspect
	\return `false` iff `sample` contains non-digit characters
}
{ Extended Pascal: `protected` means the function cannot modify `sample` }
function containsDigitsOnly(protected sample: creditCardNumber): Boolean;
var
	{ EP: the `… value []` initializes this variable as an empty set }
	characters: set of char value [];
	{ `sample.capacity` refers to `64` in this code. }
	i: 1..sample.capacity;
begin
	for i := 1 to length(sample) do
	begin
		{ Union of sets indicated by `+`. }
		characters := characters + [sample[i]]
	end;

	{
		In a Pascal `function` definition,
		there must be one assignment to the (implicit) variable
		bearing the same name as of the function.
		This will be the return value.
	}
	{ NB: This will return `true` even if `length(sample)` is zero. }
	containsDigitsOnly := card(characters - ['0'..'9']) = 0
	{ `card` is an Extended Pascal extension. }
end;

{
	\brief determines whether a string complies with ISO/IEC 7812-1 Luhn test

	\param sample the potentially correct credit card number
	\return `true` if verification succeeds
}
function luhnCheck(protected sample: creditCardNumber): Boolean;
	{
		This _nested_ function is only accessible _within_ `luhnCheck`.
		Outsourcing this code allows us to write a neat expression below.
	}
	function check: Boolean;
	var
		{ Using `integer` sub-ranges ensures only these values are assigned. }
		sum: 0..maxInt value 0;
		i: 0..sample.capacity-1;
	begin
		for i := 0 to length(sample) - 1 do
		begin
			{ `1 + ord(odd(i))` produces an alternating scale factor `* 1`/`* 2`. }
			sum := sum + (1 + ord(odd(i))) *
				{ Obtain digit value for `integer` calculation. }
				(ord(sample[length(sample) - i]) - ord('0')) -
				{ Reverse operation if digit sum > 9, i.e. we added “too much”. }
				ord(odd(i) and (sample[length(sample) - i] >= '5')) * 9
		end;

		check := sum mod 10 = 0
	end;
begin
	{
		The Extended Pascal Boolean operator `and_then` (and `or_else`)
		allows for “short-circuit evaluation”.
		Otherwise, in Pascal `and` and `or` mandate complete evaluation.
	}
	luhnCheck := (length(sample) > 0) and_then containsDigitsOnly(sample)
		and_then check
end;

{ === MAIN ============================================================= }
var
	s: creditCardNumber;
begin
	{ `EOF` is short for `EOF(input)`. }
	while not EOF do
	begin
		readLn(s); { equivalent to `readLn(input, s)` }
		writeLn(luhnCheck(s)) { = `writeLn(output, …)` }
	end
end.


with javascript_semantics
function Luhn(string st)
    integer s=0, d
    for i=1 to length(st) do
        d = st[-i]-'0'
        s += iff(mod(i,2)?d,d*2-(d>4)*9)
    end for
    return remainder(s,10)=0
end function

procedure test(string s)
    printf(1,"%20s : %t\n",{s,Luhn(s)})
end procedure

papply({"49927398716","49927398717","1234567812345678","1234567812345670"},test)


go =>
   Nums = ["49927398716","49927398717","1234567812345678","1234567812345670"],
   foreach (N in Nums)
      println([N, isluhn10(N)])
   end,
   nl.

%
% isluhn10(num) returns 1 is valid, else 0
%
% Assumption: input num is a string.
%
isluhn10(Num) = V =>
  X = [I : I in Num.reverse()] ++ [""],
  Digits = "0246813579",
  M = new_map([(I.to_string()=Digits[I+1]) : I in 0..9]),
  V1 = sum([X[I].to_integer() + M.get2(X[I+1].to_string(),0) : I in 1..2..Num.length]),
  V := cond(V1 mod 10 == 0, 1, 0).

% A variant of Map.get with conversions
get2(M, Key, Default)=V =>
   if M.has_key(Key) then V= M.get(Key).to_integer() else V=Default end.


(de luhn (Num)  # 'Num' may be a number or a string
   (=0
      (%
         (sum
            '((C F)
               (setq C (- (char C) 48))
               (if F
                  C                               # Odd
                  (+ (/ C 5) (% (* 2 C) 10)) ) )  # Even
            (flip (chop Num))
            '(T NIL .) )
         10 ) ) )


test: procedure options (main);

   declare (cardnumber, rcn) character (20) varying;
   declare (i, k, s1, s2) fixed binary;

   get edit (cardnumber) (L);
   cardnumber = trim(cardnumber);
   rcn = reverse(cardnumber);
   s1, s2 = 0;
   /* Sum the odd-numbered digits */
   do i = 1 to length(rcn) by 2;
      s1 = s1 + substr(rcn, i, 1);
   end;
   /* Twice the even-numbered digits. */
   do i = 2 to length(rcn) by 2;
      k = 2 * substr(rcn, i, 1);
      s2 = s2 + mod(k,10) + trunc(k/10);
   end;
   if mod(s1 + s2, 10) = 0 then
      put skip edit (cardnumber, ' passes the Luhn test' )(a);
   else
      put skip edit (cardnumber, ' does not pass the Luhn test' )(a);
   put skip list (s1 + s2);
end test;


100H:
BDOS: PROCEDURE(F,A); DECLARE F BYTE, A ADDRESS; GO TO 5; END BDOS;
EXIT: PROCEDURE; GO TO 0; END EXIT;
PRINT: PROCEDURE(S); DECLARE S ADDRESS; CALL BDOS(9,S); END PRINT;

LUHN: PROCEDURE(NUM) BYTE;
    DECLARE MAP DATA (0, 2, 4, 6, 8, 1, 3, 5, 7, 9);
    DECLARE (START, NUM, MASK, TOTAL) ADDRESS;
    DECLARE (CHR BASED NUM, DGT) BYTE;
    START = NUM;

    DO WHILE CHR <> '$'; NUM = NUM + 1; END;
    MASK = NUM := NUM - 1;
    TOTAL = 0;
    DO WHILE NUM >= START;
        DGT = CHR - '0';
        IF NUM XOR MASK THEN DGT = MAP(DGT);
        TOTAL = TOTAL + DGT;
        NUM = NUM - 1;
    END;
    RETURN TOTAL MOD 10 = 0;
END LUHN;

DECLARE TEST (4) ADDRESS, I BYTE;
TEST(0) = .'49927398716$';
TEST(1) = .'49927398717$';
TEST(2) = .'1234567812345678$';
TEST(3) = .'1234567812345670$';

DO I=0 TO LAST(TEST);
    CALL PRINT(TEST(I));
    CALL PRINT(.': $');
    IF LUHN(TEST(I))
        THEN CALL PRINT(.'PASS$');
        ELSE CALL PRINT(.'FAIL$');
    CALL PRINT(.(13,10,'$'));
END;
CALL EXIT;
EOF


FUNCTION algoLuhn ( p_numeroVerif VARCHAR2 )
    RETURN NUMBER
  IS
    i         NUMBER;
    v_NBi     SMALLINT;
    v_retour  SMALLINT;
    v_somme   NUMBER := 0;
    v_nbCar   NUMBER;

  BEGIN
    v_nbCar := LENGTH(p_numeroVerif);

    FOR i IN 1..v_nbCar
    LOOP
        v_NBi := TO_NUMBER(SUBSTR(p_numeroVerif,v_nbCar+1-i,1));

        v_somme := v_somme
                  + MOD(i,2)   * v_NBi
                  + MOD(i+1,2) * SIGN(-SIGN(v_Nbi-4)+1) * (2*v_NBi)
                  + MOD(i+1,2) * SIGN( SIGN(v_Nbi-5)+1) * (2*v_NBi-9);

    END LOOP;

    v_retour := SIGN(MOD(v_somme,10));

    RETURN v_retour;

  EXCEPTION
    WHEN OTHERS
      THEN
        RETURN 1;

  END algoLuhn;


To run:
Start up.
Test whether "49927398716" will pass the luhn test.
Test whether "49927398717" will pass the luhn test.
Test whether "1234567812345678" will pass the luhn test.
Test whether "1234567812345670" will pass the luhn test.
Wait for the escape key.
Shut down.

To test whether a string will pass the luhn test:
Write the string then ": " on the console without advancing.
If the string will pass the luhn test, write "valid" on the console; exit.
Write "invalid" on the console.

A sum is a number.

To decide if a string will pass the luhn test:
If the string is blank, say no.
Privatize the string.
Reverse the string.
Put 0 into a first sum.
Put 0 into a second sum.
Put 1 into a count.
Slap a rider on the string.
Loop.
If the rider's source is blank, break.
Put the rider's source's first's target into a byte.
If the byte is not any digit, say no.
Convert the byte to a number.
If the count is odd, add the number to the first sum; bump the count; bump the rider; repeat.
Double the number.
If the number is greater than 9, digital root the number.
Add the number to the second sum.
Bump the count. Bump the rider.
Repeat.
If the first sum plus the second sum is evenly divisible by 10, say yes.
Say no.

To digital root a number:
Divide the number by 10 giving a quotient and a remainder.
Put the quotient plus the remainder into the number.

To convert a byte to a number:
If the byte is any digit, put the byte minus 48 into the number.


#COMPILE EXE
#DIM ALL
#COMPILER PBCC 6

FUNCTION LuhnCheckPassed(BYVAL dgts AS STRING) AS INTEGER
LOCAL i, s, s1 AS DWORD
  dgts = STRREVERSE$(dgts)
    FOR i = 1 TO LEN(dgts) STEP 2
        s += VAL(MID$(dgts, i, 1))
    NEXT i
    FOR i = 2 TO LEN(dgts) STEP 2
        s1 = 2 * VAL(MID$(dgts, i, 1))
        IF s1 >= 10 THEN
            s -= 9
        END IF
        s += s1
    NEXT i
  FUNCTION = NOT ISTRUE (s MOD 10)
END FUNCTION

FUNCTION PBMAIN () AS LONG
  ' this test is expected to pass:
  CON.PRINT IIF$(LuhnCheckPassed("49927398716"), "passed", "failed")
  ' this test is expected to fail:
  CON.PRINT IIF$(LuhnCheckPassed("49927398717"), "passed", "failed")
  ' this test is expected to fail:
  CON.PRINT IIF$(LuhnCheckPassed("1234567812345678"), "passed", "failed")
  ' this test is expected to pass:
  CON.PRINT IIF$(LuhnCheckPassed("1234567812345670"), "passed", "failed")
END FUNCTION


function Test-LuhnNumber
{
  <#
    .SYNOPSIS
        Tests validity of credit card numbers.
    .DESCRIPTION
        Tests validity of credit card numbers using the Luhn test.
    .PARAMETER Number
        The number must be 11 or 16 digits.
    .EXAMPLE
        Test-LuhnNumber 49927398716
    .EXAMPLE
        [int64[]]$numbers = 49927398716, 49927398717, 1234567812345678, 1234567812345670
        C:\PS>$numbers | ForEach-Object {
                  "{0,-17}: {1}" -f $_,"$(if(Test-LuhnNumber $_) {'Is valid.'} else {'Is not valid.'})"
              }
  #>
    [CmdletBinding()]
    [OutputType([bool])]
    Param
    (
        [Parameter(Mandatory=$true,
                   Position=0)]
        [ValidateScript({$_.Length -eq 11 -or $_.Length -eq 16})]
        [ValidatePattern("^\d+$")]
        [string]
        $Number
    )

    $digits = ([Regex]::Matches($Number,'.','RightToLeft')).Value

    $digits |
        ForEach-Object `
               -Begin   {$i = 1} `
               -Process {if ($i++ % 2) {$_}} |
        ForEach-Object `
               -Begin   {$sumOdds = 0} `
               -Process {$sumOdds += [Char]::GetNumericValue($_)}
    $digits |
        ForEach-Object `
               -Begin   {$i = 0} `
               -Process {if ($i++ % 2) {$_}} |
        ForEach-Object `
               -Process {[Char]::GetNumericValue($_) * 2} |
        ForEach-Object `
               -Begin   {$sumEvens = 0} `
               -Process {
                            $_number = $_.ToString()
                            if ($_number.Length -eq 1)
                            {
                                $sumEvens += [Char]::GetNumericValue($_number)
                            }
                            elseif ($_number.Length -eq 2)
                            {
                                $sumEvens += [Char]::GetNumericValue($_number[0]) + [Char]::GetNumericValue($_number[1])
                            }
                        }

    ($sumOdds + $sumEvens).ToString()[-1] -eq "0"
}


DataSection
  Sample:
  Data.s "49927398716"
  Data.s "49927398717"
  Data.s "1234567812345678"
  Data.s "1234567812345670"
  Data.s ""
EndDataSection

Procedure isValid(cardNumber.s)
  Protected i, length, s1, s2, s2a

  cardNumber = ReverseString(cardNumber)
  length = Len(cardNumber)
  For i = 1 To length Step 2
    s1 + Val(Mid(cardNumber, i, 1))
  Next

  For i = 2 To length Step 2
    s2a = Val(Mid(cardNumber, i, 1)) * 2
    If s2a < 10
      s2 + s2a
    Else
      s2 + 1 + Val(Right(Str(s2a), 1))
    EndIf
  Next

  If Right(Str(s1 + s2), 1) = "0"
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf
EndProcedure

If OpenConsole()
  Define cardNumber.s

  Restore Sample
  Repeat
    Read.s cardNumber
    If cardNumber <> ""
      Print(cardNumber + " is ")
      If isValid(cardNumber)
        PrintN("valid")
      Else
        PrintN("not valid")
      EndIf
    EndIf
  Until cardNumber = ""

  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit")
  Input()
  CloseConsole()
EndIf


sd:{s:0; while[x<>0; s+:x mod 10; x:floor x%10]; s}    / Sum digits of x
luhn:{
    r:reverse string x;                             / Reversed credit card number
    o:("I"$) each r[2*til ceiling (count r) % 2];   / Odd-indexed numbers
    e:("I"$) each r[1+2*til floor (count r) % 2];   / Even-indexed numbers
    0=(sum o,sd each e*2) mod 10                    / Return 1b if checksum ends in 0; 0b otherwise
}


  [ 1 & ]               is odd        ( n --> b   )

  [ [] swap
    [ 10 /mod
      rot join swap
      dup 0 = until ]
      drop ]            is digits     ( n --> [   )

  [ [] [] rot
    dup size odd dip
    [ witheach
        [ nested join
          swap ] ]
    not if swap ]       is unzip      ( [ --> [ [ )

  [ [] swap
    witheach
      [ 2 *
        10 /mod +
        join ] ]        is 2*digitsum ( [ --> [   )

  [ behead swap
    witheach + ]        is sum        ( [ --> n   )

  [ digits
    reverse
    unzip
    2*digitsum
    sum
    swap sum
    + 10 mod 0 = ]      is luhn       ( n --> b   )

' [ 49927398716      49927398717
    1234567812345678 1234567812345670 ]

witheach
  [ dup echo
    luhn iff
      [ say " valid" ]
    else
      [ say " invalid" ]
    cr ]


#lang racket

(define (luhn-test n)
  (let loop ([n n] [odd? #t] [s 0])
    (if (zero? n)
      (zero? (modulo s 10))
      (let*-values ([(q r)   (quotient/remainder n 10)]
                    [(rq rr) (quotient/remainder (* (if odd? 1 2) r) 10)])
        (loop q (not odd?) (+ s rq rr))))))

(map luhn-test '(49927398716 49927398717 1234567812345678 1234567812345670))
;; -> '(#t #f #f #t)


sub luhn-test ($number --> Bool) {
    my @digits = $number.comb.reverse;
    my $sum = @digits[0,2...*].sum
            + @digits[1,3...*].map({ |($_ * 2).comb }).sum;
    return $sum %% 10;
}

# And we can test it like this:

use Test;

my @cc-numbers =
    '49927398716'       => True,
    '49927398717'       => False,
    '1234567812345678'  => False,
    '1234567812345670'  => True;

plan @cc-numbers.elems;

for @cc-numbers».kv -> ($cc, $expected-result) {
    is luhn-test(+$cc), $expected-result,
        "$cc {$expected-result ?? 'passes' !! 'does not pass'} the Luhn test.";
}


/*REXX program  validates  credit card numbers  using  the    Luhn    algorithm.        */
#.=;                #.1= 49927398716             /*the  1st  sample credit card number. */
                    #.2= 49927398717             /* "   2nd     "      "     "     "    */
                    #.3= 1234567812345678        /* "   3rd     "      "     "     "    */
                    #.4= 1234567812345670        /* "   4th     "      "     "     "    */
      do k=1  while #.k\==''                     /*validate all the credit card numbers.*/
      say right( Luhn(#.k), 9)          ' the Luhn test, credit card number: '    #.k
      end   /*k*/                                /* [↑] function returns passed│flunked.*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
Luhn: procedure;  parse arg x;              $= 0 /*get credit card number;  zero $ sum. */
      y= reverse( left(0, length(x) // 2)x)      /*add leading zero if needed, reverse. */
              do j=1  to length(y)-1  by 2;                _= substr(y, j+1, 1) * 2
              $= $ + substr(y, j, 1) + left(_, 1) + substr(_, 2, 1, 0)     /* ◄────────┐*/
              end   /*j*/                       /*sum odd and even decimal digits ►────┘*/
      return word('passed flunked',1+($//10==0)) /*$ ending in zero?  Then the # passed.*/


decimals(0)

test = ["49927398716", "49927398717", "1234567812345678", "1234567812345670"]
for n = 1 to len(test)
      see test[n] + " -> " + cardtest(test[n]) + nl
next

func cardtest(numstr)
        revstring = revstr(numstr)
        s1 = revodd(revstring)
        s2 = reveven(revstring)
        s3 =right(string(s1+s2), 1)
        if s3 = "0"
           return "Valid"
        else
           return "Invalid"
        ok

func revstr(str)
      strnew = ""
      for nr = len(str) to 1 step -1
           strnew = strnew + str[nr]
      next
      return strnew

func revodd(str)
        strnew = ""
        for nr = 1 to len(str) step 2
             strnew = strnew + str[nr]
        next
        sumodd = 0
        for p = 1 to len(strnew)
              sumodd = sumodd + number(strnew[p])
        next
        return sumodd

func reveven(str)
        strnew = ""
        for nr = 2 to len(str) step 2
             strnew = strnew + str[nr]
        next
        lsteven = []
        for p = 1 to len(strnew)
             add(lsteven, string(2*number(strnew[p])))
        next
        arreven = list(len(lsteven))
        for q = 1 to len(lsteven)
              sum = 0
              for w = 1 to len(lsteven[q])
                    sum = sum + lsteven[q][w]
              next
              arreven[q] = sum
        next
        sumarr = 0
        for x = 1 to len(arreven)
             sumarr = sumarr + arreven[x]
        next
        return sumarr


 def luhn_valid?(str)
   str.scan(/\d/).reverse            #using str.to_i.digits fails for cases with leading zeros
      .each_slice(2)
      .sum { |i, k = 0| i.to_i + ((k.to_i)*2).digits.sum }
      .modulo(10).zero?
 end

["49927398716", "49927398717", "1234567812345678", "1234567812345670"].map{ |i| luhn_valid?(i) }


card$(1) = "49927398716"
card$(2) = "49927398717"
card$(3) = "1234567812345678"
card$(4) = "1234567812345670"

for i = 1 to 4
print card$(i);" ";luhn$(card$(i))
next i

FUNCTION luhn$(card$)
    lc      = len(card$)
    for i   = lc to 1 step -1
      digit = val(mid$(card$,i,1))
      if ((lc -i) mod 2) = 0 then chkSum = chkSum + digit else chkSum = chkSum + int(digit * 2.2)
    next i
    if chkSum mod 10 = 0 then luhn$ = "True" else luhn$ = "False"
end function


extern crate luhn_test_of_credit_card_numbers;

use luhn_test_of_credit_card_numbers::luhn_test;

fn validate_isin(isin: &str) -> bool {
    if !isin.chars().all(|x| x.is_alphanumeric()) || isin.len() != 12 {
        return false;
    }
    if !isin[..2].chars().all(|x| x.is_alphabetic())
        || !isin[2..12].chars().all(|x| x.is_alphanumeric())
        || !isin.chars().last().unwrap().is_numeric()
    {
        return false;
    }

    let bytes = isin.as_bytes();

    let s2 = bytes
        .iter()
        .flat_map(|&c| {
            if c.is_ascii_digit() {
                vec![c]
            } else {
                (c + 10 - ('A' as u8)).to_string().into_bytes()
            }
        })
        .collect::<Vec<u8>>();

    let string = std::str::from_utf8(&s2).unwrap();
    let number = string.parse::<u64>().unwrap();

    return luhn_test(number as u64);
}

#[cfg(test)]
mod tests {
    use super::validate_isin;

    #[test]
    fn test_validate_isin() {
        assert_eq!(validate_isin("US0378331005"), true);
        assert_eq!(validate_isin("US0373831005"), false);
        assert_eq!(validate_isin("U50378331005"), false);
        assert_eq!(validate_isin("US03378331005"), false);
        assert_eq!(validate_isin("AU0000XVGZA3"), true);
        assert_eq!(validate_isin("AU0000VXGZA3"), true);
        assert_eq!(validate_isin("FR0000988040"), true);
    }
}


object Luhn {
  private def parse(s: String): Seq[Int] = s.map{c =>
    assert(c.isDigit)
    c.asDigit
  }
  def checksum(digits: Seq[Int]): Int = {
    digits.reverse.zipWithIndex.foldLeft(0){case (sum,(digit,i))=>
      if (i%2 == 0) sum + digit
      else sum + (digit*2)/10 + (digit*2)%10
    } % 10
  }
  def validate(digits: Seq[Int]): Boolean = checksum(digits) == 0
  def checksum(number: String): Int = checksum(parse(number))
  def validate(number: String): Boolean = validate(parse(number))
}

object LuhnTest extends App {
  Seq(("49927398716", true),
    ("49927398717", false),
    ("1234567812345678", false),
    ("1234567812345670", true)
  ).foreach { case (n, expected) =>
    println(s"$n ${Luhn.validate(n)}")
    assert(Luhn.validate(n) == expected)
  }
}


(define luhn
  (lambda (n)
    (let loop ((number n)
               (index 0)
               (result 0))
      (if (= 0 number)
          (= 0 (remainder result 10))
          (loop (quotient number 10)
                (+ index 1)
                (+ result
                   (if (even? index)
                       (remainder number 10)
                       (let ((part (* 2 (remainder number 10))))
                         (+ (remainder part 10) (quotient part 10))))))))))


$ include "seed7_05.s7i";

const func boolean: luhnTest (in string: cardNumber) is func
  result
    var boolean: luhnTest is FALSE;
  local
    var integer: index is 0;
    var integer: digit is 0;
    var boolean: isOdd is TRUE;
    var integer: oddSum is 0;
    var integer: evenSum is 0;
  begin
    for index range length(cardNumber) downto 1 do
      digit := integer parse str(cardNumber[index]);
      if isOdd then
        oddSum +:= digit;
      else
        evenSum +:= digit div 5 + (2 * digit) rem 10;
      end if;
      isOdd := not isOdd;
    end for;
    luhnTest := (oddSum + evenSum) rem 10 = 0;
  end func;

const proc: main is func
  local
    var string: cardNumber is "";
  begin
    for cardNumber range [] ("49927398716", "49927398717", "1234567812345678", "1234567812345670") do
      writeln(cardNumber <& ": " <& luhnTest(cardNumber));
    end for;
  end func;


function LuhnCheck ccNum
	put length of ccNum into numDigits
	put the last character of ccNum into total
	put numDigits modulo 2 into parity
	repeat for each character of the first numDigits - 1 characters of ccNum
		put it into digit
		if (the counter - 1) modulo 2 equals parity
			multiply digit by 2
		end if
		if digit is greater than 9
			subtract 9 from digit
		end if
		add digit to total
	end repeat
	return total is divisible by 10
end LuhnCheck


main(args(2)) :=
	sum(luhnTest(asciiToInt(args[1]) - asciiToInt('0'))) mod 10 = 0;

s2Mapping := [0,2,4,6,8,1,3,5,7,9];

luhnTest(x(1))[i] :=
	x[i] when i mod 2 = size(x) mod 2 else
	s2Mapping[x[i] + 1];


(define mapi
  _ _ []       -> []
  F N [X | Xs] -> [(F N X) | (mapi F (+ N 1) Xs)])

(define double
  X -> (let Y (* 2 X) (if (> Y 9) (- Y 9) Y)))

(define luhn?
  Number ->
    (let Exploded (explode Number)
         Digits   (map (/. H (- (string->n H) 48)) Exploded)
         Reversed (reverse Digits)
         Doubled  (mapi (/. N X (if (= 1 (shen.mod N 2)) (double X) X)) 0 Reversed)
         Summed   (sum Doubled)
         Modded   (shen.mod Summed 10)
      (= 0 Modded)))

"Expected: [true false false true]"

(map (function luhn?) ["49927398716" "49927398717" "1234567812345678" "1234567812345670"])


          define('luhn(n)a,d,i,j,sum') :(luhn_end)
luhn      n = reverse(n); a = array('0:9')
ln1       a<i> = (2 * i / 10) + remdr(2 * i,10)
          i = lt(i,9) i + 1 :s(ln1)
ln2       n len(1) . d = :f(ln3)
          d = ne(remdr(j,2),0) a<d>; j = j + 1
          sum = sum + d :(ln2)
ln3       luhn = 0; luhn = eq(remdr(sum,10),0) 1 :(return)
luhn_end

          ok = array('0:1')
          ok<0> = 'FAIL'
          ok<1> = 'OK'

*         Test and display
          define('test(n)')  :(test_end)
test      output = n ': ' ok<luhn(n)> :(return)
test_end

          test('49927398716')
          test('49927398717')
          test('1234567812345678')
          test('1234567812345670')
end


with Spark_IO;
--# inherit Spark_IO;
--# main_program;
procedure Luhn
--# global in out Spark_IO.Outputs;
--# derives Spark_IO.Outputs from *;
is

   function Luhn_Test (Num : String) return Boolean
   --# pre  Num'Last <= 20;
   is
      Sum : Integer := 0;
      Od  : Boolean := True;
      Int : Integer;
      X   : Integer;
      OK  : Boolean := True;
   begin
      for P in reverse Integer range Num'Range loop
         Int := Character'Pos(Num(P)) - Character'Pos('0');
         if Int not in 0 .. 9 then
            OK := False;
            exit;
         end if;
         X := (((Int*2) mod 10) + (Int / 5));
         --# assert Num'Last - P in 0 .. 19
         --#   and  Sum in 0 .. (Num'Last - P) * 10
         --#   and  Int in 0 .. 9
         --#   and  X   in 0 .. 10;
         if Od then
            Sum := Sum + Int;
         else
            Sum := Sum + X;
         end if;
         Od := not Od;
      end loop;
      return OK and (Sum mod 10) = 0;
   end Luhn_Test;

   procedure Do_Test (Num : in     String)
   --# global in out Spark_IO.Outputs;
   --# derives Spark_IO.Outputs from *, Num;
   --# pre  Num'Last <= 20;
   is
   begin
      Spark_IO.Put_String(Spark_IO.Standard_Output, Num, 16);
      if Luhn_Test(Num) then
         Spark_IO.Put_String(Spark_IO.Standard_Output, " is valid.", 0);
      else
         Spark_IO.Put_String(Spark_IO.Standard_Output, " is not valid.", 0);
      end if;
      Spark_IO.New_Line(Spark_IO.Standard_Output, 1);
   end Do_Test;

begin
   Do_Test("49927398716");
   Do_Test("49927398717");
   Do_Test("1234567812345678");
   Do_Test("1234567812345670");
   Do_Test("123456781234567D");
end Luhn;