Module Module1

    Sub Main()
        Using active As New Integrator
            active.Operation = Function(t As Double) Math.Sin(2 * Math.PI * 0.5 * t)
            Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
            Console.WriteLine(active.Value)
            active.Operation = Function(t As Double) 0
            Threading.Thread.Sleep(TimeSpan.FromSeconds(0.5))
            Console.WriteLine(active.Value)
        End Using
        Console.ReadLine()
    End Sub

End Module

Class Integrator
    Implements IDisposable

    Private m_Operation As Func(Of Double, Double)
    Private m_Disposed As Boolean
    Private m_SyncRoot As New Object
    Private m_Value As Double

    Public Sub New()
        m_Operation = Function(void) 0.0
        Dim t As New Threading.Thread(AddressOf MainLoop)
        t.Start()
    End Sub

    Private Sub MainLoop()
        Dim epoch = Now
        Dim t0 = 0.0
        Do
            SyncLock m_SyncRoot
                Dim t1 = (Now - epoch).TotalSeconds
                m_Value = m_Value + (Operation(t1) + Operation(t0)) * (t1 - t0) / 2
                t0 = t1
            End SyncLock
            Threading.Thread.Sleep(10)
        Loop Until m_Disposed
    End Sub

    Public Property Operation() As Func(Of Double, Double)
        Get
            SyncLock m_SyncRoot
                Return m_Operation
            End SyncLock
        End Get
        Set(ByVal value As Func(Of Double, Double))
            SyncLock m_SyncRoot
                m_Operation = value
            End SyncLock
        End Set
    End Property

    Public ReadOnly Property Value() As Double
        Get
            SyncLock m_SyncRoot
                Return m_Value
            End SyncLock
        End Get
    End Property

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        m_Disposed = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

End Class


import "scheduler" for Scheduler
import "timer" for Timer

var Interval = 0

class Integrator {
    construct new() {
        _sum = 0
    }

    input(k) {
        _k = k
        _v0 = k.call(0)
        _t = 0
        _running = true
        integrate_()
    }

    output { _sum }

    stop() {
        _running = false
    }

    integrate_() {
        while (_running) {
            Timer.sleep(1)
            update_()
        }
    }

    update_() {
        _t = _t + Interval
        var v1 = _k.call(_t)
        var trap = Interval * (_v0 + v1) / 2
        _sum = _sum + trap
        _v0 = v1
    }
}

var integrator = Integrator.new()
Scheduler.add {
    Interval = 2 / 1550  // machine specific value
    integrator.input(Fn.new { |t| (Num.pi * t).sin })
}
Timer.sleep(2000)

Scheduler.add {
    Interval = 0.5 / 775 // machine specific value
    integrator.input(Fn.new { |t| 0 })
}
Timer.sleep(500)

integrator.stop()
System.print(integrator.output)


class Integrator{
   // continuously integrate a function `K`, at each `interval` seconds'
   fcn init(f,interval=1e-4){
      var _interval=interval, K=Ref(f), S=Ref(0.0), run=True;
      self.launch();  // start me as a thread
   }
   fcn liftoff{ // entry point for the thread
      start:=Time.Clock.timef;  // floating point seconds since Epoch
      t0,k0,s:=0,K.value(0),S.value;
      while(run){
	 Atomic.sleep(_interval);
	 t1,k1:=Time.Clock.timef - start, K.value(t1);
	 s+=(k1 + k0)*(t1 - t0)/2.0; S.set(s);
	 t0,k0=t1,k1;
      }
   }
   fcn sample  { S.value  }
   fcn setF(f) { K.set(f) }
}


/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program achilleNumber.s   */

/************************************/
/* Constantes                       */
/************************************/
.include "../includeConstantesARM64.inc"
.equ NBFACT,    33
.equ MAXI,      50
.equ MAXI1,     20
.equ MAXI2,     1000000

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessNumber:       .asciz " @ "
szCarriageReturn:   .asciz "\n"
szErrorGen:         .asciz "Program error !!!\n"
szMessPrime:        .asciz "This number is prime.\n"
szMessErrGen:       .asciz "Error end program.\n"
szMessNbPrem:       .asciz "This number is prime !!!.\n"
szMessOverflow:     .asciz "Overflow function isPrime.\n"
szMessError:        .asciz "\033[31mError  !!!\n"
szMessTitAchille:   .asciz "First 50 Achilles Numbers:\n"
szMessTitStrong:    .asciz "First 20 Strong Achilles Numbers:\n"
szMessDigitsCounter: .asciz "Numbers with @ digits : @ \n"
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:           .skip 24
tbZoneDecom:         .skip 16 * NBFACT  // factor 8 bytes, number of each factor 8 bytes
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                             // entry of program

    ldr x0,qAdrszMessTitAchille
    bl affichageMess
    mov x4,#1                      // start number
    mov x5,#0                      // total counter
    mov x6,#0                      // line display counter
1:
    mov x0,x4
    bl controlAchille
    cmp x0,#0                      // achille number ?
    beq 2f                         // no
    mov x0,x4
    ldr x1,qAdrsZoneConv
    bl conversion10                // call décimal conversion
    ldr x0,qAdrszMessNumber
    ldr x1,qAdrsZoneConv           // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess               // display message
    add x5,x5,#1                   // increment counter
    add x6,x6,#1                   // increment indice line display
    cmp x6,#10                     // if = 10  new line
    bne 2f
    mov x6,#0
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
2:
    add x4,x4,#1                   // increment number
    cmp x5,#MAXI
    blt 1b                         // and loop

    ldr x0,qAdrszMessTitStrong
    bl affichageMess
    mov x4,#1                      // start number
    mov x5,#0                      // total counter
    mov x6,#0

3:
    mov x0,x4
    bl controlAchille
    cmp x0,#0
    beq 4f
    mov x0,x4
    bl computeTotient
    bl controlAchille
    cmp x0,#0
    beq 4f
    mov x0,x4
    ldr x1,qAdrsZoneConv
    bl conversion10                  // call décimal conversion
    ldr x0,qAdrszMessNumber
    ldr x1,qAdrsZoneConv             // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess                 // display message
    add x5,x5,#1
    add x6,x6,#1
    cmp x6,#10
    bne 4f
    mov x6,#0
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
4:
    add x4,x4,#1
    cmp x5,#MAXI1
    blt 3b

    ldr x3,icstMaxi2
    mov x4,#1                      // start number
    mov x6,#0                      // total counter 2 digits
    mov x7,#0                      // total counter 3 digits
    mov x8,#0                      // total counter 4 digits
    mov x9,#0                      // total counter 5 digits
    mov x10,#0                     // total counter 6 digits
5:
    mov x0,x4
    bl controlAchille
    cmp x0,#0
    beq 10f

    mov x0,x4
    ldr x1,qAdrsZoneConv
    bl conversion10             // call décimal conversion x0 return digit number
    cmp x0,#6
    bne 6f
    add x10,x10,#1
    beq 10f
 6:
    cmp x0,#5
    bne 7f
    add x9,x9,#1
    b 10f
 7:
    cmp x0,#4
    bne 8f
    add x8,x8,#1
    b 10f
 8:
    cmp x0,#3
    bne 9f
    add x7,x7,#1
    b 10f
 9:
    cmp x0,#2
    bne 10f
    add x6,x6,#1
10:

    add x4,x4,#1
    cmp x4,x3
    blt 5b
    mov x0,#2
    mov x1,x6
    bl displayCounter
    mov x0,#3
    mov x1,x7
    bl displayCounter
    mov x0,#4
    mov x1,x8
    bl displayCounter
    mov x0,#5
    mov x1,x9
    bl displayCounter
    mov x0,#6
    mov x1,x10
    bl displayCounter
    b 100f
98:
    ldr x0,qAdrszErrorGen
    bl affichageMess
100:                              // standard end of the program
    mov x0, #0                    // return code
    mov x8,EXIT
    svc #0                        // perform the system call
qAdrszCarriageReturn:    .quad szCarriageReturn
qAdrszErrorGen:          .quad szErrorGen
qAdrsZoneConv:           .quad sZoneConv
qAdrtbZoneDecom:         .quad tbZoneDecom
qAdrszMessNumber:        .quad szMessNumber
qAdrszMessTitAchille:    .quad szMessTitAchille
qAdrszMessTitStrong:     .quad szMessTitStrong
icstMaxi2:               .quad MAXI2
/******************************************************************/
/*     display digit counter                        */
/******************************************************************/
/* x0 contains limit  */
/* x1 contains counter */
displayCounter:
    stp x1,lr,[sp,-16]!          // save  registers
    stp x2,x3,[sp,-16]!          // save  registers
    mov x2,x1
    ldr x1,qAdrsZoneConv
    bl conversion10             // call décimal conversion
    ldr x0,qAdrszMessDigitsCounter
    ldr x1,qAdrsZoneConv        // insert conversion in message
    bl strInsertAtCharInc
    mov x3,x0
    mov x0,x2
    ldr x1,qAdrsZoneConv
    bl conversion10             // call décimal conversion
    mov x0,x3
    ldr x1,qAdrsZoneConv        // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess            // display message
100:
    ldp x2,x3,[sp],16           // restaur  registers
    ldp x1,lr,[sp],16           // restaur  registers
    ret
qAdrszMessDigitsCounter:   .quad szMessDigitsCounter
/******************************************************************/
/*     control if number is Achille number                        */
/******************************************************************/
/* x0 contains number  */
/* x0 return 0 if not else return 1 */
controlAchille:
    stp x1,lr,[sp,-16]!          // save  registers
    stp x2,x3,[sp,-16]!          // save  registers
    stp x4,x5,[sp,-16]!          // save  registers
    mov x4,x0
    ldr x1,qAdrtbZoneDecom
    bl decompFact               // factor decomposition
    cmp x0,#-1
    beq 99f                     // error ?
    cmp x0,#1                   // one only factor or prime ?
    ble 98f
    mov x1,x0
    ldr x0,qAdrtbZoneDecom
    mov x2,x4
    bl controlDivisor
    b 100f
98:
    mov x0,#0
    b 100f
99:
    ldr x0,qAdrszErrorGen
    bl affichageMess
100:
    ldp x4,x5,[sp],16        // restaur  registers
    ldp x2,x3,[sp],16        // restaur  registers
    ldp x1,lr,[sp],16            // restaur  registers
    ret
/******************************************************************/
/*     control divisors function                         */
/******************************************************************/
/* x0 contains address of divisors area */
/* x1 contains the number of area items  */
/* x2 contains number  */
controlDivisor:
    stp x1,lr,[sp,-16]!          // save  registers
    stp x2,x3,[sp,-16]!          // save  registers
    stp x4,x5,[sp,-16]!          // save  registers
    stp x6,x7,[sp,-16]!          // save  registers
    stp x8,x9,[sp,-16]!          // save  registers
    stp x10,x11,[sp,-16]!          // save  registers

    mov x6,x1                   // factors number
    mov x8,x2                   // save number
    mov x9,#0                   // indice
    mov x4,x0                   // save area address
    add x5,x4,x9,lsl #4         // compute address first factor
    ldr x7,[x5,#8]              // load first exposant of factor
    add x2,x9,#1
1:
    add x5,x4,x2,lsl #4         // compute address next factor
    ldr x3,[x5,#8]              // load exposant of factor
    cmp x3,x7                   // factor exposant <> ?
    bne 2f                      // yes -> end verif
    add x2,x2,#1                // increment indice
    cmp x2,x6                   // factor maxi ?
    blt 1b                      // no -> loop
    mov x0,#0
    b 100f                      // all exposants are equals
2:
    mov x10,x2                  // save indice
21:
    bge 22f
    mov x2,x7                 // if x3 < x7 -> inversion
    mov x7,x3
    mov x3,x2                 // x7 is the smaller exposant
22:
    mov x0,x3
    mov x1,x7                   // x7 < x3
    bl calPGCDmod
    cmp x0,#1
    beq 24f                     // no commun multiple -> ne peux donc pas etre une puissance
23:
    add x10,x10,#1              // increment indice
    cmp x10,x6                  // factor maxi ?
    bge 99f                     // yes -> all exposants are multiples to smaller
    add x5,x4,x10,lsl #4
    ldr x3,[x5,#8]              // load exposant of next factor
    cmp x3,x7
    beq 23b                     // for next
    b 21b                       // for compare the 2 exposants

24:
    mov x9,#0                   // indice
3:
    add x5,x4,x9,lsl #4
    ldr x7,[x5]                 // load factor
    mul x1,x7,x7                // factor square
    udiv x2,x8,x1
    msub x3,x1,x2,x8            // compute remainder
    cmp x3,#0                   // remainder null ?
    bne 99f

    add x9,x9,#1                // other factor
    cmp x9,x6                   // factors maxi ?
    blt 3b
    mov x0,#1                   // achille number ok
    b 100f
99:                             // achille not ok
    mov x0,0
100:
    ldp x10,x11,[sp],16            // restaur  registers
    ldp x8,x9,[sp],16            // restaur  registers
    ldp x6,x7,[sp],16            // restaur  registers
    ldp x4,x5,[sp],16            // restaur  registers
    ldp x2,x3,[sp],16            // restaur  registers
    ldp x1,lr,[sp],16            // restaur  registers
    ret

/***************************************************/
/*   Compute pgcd  modulo use                     */
/***************************************************/
/* x0 contains first number */
/* x1 contains second number */
/* x0 return  PGCD            */
/* if error carry set to 1    */
calPGCDmod:
    stp x1,lr,[sp,-16]!        // save  registres
    stp x2,x3,[sp,-16]!        // save  registres
    cbz x0,99f                 // if = 0 error
    cbz x1,99f
    cmp x0,0
    bgt 1f
    neg x0,x0                  // if negative inversion number 1
1:
    cmp x1,0
    bgt 2f
    neg x1,x1                  // if negative inversion number 2
2:
    cmp x0,x1                  // compare two numbers
    bgt 3f
    mov x2,x0                  // inversion
    mov x0,x1
    mov x1,x2
3:
    udiv x2,x0,x1              // division
    msub x0,x2,x1,x0           // compute remainder
    cmp x0,0
    bgt 2b                     // loop
    mov x0,x1
    cmn x0,0                   // clear carry
    b 100f
99:                            // error
    mov x0,0
    cmp x0,0                   // set carry
100:
    ldp x2,x3,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret                        // retour adresse lr x30
/******************************************************************/
/*     compute totient of number                                  */
/******************************************************************/
/* x0 contains number  */
computeTotient:
    stp x1,lr,[sp,-16]!       // save  registers
    stp x2,x3,[sp,-16]!       // save  registers
    stp x4,x5,[sp,-16]!       // save  registers
    mov x4,x0                 // totient
    mov x5,x0                 // save number
    mov x1,#0                 // for first divisor
1:                            // begin loop
    mul x3,x1,x1              // compute square
    cmp x3,x5                 // compare number
    bgt 4f                    // end
    add x1,x1,#2              // next divisor
    udiv x2,x5,x1
    msub x3,x1,x2,x5          // compute remainder
    cmp x3,#0                 // remainder null ?
    bne 3f
2:                            // begin loop 2
    udiv x2,x5,x1
    msub x3,x1,x2,x5          // compute remainder
    cmp x3,#0
    csel x5,x2,x5,eq          // new value = quotient
    beq 2b

    udiv x2,x4,x1             // divide totient
    sub x4,x4,x2              // compute new totient
3:
    cmp x1,#2                 // first divisor ?
    mov x0,1
    csel x1,x0,x1,eq          // divisor = 1
    b 1b                      // and loop
4:
    cmp x5,#1                 // final value > 1
    ble 5f
    mov x0,x4                 // totient
    mov x1,x5                 // divide by value
    udiv x2,x4,x5             // totient divide by value
    sub x4,x4,x2              // compute new totient
5:

    mov x0,x4
100:
    ldp x4,x5,[sp],16         // restaur  registers
    ldp x2,x3,[sp],16         // restaur  registers
    ldp x1,lr,[sp],16         // restaur  registers
    ret
/******************************************************************/
/*     factor decomposition                                               */
/******************************************************************/
/* x0 contains number */
/* x1 contains address of divisors area */
/* x0 return divisors items in table */
decompFact:
    stp x1,lr,[sp,-16]!          // save  registers
    stp x2,x3,[sp,-16]!          // save  registers
    stp x4,x5,[sp,-16]!          // save  registers
    stp x6,x7,[sp,-16]!          // save  registers
    stp x8,x9,[sp,-16]!          // save  registers
    mov x5,x1
    mov x8,x0                  // save number
    bl isPrime                 // prime ?
    cmp x0,#1
    beq 98f                    // yes is prime
    mov x4,#0                  // raz indice
    mov x1,#2                  // first divisor
    mov x6,#0                  // previous divisor
    mov x7,#0                  // number of same divisors
2:
    udiv x2,x8,x1              // divide number or other result
    msub x3,x2,x1,x8           // compute remainder
    cmp x3,#0
    bne 5f                     // if remainder <> zero  -> no divisor
    mov x8,x2                  // else quotient -> new dividende
    cmp x1,x6                  // same divisor ?
    beq 4f                     // yes
    cmp x6,#0                  // no but is the first divisor ?
    beq 3f                     // yes
    str x6,[x5,x4,lsl #3]      // else store in the table
    add x4,x4,#1               // and increment counter
    str x7,[x5,x4,lsl #3]      // store counter
    add x4,x4,#1               // next item
    mov x7,#0                  // and raz counter
3:
    mov x6,x1                  // new divisor
4:
    add x7,x7,#1               // increment counter
    b 7f                       // and loop

    /* not divisor -> increment next divisor */
5:
    cmp x1,#2                  // if divisor = 2 -> add 1
    mov x0,#1
    mov x3,#2                  // else add 2
    csel x3,x0,x3,eq
    add x1,x1,x3
    b 2b

    /* divisor -> test if new dividende is prime */
7:
    mov x3,x1                  // save divisor
    cmp x8,#1                  // dividende = 1 ? -> end
    beq 10f
    mov x0,x8                  // new dividende is prime ?
    mov x1,#0
    bl isPrime                 // the new dividende is prime ?
    cmp x0,#1
    bne 10f                    // the new dividende is not prime

    cmp x8,x6                  // else dividende is same divisor ?
    beq 9f                     // yes
    cmp x6,#0                  // no but is the first divisor ?
    beq 8f                     // yes it is a first
    str x6,[x5,x4,lsl #3]      // else store in table
    add x4,x4,#1               // and increment counter
    str x7,[x5,x4,lsl #3]      // and store counter
    add x4,x4,#1               // next item
8:
    mov x6,x8                  // new dividende -> divisor prec
    mov x7,#0                  // and raz counter
9:
    add x7,x7,#1               // increment counter
    b 11f

10:
    mov x1,x3                  // current divisor = new divisor
    cmp x1,x8                  // current divisor  > new dividende ?
    ble 2b                     // no -> loop

    /* end decomposition */
11:
    str x6,[x5,x4,lsl #3]      // store last divisor
    add x4,x4,#1
    str x7,[x5,x4,lsl #3]      // and store last number of same divisors
    add x4,x4,#1
    lsr x0,x4,#1               // return number of table items
    mov x3,#0
    str x3,[x5,x4,lsl #3]      // store zéro in last table item
    add x4,x4,#1
    str x3,[x5,x4,lsl #3]      // and zero in counter same divisor
    b 100f

98:
    //ldr x0,qAdrszMessPrime
    //bl   affichageMess
    mov x0,#0                  // return code 0 = number is prime
    b 100f
99:
    ldr x0,qAdrszMessErrGen
    bl   affichageMess
    mov x0,#-1                  // error code
    b 100f
100:
    ldp x8,x9,[sp],16        // restaur  registers
    ldp x6,x7,[sp],16        // restaur  registers
    ldp x4,x5,[sp],16        // restaur  registers
    ldp x2,x3,[sp],16        // restaur  registers
    ldp x1,lr,[sp],16            // restaur  registers
    ret
qAdrszMessErrGen:          .quad szMessErrGen

/***************************************************/
/*   Verification si un nombre est premier         */
/***************************************************/
/* x0 contient le nombre à verifier */
/* x0 retourne 1 si premier  0 sinon */
isPrime:
    stp x1,lr,[sp,-16]!        // save  registres
    stp x2,x3,[sp,-16]!        // save  registres
    mov x2,x0
    sub x1,x0,#1
    cmp x2,0
    beq 99f                    // retourne zéro
    cmp x2,2                   // pour 1 et 2 retourne 1
    ble 2f
    mov x0,#2
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier
    cmp x2,3
    beq 2f
    mov x0,#3
    bl moduloPur64
    blt 100f                   // erreur overflow
    cmp x0,#1
    bne 99f

    cmp x2,5
    beq 2f
    mov x0,#5
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier

    cmp x2,7
    beq 2f
    mov x0,#7
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier

    cmp x2,11
    beq 2f
    mov x0,#11
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier

    cmp x2,13
    beq 2f
    mov x0,#13
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier

    cmp x2,17
    beq 2f
    mov x0,#17
    bl moduloPur64
    bcs 100f                   // erreur overflow
    cmp x0,#1
    bne 99f                    // Pas premier
2:
    cmn x0,0                   // carry à zero pas d'erreur
    mov x0,1                   // premier
    b 100f
99:
    cmn x0,0                   // carry à zero pas d'erreur
    mov x0,#0                  // Pas premier
100:
    ldp x2,x3,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret                        // retour adresse lr x30

/**************************************************************/
/********************************************************/
/*   Calcul modulo de b puissance e modulo m  */
/*    Exemple 4 puissance 13 modulo 497 = 445         */
/********************************************************/
/* x0  nombre  */
/* x1 exposant */
/* x2 modulo   */
moduloPur64:
    stp x1,lr,[sp,-16]!        // save  registres
    stp x3,x4,[sp,-16]!        // save  registres
    stp x5,x6,[sp,-16]!        // save  registres
    stp x7,x8,[sp,-16]!        // save  registres
    stp x9,x10,[sp,-16]!        // save  registres
    cbz x0,100f
    cbz x1,100f
    mov x8,x0
    mov x7,x1
    mov x6,1                   // resultat
    udiv x4,x8,x2
    msub x9,x4,x2,x8           // contient le reste
1:
    tst x7,1
    beq 2f
    mul x4,x9,x6
    umulh x5,x9,x6
    //cbnz x5,99f
    mov x6,x4
    mov x0,x6
    mov x1,x5
    bl divisionReg128U
    cbnz x1,99f                // overflow
    mov x6,x3
2:
    mul x8,x9,x9
    umulh x5,x9,x9
    mov x0,x8
    mov x1,x5
    bl divisionReg128U
    cbnz x1,99f                // overflow
    mov x9,x3
    lsr x7,x7,1
    cbnz x7,1b
    mov x0,x6                  // result
    cmn x0,0                   // carry à zero pas d'erreur
    b 100f
99:
    ldr x0,qAdrszMessOverflow
    bl  affichageMess
    cmp x0,0                   // carry à un car erreur
    mov x0,-1                  // code erreur

100:
    ldp x9,x10,[sp],16          // restaur des  2 registres
    ldp x7,x8,[sp],16          // restaur des  2 registres
    ldp x5,x6,[sp],16          // restaur des  2 registres
    ldp x3,x4,[sp],16          // restaur des  2 registres
    ldp x1,lr,[sp],16          // restaur des  2 registres
    ret                        // retour adresse lr x30
qAdrszMessOverflow:         .quad  szMessOverflow
/***************************************************/
/*   division d un nombre de 128 bits par un nombre de 64 bits */
/***************************************************/
/* x0 contient partie basse dividende */
/* x1 contient partie haute dividente */
/* x2 contient le diviseur */
/* x0 retourne partie basse quotient */
/* x1 retourne partie haute quotient */
/* x3 retourne le reste */
divisionReg128U:
    stp x6,lr,[sp,-16]!        // save  registres
    stp x4,x5,[sp,-16]!        // save  registres
    mov x5,#0                  // raz du reste R
    mov x3,#128                // compteur de boucle
    mov x4,#0                  // dernier bit
1:
    lsl x5,x5,#1               // on decale le reste de 1
    tst x1,1<<63               // test du bit le plus à gauche
    lsl x1,x1,#1               // on decale la partie haute du quotient de 1
    beq 2f
    orr  x5,x5,#1              // et on le pousse dans le reste R
2:
    tst x0,1<<63
    lsl x0,x0,#1               // puis on decale la partie basse
    beq 3f
    orr x1,x1,#1               // et on pousse le bit de gauche dans la partie haute
3:
    orr x0,x0,x4               // position du dernier bit du quotient
    mov x4,#0                  // raz du bit
    cmp x5,x2
    blt 4f
    sub x5,x5,x2                // on enleve le diviseur du reste
    mov x4,#1                   // dernier bit à 1
4:
                               // et boucle
    subs x3,x3,#1
    bgt 1b
    lsl x1,x1,#1               // on decale le quotient de 1
    tst x0,1<<63
    lsl x0,x0,#1              // puis on decale la partie basse
    beq 5f
    orr x1,x1,#1
5:
    orr x0,x0,x4                  // position du dernier bit du quotient
    mov x3,x5
100:
    ldp x4,x5,[sp],16          // restaur des  2 registres
    ldp x6,lr,[sp],16          // restaur des  2 registres
    ret                        // retour adresse lr x30
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../includeARM64.inc"


BEGIN # find Achilles Numbers: numbers whose prime factors p appear at least  #
      # twice (i.e. if p is a prime factor, so is p^2) and cannot be          #
      # expressed as m^k for any integer m, k > 1                             #
      # also find strong Achilles Numbers: Achilles Numbers where the Euler's #
      # totient of the number is also Achilles                                #
    # returns the number of integers k where 1 <= k <= n that are mutually    #
    #         prime to n                                                      #
    PROC totient = ( INT n )INT:        # algorithm from the second Go sample #
        IF   n < 3 THEN 1               #        in the Totient Function task #
        ELIF n = 3 THEN 2
        ELSE
            INT result := n;
            INT v      := n;
            INT i      := 2;
            WHILE i * i <= v DO
                IF v MOD i = 0 THEN
                    WHILE v MOD i = 0 DO v OVERAB i OD;
                    result -:= result OVER i
                FI;
                IF i = 2 THEN
                   i := 1
                FI;
                i +:= 2
            OD;
            IF v > 1 THEN result -:= result OVER v FI;
            result
         FI # totient # ;
    # find the numbers                                                        #
    INT max number = 1 000 000;                 # max number we will consider #
    PR read "primes.incl.a68" PR                #     include prime utilities #
    []BOOL prime = PRIMESIEVE max number;       # construct a sieve of primes #
    # table of numbers, will be set to TRUE for the Achilles Numbers          #
    [ 1 : max number ]BOOL achiles;
    FOR a TO UPB achiles DO
        achiles[ a ] := TRUE
    OD;
    # remove the numbers that don't have squared primes as factors            #
    achiles[ 1 ] := FALSE;
    FOR a TO UPB achiles DO
        IF prime[ a ] THEN
            # have a prime, remove it and every multiple of it that isn't a   #
            # multiple of a squared                                           #
            INT a count := 0;
            FOR j FROM a BY a TO UPB achiles DO
                a count +:= 1;
                IF a count = a THEN # have a multiple of i^2, keep the number #
                    a count := 0
                ELSE               # not a multiple of i^2, remove the number #
                    achiles[ j ] := FALSE
                FI
            OD
        FI
    OD;
    # achiles now has TRUE for the powerful numbers, remove all m^k (m,k > 1) #
    FOR m FROM 2 TO UPB achiles DO
        INT mk    := m;
        INT max mk = UPB achiles OVER m;    # avoid overflow if INT is 32 bit #
        WHILE mk <= max mk DO
            mk           *:= m;
            achiles[ mk ] := FALSE
        OD
    OD;
    # achiles now has TRUE for imperfect powerful numbers                     #
    # show the first 50 Achilles Numbers                                      #
    BEGIN
        print( ( "First 50 Achilles Numbers:", newline ) );
        INT a count := 0;
        FOR a WHILE a count < 50 DO
            IF achiles[ a ] THEN
                a count +:= 1;
                print( ( " ", whole( a, -6 ) ) );
                IF a count MOD 10 = 0 THEN
                    print( ( newline ) )
                FI
            FI
        OD
    END;
    # show the first 50 Strong Achilles numbers                               #
    BEGIN
        print( ( "First 20 Strong Achilles Numbers:", newline ) );
        INT s count := 0;
        FOR s WHILE s count < 20 DO
            IF achiles[ s ] THEN
                IF achiles[ totient( s ) ] THEN
                    s count +:= 1;
                    print( ( " ", whole( s, -6 ) ) );
                    IF s count MOD 10 = 0 THEN
                        print( ( newline ) )
                    FI
                FI
            FI
        OD
    END;
    # count the number of Achilles Numbers by their digit counts              #
    BEGIN
        INT a count     :=   0;
        INT power of 10 := 100;
        INT digit count :=   2;
        FOR a TO UPB achiles DO
            IF achiles[ a ] THEN
                # have an Achilles Number                                     #
                a count +:= 1
            FI;
            IF a = power of 10 THEN
                # have reached a power of 10                                  #
                print( ( "Achilles Numbers with ", whole( digit count, 0 )
                       , " digits: ",             whole( a count,    -6 )
                       , newline
                       )
                     );
                digit count +:=  1;
                power of 10 *:= 10;
                a count      :=  0
            FI
        OD
    END
END


/* ARM assembly Raspberry PI  */
/*  program achilleNumber.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 */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"
.equ NBFACT,    33
.equ MAXI,      50
.equ MAXI1,     20
.equ MAXI2,     1000000

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessNumber:       .asciz " @ "
szCarriageReturn:   .asciz "\n"
szErrorGen:         .asciz "Program error !!!\n"
szMessPrime:        .asciz "This number is prime.\n"
szMessTitAchille:   .asciz "First 50 Achilles Numbers:\n"
szMessTitStrong:    .asciz "First 20 Strong Achilles Numbers:\n"
szMessDigitsCounter: .asciz "Numbers with @ digits : @ \n"
/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:           .skip 24
tbZoneDecom:         .skip 8 * NBFACT          // factor 4 bytes, number of each factor 4 bytes
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                             @ entry of program
    ldr r0,iAdrszMessTitAchille
    bl affichageMess
    mov r4,#1                      @ start number
    mov r5,#0                      @ total counter
    mov r6,#0                      @ line display counter
1:
    mov r0,r4
    bl controlAchille
    cmp r0,#0                      @ achille number ?
    beq 2f                         @ no
    mov r0,r4
    ldr r1,iAdrsZoneConv
    bl conversion10                @ call décimal conversion
    ldr r0,iAdrszMessNumber
    ldr r1,iAdrsZoneConv           @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess               @ display message
    add r5,r5,#1                   @ increment counter
    add r6,r6,#1                   @ increment indice line display
    cmp r6,#10                     @ if = 10  new line
    bne 2f
    mov r6,#0
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
2:
    add r4,r4,#1                   @ increment number
    cmp r5,#MAXI
    blt 1b                         @ and loop

    ldr r0,iAdrszMessTitStrong
    bl affichageMess
    mov r4,#1                      @ start number
    mov r5,#0                      @ total counter
    mov r6,#0

3:
    mov r0,r4
    bl controlAchille
    cmp r0,#0
    beq 4f
    mov r0,r4
    bl computeTotient
    bl controlAchille
    cmp r0,#0
    beq 4f
    mov r0,r4
    ldr r1,iAdrsZoneConv
    bl conversion10                  @ call décimal conversion
    ldr r0,iAdrszMessNumber
    ldr r1,iAdrsZoneConv             @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess                 @ display message
    add r5,r5,#1
    add r6,r6,#1
    cmp r6,#10
    bne 4f
    mov r6,#0
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
4:
    add r4,r4,#1
    cmp r5,#MAXI1
    blt 3b

    ldr r3,icstMaxi2
    mov r4,#1                      @ start number
    mov r6,#0                      @ total counter 2 digits
    mov r7,#0                      @ total counter 3 digits
    mov r8,#0                      @ total counter 4 digits
    mov r9,#0                      @ total counter 5 digits
    mov r10,#0                     @ total counter 6 digits
5:
    mov r0,r4
    bl controlAchille
    cmp r0,#0
    beq 6f

    mov r0,r4
    ldr r1,iAdrsZoneConv
    bl conversion10             @ call décimal conversion r0 return digit number
    cmp r0,#6
    addeq r10,r10,#1
    beq 6f
    cmp r0,#5
    addeq r9,r9,#1
    beq 6f
    cmp r0,#4
    addeq r8,r8,#1
    beq 6f
    cmp r0,#3
    addeq r7,r7,#1
    beq 6f
    cmp r0,#2
    addeq r6,r6,#1
    beq 6f
6:

    add r4,r4,#1
    cmp r4,r3
    blt 5b
    mov r0,#2
    mov r1,r6
    bl displayCounter
    mov r0,#3
    mov r1,r7
    bl displayCounter
    mov r0,#4
    mov r1,r8
    bl displayCounter
    mov r0,#5
    mov r1,r9
    bl displayCounter
    mov r0,#6
    mov r1,r10
    bl displayCounter
    b 100f
98:
    ldr r0,iAdrszErrorGen
    bl affichageMess
100:                              @ standard end of the program
    mov r0, #0                    @ return code
    mov r7, #EXIT                 @ request to exit program
    svc #0                        @ perform the system call
iAdrszCarriageReturn:    .int szCarriageReturn
iAdrszErrorGen:          .int szErrorGen
iAdrsZoneConv:           .int sZoneConv
iAdrtbZoneDecom:         .int tbZoneDecom
iAdrszMessNumber:        .int szMessNumber
iAdrszMessTitAchille:    .int szMessTitAchille
iAdrszMessTitStrong:     .int szMessTitStrong
icstMaxi2:               .int MAXI2
/******************************************************************/
/*     display digit counter                        */
/******************************************************************/
/* r0 contains limit  */
/* r1 contains counter */
displayCounter:
    push {r1-r3,lr}            @ save  registers
    mov r2,r1
    ldr r1,iAdrsZoneConv
    bl conversion10             @ call décimal conversion
    ldr r0,iAdrszMessDigitsCounter
    ldr r1,iAdrsZoneConv        @ insert conversion in message
    bl strInsertAtCharInc
    mov r3,r0
    mov r0,r2
    ldr r1,iAdrsZoneConv
    bl conversion10             @ call décimal conversion
    mov r0,r3
    ldr r1,iAdrsZoneConv        @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess            @ display message
100:
    pop {r1-r3,pc}             @ restaur registers
iAdrszMessDigitsCounter:   .int szMessDigitsCounter
/******************************************************************/
/*     control if number is Achille number                        */
/******************************************************************/
/* r0 contains number  */
/* r0 return 0 if not else return 1 */
controlAchille:
    push {r1-r4,lr}            @ save  registers
    mov r4,r0
    ldr r1,iAdrtbZoneDecom
    bl decompFact               @ factor decomposition
    cmp r0,#-1
    beq 98f                     @ error ?
    cmp r0,#1                   @ one only factor ?
    moveq r0,#0
    beq 100f
    mov r1,r0
    ldr r0,iAdrtbZoneDecom
    mov r2,r4
    bl controlDivisor
    b 100f
98:
    ldr r0,iAdrszErrorGen
    bl affichageMess
100:
    pop {r1-r4,pc}             @ restaur registers
/******************************************************************/
/*     control divisors function                         */
/******************************************************************/
/* r0 contains address of divisors area */
/* r1 contains the number of area items  */
/* r2 contains number  */
controlDivisor:
    push {r1-r10,lr}            @ save  registers
    cmp r1,#0
    moveq r0,#0
    beq 100f
    mov r6,r1                   @ factors number
    mov r8,r2                   @ save number
    mov r9,#0                   @ indice
    mov r4,r0                   @ save area address
    add r5,r4,r9,lsl #3         @ compute address first factor
    ldr r7,[r5,#4]              @ load first exposant of factor
    add r2,r9,#1
1:
    add r5,r4,r2,lsl #3         @ compute address next factor
    ldr r3,[r5,#4]              @ load exposant of factor
    cmp r3,r7                   @ factor exposant <> ?
    bne 2f                      @ yes -> end verif
    add r2,r2,#1                @ increment indice
    cmp r2,r6                   @ factor maxi ?
    blt 1b                      @ no -> loop
    mov r0,#0
    b 100f                      @ all exposants are equals
2:
    mov r10,r2                  @ save indice
21:
    movlt r2,r7                 @ if r3 < r7 -> inversion
    movlt r7,r3
    movlt r3,r2                 @ r7 is the smaller exposant
    mov r0,r3
    mov r1,r7                   @ r7 < r3
    bl computePgcd
    cmp r0,#1
    beq 23f                     @ no commun multiple -> ne peux donc pas etre une puissance
22:
    add r10,r10,#1              @ increment indice
    cmp r10,r6                  @ factor maxi ?
    movge r0,#0
    bge 100f                    @ yes -> all exposants are multiples to smaller
    add r5,r4,r10,lsl #3
    ldr r3,[r5,#4]              @ load exposant of next factor
    cmp r3,r7
    beq 22b                     @ for next
    b 21b                       @ for compare the 2 exposants

23:
    mov r9,#0                   @ indice
3:
    add r5,r4,r9,lsl #3
    ldr r7,[r5]                 @ load factor
    mul r1,r7,r7                @ factor square
    mov r0,r8                   @ number
    bl division
    cmp r3,#0                   @ remainder null ?
    movne r0,#0
    bne 100f

    add r9,#1                   @ other factor
    cmp r9,r6                   @ factors maxi ?
    blt 3b
    mov r0,#1                   @ achille number ok
100:
    pop {r1-r10,lr}             @ restaur registers
    bx lr                       @ return

/******************************************/
/* calcul du pgcd                         */
/*****************************************/
/* r0 number one  */
/* r1 number two  */
/* r0 result return */
computePgcd:
    push {r2,lr}       @ save registers
1:
    cmp r0,#0
    ble 2f
    cmp r1,r0
    movgt r2,r0
    movgt r0,r1
    movgt r1,r2
    sub r0,r1
    b 1b
2:
    mov r0,r1
    pop {r2,pc}       @ restaur registers
/******************************************************************/
/*     compute totient of number                                  */
/******************************************************************/
/* r0 contains number  */
computeTotient:
    push {r1-r5,lr}           @ save  registers
    mov r4,r0                 @ totient
    mov r5,r0                 @ save number
    mov r1,#0                 @ for first divisor
1:                            @ begin loop
    mul r3,r1,r1              @ compute square
    cmp r3,r5                 @ compare number
    bgt 4f                    @ end
    add r1,r1,#2              @ next divisor
    mov r0,r5
    bl division
    cmp r3,#0                 @ remainder null ?
    bne 3f
2:                            @ begin loop 2
    mov r0,r5
    bl division
    cmp r3,#0
    moveq r5,r2               @ new value = quotient
    beq 2b

    mov r0,r4                 @ totient
    bl division
    sub r4,r4,r2              @ compute new totient
3:
    cmp r1,#2                 @ first divisor ?
    moveq r1,#1               @ divisor = 1
    b 1b                      @ and loop
4:
    cmp r5,#1                 @ final value > 1
    ble 5f
    mov r0,r4                 @ totient
    mov r1,r5                 @ divide by value
    bl division
    sub r4,r4,r2              @ compute new totient
5:

    mov r0,r4
100:
    pop {r1-r5,pc}             @ restaur registers

/******************************************************************/
/*     factor decomposition                                               */
/******************************************************************/
/* r0 contains number */
/* r1 contains address of divisors area */
/* r0 return divisors items in table */
decompFact:
    push {r1-r8,lr}            @ save  registers
    mov r5,r1
    mov r8,r0                  @ save number
    bl isPrime                 @ prime ?
    cmp r0,#1
    beq 98f                    @ yes is prime
    mov r4,#0                  @ raz indice
    mov r1,#2                  @ first divisor
    mov r6,#0                  @ previous divisor
    mov r7,#0                  @ number of same divisors
2:
    mov r0,r8                  @ dividende
    bl division                @  r1 divisor r2 quotient r3 remainder
    cmp r3,#0
    bne 5f                     @ if remainder <> zero  -> no divisor
    mov r8,r2                  @ else quotient -> new dividende
    cmp r1,r6                  @ same divisor ?
    beq 4f                     @ yes
    cmp r6,#0                  @ no but is the first divisor ?
    beq 3f                     @ yes
    str r6,[r5,r4,lsl #2]      @ else store in the table
    add r4,r4,#1               @ and increment counter
    str r7,[r5,r4,lsl #2]      @ store counter
    add r4,r4,#1               @ next item
    mov r7,#0                  @ and raz counter
3:
    mov r6,r1                  @ new divisor
4:
    add r7,r7,#1               @ increment counter
    b 7f                       @ and loop

    /* not divisor -> increment next divisor */
5:
    cmp r1,#2                  @ if divisor = 2 -> add 1
    addeq r1,#1
    addne r1,#2                @ else add 2
    b 2b

    /* divisor -> test if new dividende is prime */
7:
    mov r3,r1                  @ save divisor
    cmp r8,#1                  @ dividende = 1 ? -> end
    beq 10f
    mov r0,r8                  @ new dividende is prime ?
    mov r1,#0
    bl isPrime                 @ the new dividende is prime ?
    cmp r0,#1
    bne 10f                    @ the new dividende is not prime

    cmp r8,r6                  @ else dividende is same divisor ?
    beq 9f                     @ yes
    cmp r6,#0                  @ no but is the first divisor ?
    beq 8f                     @ yes it is a first
    str r6,[r5,r4,lsl #2]      @ else store in table
    add r4,r4,#1               @ and increment counter
    str r7,[r5,r4,lsl #2]      @ and store counter
    add r4,r4,#1               @ next item
8:
    mov r6,r8                  @ new dividende -> divisor prec
    mov r7,#0                  @ and raz counter
9:
    add r7,r7,#1               @ increment counter
    b 11f

10:
    mov r1,r3                  @ current divisor = new divisor
    cmp r1,r8                  @ current divisor  > new dividende ?
    ble 2b                     @ no -> loop

    /* end decomposition */
11:
    str r6,[r5,r4,lsl #2]      @ store last divisor
    add r4,r4,#1
    str r7,[r5,r4,lsl #2]      @ and store last number of same divisors
    add r4,r4,#1
    lsr r0,r4,#1               @ return number of table items
    mov r3,#0
    str r3,[r5,r4,lsl #2]      @ store zéro in last table item
    add r4,r4,#1
    str r3,[r5,r4,lsl #2]      @ and zero in counter same divisor
    b 100f

98:
    //ldr r0,iAdrszMessPrime
    //bl   affichageMess
    mov r0,#1                   @ return code
    b 100f
99:
    ldr r0,iAdrszErrorGen
    bl   affichageMess
    mov r0,#-1                  @ error code
    b 100f
100:
    pop {r1-r8,lr}              @ restaur registers
    bx lr
iAdrszMessPrime:           .int szMessPrime

/***************************************************/
/*   check if a number is prime              */
/***************************************************/
/* r0 contains the number            */
/* r0 return 1 if prime  0 else */
@2147483647
@4294967297
@131071
isPrime:
    push {r1-r6,lr}    @ save registers
    cmp r0,#0
    beq 90f
    cmp r0,#17
    bhi 1f
    cmp r0,#3
    bls 80f            @ for 1,2,3 return prime
    cmp r0,#5
    beq 80f            @ for 5 return prime
    cmp r0,#7
    beq 80f            @ for 7 return prime
    cmp r0,#11
    beq 80f            @ for 11 return prime
    cmp r0,#13
    beq 80f            @ for 13 return prime
    cmp r0,#17
    beq 80f            @ for 17 return prime
1:
    tst r0,#1          @ even ?
    beq 90f            @ yes -> not prime
    mov r2,r0          @ save number
    sub r1,r0,#1       @ exposant n - 1
    mov r0,#3          @ base
    bl moduloPuR32     @ compute base power n - 1 modulo n
    cmp r0,#1
    bne 90f            @ if <> 1  -> not prime

    mov r0,#5
    bl moduloPuR32
    cmp r0,#1
    bne 90f

    mov r0,#7
    bl moduloPuR32
    cmp r0,#1
    bne 90f

    mov r0,#11
    bl moduloPuR32
    cmp r0,#1
    bne 90f

    mov r0,#13
    bl moduloPuR32
    cmp r0,#1
    bne 90f

    mov r0,#17
    bl moduloPuR32
    cmp r0,#1
    bne 90f
80:
    mov r0,#1        @ is prime
    b 100f
90:
    mov r0,#0        @ no prime
100:                 @ fin standard de la fonction
    pop {r1-r6,lr}   @ restaur des registres
    bx lr            @ retour de la fonction en utilisant lr
/********************************************************/
/*   Calcul modulo de b puissance e modulo m  */
/*    Exemple 4 puissance 13 modulo 497 = 445         */
/*                                             */
/********************************************************/
/* r0  nombre  */
/* r1 exposant */
/* r2 modulo   */
/* r0 return result  */
moduloPuR32:
    push {r1-r7,lr}    @ save registers
    cmp r0,#0          @ verif <> zero
    beq 100f
    cmp r2,#0          @ verif <> zero
    beq 100f           @ TODO: vérifier les cas erreur
1:
    mov r4,r2          @ save modulo
    mov r5,r1          @ save exposant
    mov r6,r0          @ save base
    mov r3,#1          @ start result

    mov r1,#0          @ division de r0,r1 par r2
    bl division32R
    mov r6,r2          @ base <- remainder
2:
    tst r5,#1          @  exposant even or odd
    beq 3f
    umull r0,r1,r6,r3
    mov r2,r4
    bl division32R
    mov r3,r2          @ result <- remainder
3:
    umull r0,r1,r6,r6
    mov r2,r4
    bl division32R
    mov r6,r2          @ base <- remainder

    lsr r5,#1          @ left shift 1 bit
    cmp r5,#0          @ end ?
    bne 2b
    mov r0,r3
100:                   @ fin standard de la fonction
    pop {r1-r7,lr}     @ restaur des registres
    bx lr              @ retour de la fonction en utilisant lr

/***************************************************/
/*   division number 64 bits in 2 registers by number 32 bits */
/***************************************************/
/* r0 contains lower part dividende   */
/* r1 contains upper part dividende   */
/* r2 contains divisor   */
/* r0 return lower part quotient    */
/* r1 return upper part quotient    */
/* r2 return remainder               */
division32R:
    push {r3-r9,lr}    @ save registers
    mov r6,#0          @ init upper upper part remainder  !!
    mov r7,r1          @ init upper part remainder with upper part dividende
    mov r8,r0          @ init lower part remainder with lower part dividende
    mov r9,#0          @ upper part quotient
    mov r4,#0          @ lower part quotient
    mov r5,#32         @ bits number
1:                     @ begin loop
    lsl r6,#1          @ shift upper upper part remainder
    lsls r7,#1         @ shift upper  part remainder
    orrcs r6,#1
    lsls r8,#1         @ shift lower  part remainder
    orrcs r7,#1
    lsls r4,#1         @ shift lower part quotient
    lsl r9,#1          @ shift upper part quotient
    orrcs r9,#1
                       @ divisor sustract  upper  part remainder
    subs r7,r2
    sbcs  r6,#0        @ and substract carry
    bmi 2f             @ négative ?

                       @ positive or equal
    orr r4,#1          @ 1 -> right bit quotient
    b 3f
2:                     @ negative
    orr r4,#0          @ 0 -> right bit quotient
    adds r7,r2         @ and restaur remainder
    adc  r6,#0
3:
    subs r5,#1         @ decrement bit size
    bgt 1b             @ end ?
    mov r0,r4          @ lower part quotient
    mov r1,r9          @ upper part quotient
    mov r2,r7          @ remainder
100:                   @ function end
    pop {r3-r9,lr}     @ restaur registers
    bx lr

/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <vector>

#include <boost/multiprecision/cpp_int.hpp>

using boost::multiprecision::uint128_t;

template <typename T> void unique_sort(std::vector<T>& vector) {
    std::sort(vector.begin(), vector.end());
    vector.erase(std::unique(vector.begin(), vector.end()), vector.end());
}

auto perfect_powers(uint128_t n) {
    std::vector<uint128_t> result;
    for (uint128_t i = 2, s = sqrt(n); i <= s; ++i)
        for (uint128_t p = i * i; p < n; p *= i)
            result.push_back(p);
    unique_sort(result);
    return result;
}

auto achilles(uint128_t from, uint128_t to, const std::vector<uint128_t>& pps) {
    std::vector<uint128_t> result;
    auto c = static_cast<uint128_t>(std::cbrt(static_cast<double>(to / 4)));
    auto s = sqrt(to / 8);
    for (uint128_t b = 2; b <= c; ++b) {
        uint128_t b3 = b * b * b;
        for (uint128_t a = 2; a <= s; ++a) {
            uint128_t p = b3 * a * a;
            if (p >= to)
                break;
            if (p >= from && !binary_search(pps.begin(), pps.end(), p))
                result.push_back(p);
        }
    }
    unique_sort(result);
    return result;
}

uint128_t totient(uint128_t n) {
    uint128_t tot = n;
    if ((n & 1) == 0) {
        while ((n & 1) == 0)
            n >>= 1;
        tot -= tot >> 1;
    }
    for (uint128_t p = 3; p * p <= n; p += 2) {
        if (n % p == 0) {
            while (n % p == 0)
                n /= p;
            tot -= tot / p;
        }
    }
    if (n > 1)
        tot -= tot / n;
    return tot;
}

int main() {
    auto start = std::chrono::high_resolution_clock::now();

    const uint128_t limit = 1000000000000000;

    auto pps = perfect_powers(limit);
    auto ach = achilles(1, 1000000, pps);

    std::cout << "First 50 Achilles numbers:\n";
    for (size_t i = 0; i < 50 && i < ach.size(); ++i)
        std::cout << std::setw(4) << ach[i] << ((i + 1) % 10 == 0 ? '\n' : ' ');

    std::cout << "\nFirst 50 strong Achilles numbers:\n";
    for (size_t i = 0, count = 0; count < 50 && i < ach.size(); ++i)
        if (binary_search(ach.begin(), ach.end(), totient(ach[i])))
            std::cout << std::setw(6) << ach[i]
                      << (++count % 10 == 0 ? '\n' : ' ');

    int digits = 2;
    std::cout << "\nNumber of Achilles numbers with:\n";
    for (uint128_t from = 1, to = 100; to <= limit; to *= 10, ++digits) {
        size_t count = achilles(from, to, pps).size();
        std::cout << std::setw(2) << digits << " digits: " << count << '\n';
        from = to;
    }

    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> duration(end - start);
    std::cout << "\nElapsed time: " << duration.count() << " seconds\n";
}


Function GCD(n As Uinteger, d As Uinteger) As Uinteger
    Return Iif(d = 0, n, GCD(d, n Mod d))
End Function

Function Totient(n As Integer) As Integer
    Dim As Integer m, tot = 0
    For m = 1 To n
        If GCD(m, n) = 1 Then tot += 1
    Next m
    Return tot
End Function

Function isPowerful(m As Integer) As Boolean
    Dim As Integer n = m, f = 2, q, l = Sqr(m)

    If m <= 1 Then Return false
    Do
        q = n/f
        If (n Mod f) = 0 Then
            If (m Mod(f*f)) Then Return false
            n = q
            If f > n Then Exit Do
        Else
            f += 1
            If f > l Then
                If (m Mod (n*n)) Then Return false
                Exit Do
            End If
        End If
    Loop
    Return true
End Function

Function isAchilles(n As Integer) As Boolean
    If Not isPowerful(n) Then Return false
    Dim As Integer m = 2, a = m*m
    Do
        Do
            If a = n Then Return false
            If a > n Then Exit Do
            a *= m
        Loop
        m += 1
        a = m*m
    Loop Until a > n
    Return true
End Function

Dim As Integer num, n, i
Dim As Single inicio
Dim As Double t0 = Timer

Print "First 50 Achilles numbers:"
num = 0
n = 1
Do
    If isAchilles(n) Then
        Print Using "#####"; n;
        num += 1
        If num >= 50 Then Exit Do
        If (num Mod 10) Then Print Space(3); Else Print
    End If
    n += 1
Loop

Print !"\n\nFirst 20 strong Achilles numbers:"
num = 0
n = 1
Do
    If isAchilles(n) And isAchilles(Totient(n)) Then
        Print Using "#####"; n;
        num += 1
        If num >= 20 Then Exit Do
        If (num Mod 10) Then Print Space(3); Else Print
    End If
    n += 1
Loop

Print !"\n\nNumber of Achilles numbers with:"
For i = 2 To 6
    inicio = Fix(10.0 ^ (i-1))
    num = 0
    For n = inicio To inicio*10-1
        If isAchilles(n) Then num += 1
    Next n
    Print i; " digits:"; num
Next i
Sleep


package main

import (
    "fmt"
    "math"
    "sort"
)

func totient(n int) int {
    tot := n
    i := 2
    for i*i <= n {
        if n%i == 0 {
            for n%i == 0 {
                n /= i
            }
            tot -= tot / i
        }
        if i == 2 {
            i = 1
        }
        i += 2
    }
    if n > 1 {
        tot -= tot / n
    }
    return tot
}

var pps = make(map[int]bool)

func getPerfectPowers(maxExp int) {
    upper := math.Pow(10, float64(maxExp))
    for i := 2; i <= int(math.Sqrt(upper)); i++ {
        fi := float64(i)
        p := fi
        for {
            p *= fi
            if p >= upper {
                break
            }
            pps[int(p)] = true
        }
    }
}

func getAchilles(minExp, maxExp int) map[int]bool {
    lower := math.Pow(10, float64(minExp))
    upper := math.Pow(10, float64(maxExp))
    achilles := make(map[int]bool)
    for b := 1; b <= int(math.Cbrt(upper)); b++ {
        b3 := b * b * b
        for a := 1; a <= int(math.Sqrt(upper)); a++ {
            p := b3 * a * a
            if p >= int(upper) {
                break
            }
            if p >= int(lower) {
                if _, ok := pps[p]; !ok {
                    achilles[p] = true
                }
            }
        }
    }
    return achilles
}

func main() {
    maxDigits := 15
    getPerfectPowers(maxDigits)
    achillesSet := getAchilles(1, 5) // enough for first 2 parts
    achilles := make([]int, len(achillesSet))
    i := 0
    for k := range achillesSet {
        achilles[i] = k
        i++
    }
    sort.Ints(achilles)

    fmt.Println("First 50 Achilles numbers:")
    for i = 0; i < 50; i++ {
        fmt.Printf("%4d ", achilles[i])
        if (i+1)%10 == 0 {
            fmt.Println()
        }
    }

    fmt.Println("\nFirst 30 strong Achilles numbers:")
    var strongAchilles []int
    count := 0
    for n := 0; count < 30; n++ {
        tot := totient(achilles[n])
        if _, ok := achillesSet[tot]; ok {
            strongAchilles = append(strongAchilles, achilles[n])
            count++
        }
    }
    for i = 0; i < 30; i++ {
        fmt.Printf("%5d ", strongAchilles[i])
        if (i+1)%10 == 0 {
            fmt.Println()
        }
    }

    fmt.Println("\nNumber of Achilles numbers with:")
    for d := 2; d <= maxDigits; d++ {
        ac := len(getAchilles(d-1, d))
        fmt.Printf("%2d digits: %d\n", d, ac)
    }
}


using Primes

isAchilles(n) = (p = [x[2] for x in factor(n).pe]; all(>(1), p) && gcd(p) == 1)

isstrongAchilles(n) = isAchilles(n) && isAchilles(totient(n))

function teststrongachilles(nachilles = 50, nstrongachilles = 100)
    # task 1
    println("First $nachilles Achilles numbers:")
    n, found = 0, 0
    while found < nachilles
        if isAchilles(n)
            found += 1
            print(rpad(n, 5), found % 10 == 0 ? "\n" : "")
        end
        n += 1
    end
    # task 2
    println("\nFirst $nstrongachilles strong Achilles numbers:")
    n, found = 0, 0
    while found < nstrongachilles
        if isstrongAchilles(n)
            found += 1
            print(rpad(n, 7), found % 10 == 0 ? "\n" : "")
        end
        n += 1
    end
    # task 3
    println("\nCount of Achilles numbers for various intervals:")
    intervals = [10:99, 100:999, 1000:9999, 10000:99999, 100000:999999]
    for interval in intervals
        println(lpad(interval, 15), " ", count(isAchilles, interval))
    end
end

teststrongachilles()


ClearAll[PowerfulNumberQ, StrongAchillesNumberQ]
PowerfulNumberQ[n_Integer] := AllTrue[FactorInteger[n][[All, 2]], GreaterEqualThan[2]]
AchillesNumberQ[n_Integer] := Module[{divs},
  If[PowerfulNumberQ[n],
   divs = Divisors[n];
   If[Length[divs] > 2,
    divs = divs[[2 ;; -2]];
    !AnyTrue[Log[#, n] & /@ divs, IntegerQ]
    ,
    True
    ]
   ,
   False
   ]
  ]
StrongAchillesNumberQ[n_] := AchillesNumberQ[n] \[And] AchillesNumberQ[EulerPhi[n]]

n = 0;
i = 0;
Reap[While[n < 50,
   i++;
   If[AchillesNumberQ[i], n++; Sow[i]]
   ]][[2, 1]]

n = 0;
i = 0;
Reap[While[n < 20,
   i++;
   If[StrongAchillesNumberQ[i], n++; Sow[i]]
   ]][[2, 1]]

Tally[IntegerLength /@ Select[Range[9999999], AchillesNumberQ]] // Grid


use strict;
use warnings;
use feature <say current_sub>;
use experimental 'signatures';
use List::AllUtils <max head uniqint>;
use ntheory <is_square_free is_power euler_phi>;
use Math::AnyNum <:overload idiv iroot ipow is_coprime>;

sub table { my $t = shift() * (my $c = 1 + length max @_); ( sprintf( ('%'.$c.'d')x@_, @_) ) =~ s/.{1,$t}\K/\n/gr }

sub powerful_numbers ($n, $k = 2) {
    my @powerful;
    sub ($m, $r) {
        $r < $k and push @powerful, $m and return;
        for my $v (1 .. iroot(idiv($n, $m), $r)) {
            if ($r > $k) { next unless is_square_free($v) and is_coprime($m, $v) }
            __SUB__->($m * ipow($v, $r), $r - 1);
        }
    }->(1, 2*$k - 1);
    sort { $a <=> $b } @powerful;
}

my(@P, @achilles, %Ahash, @strong);
@P = uniqint @P, powerful_numbers(10**9, $_) for 2..9; shift @P;
!is_power($_) and push @achilles, $_ and $Ahash{$_}++ for @P;
$Ahash{euler_phi $_} and push @strong, $_ for @achilles;

say "First 50 Achilles numbers:\n"        . table 10, head 50, @achilles;
say "First 30 strong Achilles numbers:\n" . table 10, head 30, @strong;
say "Number of Achilles numbers with:\n";
for my $l (2..9) {
    my $c; $l == length and $c++ for @achilles;
    say "$l digits: $c";
}


with javascript_semantics
requires("1.0.2") -- [join_by(fmt)]
atom t0 = time()
constant maxDigits = iff(platform()=JS?10:12)
integer pps = new_dict()

procedure getPerfectPowers(integer maxExp)
    atom hi = power(10, maxExp)
    integer imax = floor(sqrt(hi))
    for i=2 to imax do
        atom p = i
        while true do
            p *= i
            if p>=hi then exit end if
            setd(p,true,pps)
        end while
    end for
end procedure

function get_achilles(integer minExp, maxExp)
    atom lo10 = power(10,minExp),
         hi10 = power(10,maxExp)
    integer bmax = floor(power(hi10,1/3)),
            amax = floor(sqrt(hi10))
    sequence achilles = {}
    for b=2 to bmax do
        atom b3 = b * b * b
        for a=2 to amax do
            atom p = b3 * a * a
            if p>=hi10 then exit end if
            if p>=lo10 then
                integer node = getd_index(p,pps)
                if node=NULL then
                    achilles &= p
                end if
            end if
        end for
    end for
    achilles = unique(achilles)
    return achilles
end function

getPerfectPowers(maxDigits)
sequence achilles = get_achilles(1,5)

function strong_achilles(integer n)
    integer totient = sum(sq_eq(apply(true,gcd,{tagset(n),n}),1))
    return find(totient,achilles)
end function

sequence a = join_by(achilles[1..50],1,10," ",fmt:="%4d"),
         sa = filter(achilles,strong_achilles)[1..30],
         ssa = join_by(sa,1,10," ",fmt:="%5d")

printf(1,"First 50 Achilles numbers:\n%s\n",{a})
printf(1,"First 30 strong Achilles numbers:\n%s\n",{ssa})
for d=2 to maxDigits do
    printf(1,"Achilles numbers with %d digits:%d\n",{d,length(get_achilles(d-1,d))})
end for
?elapsed(time()-t0)


use Prime::Factor;
use Math::Root;

sub is-square-free (Int \n) {
    constant @p = ^100 .map: { next unless .is-prime; .² };
    for @p -> \p { return False if n %% p }
    True
}

sub powerful (\n, \k = 2) {
    my @p;
    p(1, 2*k - 1);
    sub p (\m, \r) {
        @p.push(m) and return if r < k;
        for 1 .. (n / m).&root(r) -> \v {
            if r > k {
                next unless is-square-free(v);
                next unless m gcd v == 1;
            }
            p(m * v ** r, r - 1)
        }
    }
    @p
}

my $achilles = powerful(10**9).hyper(:500batch).grep( {
    my $f = .&prime-factors.Bag;
    (+$f.keys > 1) && (1 == [gcd] $f.values) && (.sqrt.Int² !== $_)
} ).classify: { .chars }

my \𝜑 = 0, |(1..*).hyper.map: -> \t { t × [×] t.&prime-factors.squish.map: { 1 - 1/$_ } }

my %as = Set.new: flat $achilles.values».list;

my $strong = lazy (flat $achilles.sort».value».list».sort).grep: { ?%as{𝜑[$_]} };

put "First 50 Achilles numbers:";
put (flat $achilles.sort».value».list».sort)[^50].batch(10)».fmt("%4d").join("\n");

put "\nFirst 30 strong Achilles numbers:";
put   $strong[^30].batch(10)».fmt("%5d").join("\n");

put "\nNumber of Achilles numbers with:";
say "$_ digits: " ~ +$achilles{$_} // 0 for 2..9;

printf "\n%.1f total elapsed seconds\n", now - INIT now;


fn perfect_powers(n: u128) -> Vec<u128> {
    let mut powers = Vec::<u128>::new();
    let sqrt = (n as f64).sqrt() as u128;
    for i in 2..=sqrt {
        let mut p = i * i;
        while p < n {
            powers.push(p);
            p *= i;
        }
    }
    powers.sort();
    powers.dedup();
    powers
}

fn bsearch<T: Ord>(vector: &Vec<T>, value: &T) -> bool {
    match vector.binary_search(value) {
        Ok(_) => true,
        _ => false,
    }
}

fn achilles(from: u128, to: u128, pps: &Vec<u128>) -> Vec<u128> {
    let mut result = Vec::<u128>::new();
    let cbrt = ((to / 4) as f64).cbrt() as u128;
    let sqrt = ((to / 8) as f64).sqrt() as u128;
    for b in 2..=cbrt {
        let b3 = b * b * b;
        for a in 2..=sqrt {
            let p = b3 * a * a;
            if p >= to {
                break;
            }
            if p >= from && !bsearch(&pps, &p) {
                result.push(p);
            }
        }
    }
    result.sort();
    result.dedup();
    result
}

fn totient(mut n: u128) -> u128 {
    let mut tot = n;
    if (n & 1) == 0 {
        while (n & 1) == 0 {
            n >>= 1;
        }
        tot -= tot >> 1;
    }
    let mut p = 3;
    while p * p <= n {
        if n % p == 0 {
            while n % p == 0 {
                n /= p;
            }
            tot -= tot / p;
        }
        p += 2;
    }
    if n > 1 {
        tot -= tot / n;
    }
    tot
}

fn main() {
    use std::time::Instant;
    let t0 = Instant::now();
    let limit = 1000000000000000u128;

    let pps = perfect_powers(limit);
    let ach = achilles(1, 1000000, &pps);

    println!("First 50 Achilles numbers:");
    for i in 0..50 {
        print!("{:4}{}", ach[i], if (i + 1) % 10 == 0 { "\n" } else { " " });
    }

    println!("\nFirst 50 strong Achilles numbers:");
    for (i, n) in ach
        .iter()
        .filter(|&x| bsearch(&ach, &totient(*x)))
        .take(50)
        .enumerate()
    {
        print!("{:6}{}", n, if (i + 1) % 10 == 0 { "\n" } else { " " });
    }
    println!();

    let mut from = 1u128;
    let mut to = 100u128;
    let mut digits = 2;
    while to <= limit {
        let count = achilles(from, to, &pps).len();
        println!("{:2} digits: {}", digits, count);
        from = to;
        to *= 10;
        digits += 1;
    }

    let duration = t0.elapsed();
    println!("\nElapsed time: {} milliseconds", duration.as_millis());
}


import "./math" for Int
import "./seq" for Lst
import "./fmt" for Fmt

var maxDigits = 8
var limit = 10.pow(maxDigits)
var c = Int.primeSieve(limit-1, false)

var totient = Fn.new { |n|
    var tot = n
    var i = 2
    while (i*i <= n) {
        if (n%i == 0) {
            while(n%i == 0) n = (n/i).floor
            tot = tot - (tot/i).floor
        }
        if (i == 2) i = 1
        i = i + 2
    }
    if (n > 1) tot = tot - (tot/n).floor
    return tot
}

var isPerfectPower = Fn.new { |n|
    if (n == 1) return true
    var x = 2
    while (x * x <= n) {
        var y = 2
        var p = x.pow(y)
        while (p > 0 && p <= n) {
            if (p == n) return true
            y = y + 1
            p = x.pow(y)
        }
        x = x + 1
    }
    return false
}

var isPowerful = Fn.new { |n|
    while (n % 2 == 0) {
        var p = 0
        while (n % 2 == 0) {
            n = (n/2).floor
            p = p + 1
        }
        if (p == 1) return false
    }
    var f = 3
    while (f * f <= n) {
        var p = 0
        while (n % f == 0) {
            n = (n/f).floor
            p = p + 1
        }
        if (p == 1) return false
        f = f + 2
    }
    return n == 1
}

var isAchilles = Fn.new { |n| c[n] && isPowerful.call(n) && !isPerfectPower.call(n) }

var isStrongAchilles = Fn.new { |n|
    if (!isAchilles.call(n)) return false
    var tot = totient.call(n)
    return isAchilles.call(tot)
}

System.print("First 50 Achilles numbers:")
var achilles = []
var count = 0
var n = 2
while (count < 50) {
    if (isAchilles.call(n)) {
        achilles.add(n)
        count = count + 1
    }
    n = n + 1
}
for (chunk in Lst.chunks(achilles, 10)) Fmt.print("$4d", chunk)

System.print("\nFirst 30 strong Achilles numbers:")
var strongAchilles = []
count = 0
n = achilles[0]
while (count < 30) {
    if (isStrongAchilles.call(n)) {
        strongAchilles.add(n)
        count = count + 1
    }
    n = n + 1
}
for (chunk in Lst.chunks(strongAchilles, 10)) Fmt.print("$5d", chunk)

System.print("\nNumber of Achilles numbers with:")
var pow = 10
for (i in 2..maxDigits) {
    var count = 0
    for (j in pow..pow*10-1) {
        if (isAchilles.call(j)) count = count + 1
    }
    System.print("%(i) digits: %(count)")
    pow = pow * 10
}


func GCD(N, D);         \Return the greatest common divisor of N and D
int  N, D;              \numerator and denominator
int  R;
[if D > N then
    [R:= D;  D:= N;  N:= R];    \swap D and N
while D > 0 do
    [R:= rem(N/D);
    N:= D;
    D:= R;
    ];
return N;
];      \GCD

func Totient(N);        \Return the totient of N
int  N, Phi, M;
[Phi:= 0;
for M:= 1 to N do
    if GCD(M, N) = 1 then Phi:= Phi+1;
return Phi;
];

func Powerful(N0);      \Return 'true' if N0 is a powerful number
int  N0, N, F, Q, L;
[if N0 <= 1 then return false;
N:= N0;  F:= 2;
L:= sqrt(N0);
loop    [Q:= N/F;
        if rem(0) = 0 then      \found a factor
                [if rem(N0/(F*F)) then return false;
                N:= Q;
                if F>N then quit;
                ]
        else    [F:= F+1;
                if F > L then
                    [if rem(N0/(N*N)) then return false;
                    quit;
                    ];
                ];
        ];
return true;
];

func Achilles(N);       \Return 'true' if N is an Achilles number
int  N, M, A;
[if not Powerful(N) then return false;
M:= 2;
A:= M*M;
repeat  loop    [if A = N then return false;
                if A > N then quit;
                A:= A*M;
                ];
        M:= M+1;
        A:= M*M;
until   A > N;
return true;
];

int Cnt, N, Pwr, Start;
[Cnt:= 0;
N:= 1;
loop    [if Achilles(N) then
            [IntOut(0, N);
            Cnt:= Cnt+1;
            if Cnt >= 50 then quit;
            if rem(Cnt/10) then ChOut(0, 9) else CrLf(0);
            ];
        N:= N+1;
        ];
CrLf(0);  CrLf(0);
Cnt:= 0;
N:= 1;
loop    [if Achilles(N) then
            if Achilles(Totient(N)) then
                [IntOut(0, N);
                Cnt:= Cnt+1;
                if Cnt >= 20 then quit;
                if rem(Cnt/10) then ChOut(0, 9) else CrLf(0);
                ];
        N:= N+1;
        ];
CrLf(0);  CrLf(0);
for Pwr:= 1 to 6 do
    [IntOut(0, Pwr);  Text(0, ": ");
    Start:= fix(Pow(10.0, float(Pwr-1)));
    Cnt:= 0;
    for N:= Start to Start*10-1 do
        if Achilles(N) then Cnt:= Cnt+1;
    IntOut(0, Cnt);  CrLf(0);
    ];
]


F expand_x_1(p)
   V ex = [BigInt(1)]
   L(i) 0 .< p
      ex.append(ex.last * -(p - i) I/ (i + 1))
   R reversed(ex)

F aks_test(p)
   I p < 2
      R 0B
   V ex = expand_x_1(p)
   ex[0]++
   R !any(ex[0 .< (len)-1].map(mult -> mult % @p != 0))

print(‘# p: (x-1)^p for small p’)
L(p) 12
   print(‘#3: #.’.format(p, enumerate(expand_x_1(p)).map((n, e) -> ‘#.#.#.’.format(‘+’ * (e >= 0), e, I n {(‘x^#.’.format(n))} E ‘’)).join(‘ ’)))

print("\n# small primes using the aks test")
print((0..100).filter(p -> aks_test(p)))


with: a

: nextrow  \ a -- a
    len
    [ ( drop [1] ),
      ( drop [1,1] ),
      ( ' n:+ y 1 slide 1 push ) ]
    swap 2 min caseof ;

;with

with: n

: .x   \ n --
    dup
    [ ( drop ),
      ( drop "x" . ),
      ( "x^" . . ) ]
    swap 2 min caseof space ;

: .term  \ coef exp -- ; omit coef for 1x^n when n > 0
    over 1 = over 0 > and if  nip .x  else  swap . .x  then ;

: .sgn  \ +/-1 --
    [ "-", null, "+" ]
    swap 1+ caseof . space ;

: .lhs  \ n --
    "(x-1)^" . . ;

: .rhs  \ a -- a
    a:len 1- >r
    1 swap ( third .sgn [email protected] rot - .term -1 * ) a:each
    nip rdrop ;

: .eqn  \ a -- a
    a:len 1- .lhs " = " . .rhs ;

: .binomials  \ --
    [] ( nextrow .eqn cr ) 8 times drop ;

: primerow? \ a -- a ?
    a:len 3 < if false ;then
    1 a:@ >r   \ 2nd position is the number to check for primality
    true swap ( nip dup 1 = swap [email protected] mod 0 = or and ) a:each swap
    rdrop ;

: .primes-via-aks \ --
    [] ( nextrow primerow? if 1 a:@ . space then ) 50 times drop ;

;with

.binomials cr
"The primes upto 50 are (via AKS): " . .primes-via-aks cr

bye


/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/*  program AKS64.s   */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ MAXI,       64
.equ NUMBERLOOP, 10

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessResult:        .asciz " (x-1)^@ = "
szMessResult1:       .asciz " @ x^@   "
szMessResPrime:      .asciz "Number @ is prime. \n"
szCarriageReturn:    .asciz "\n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
qTabCoef:         .skip 8 * MAXI
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                               // entry of program

    mov x4,#1
1:                                  // loop
    mov x0,x4
    bl computeCoef                  // compute coefficient
    ldr x0,qAdrqTabCoef
    mov x0,x4
    bl displayCoef                  // display coefficient
    add x4,x4,1
    cmp x4,NUMBERLOOP
    blt 1b

    mov x4,1
2:
    mov x0,x4
    bl isPrime                      // is prime ?
    cmp x0,1
    bne 3f
    mov x0,x4
    ldr x1,qAdrsZoneConv
    bl conversion10                  // call decimal conversion
    add x1,x1,x0
    strb wzr,[x1]
    ldr x0,qAdrszMessResPrime
    ldr x1,qAdrsZoneConv             // insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess

3:
    add x4,x4,1
    cmp x4,MAXI
    blt 2b

100:                                 // standard end of the program
    mov x0,0                         // return code
    mov x8,EXIT                      // request to exit program
    svc 0                            // perform the system call

qAdrszCarriageReturn:     .quad szCarriageReturn
qAdrsZoneConv:            .quad sZoneConv
qAdrqTabCoef:             .quad qTabCoef
qAdrszMessResPrime:       .quad szMessResPrime
/***************************************************/
/*     display coefficients                        */
/***************************************************/
// x0 contains a number
displayCoef:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    stp x6,x7,[sp,-16]!         // save  registres
    mov x2,x0
    ldr x1,qAdrsZoneConv        //
    bl conversion10             // call decimal conversion
    add x1,x1,x0
    strb wzr,[x1]
    ldr x0,qAdrszMessResult
    ldr x1,qAdrsZoneConv        // insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    ldr x3,qAdrqTabCoef
1:
    ldr x0,[x3,x2,lsl #3]
    ldr x1,qAdrsZoneConv        //
    bl conversion10S            // call decimal conversion
2:                              // removing spaces
    ldrb w6,[x1]
    cmp x6,' '
    cinc x1,x1,eq
    beq 2b

    ldr x0,qAdrszMessResult1
    bl strInsertAtCharInc
    mov x4,x0
    mov x0,x2
    ldr x1,qAdrsZoneConv        // else display odd message
    bl conversion10             // call decimal conversion
    add x1,x1,x0
    strb wzr,[x1]
    mov x0,x4
    ldr x1,qAdrsZoneConv        // insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    subs x2,x2,#1
    bge 1b

    ldr x0,qAdrszCarriageReturn
    bl affichageMess
100:
    ldp x6,x7,[sp],16         // restaur des  2 registres
    ldp x4,x5,[sp],16         // restaur des  2 registres
    ldp x2,x3,[sp],16         // restaur des  2 registres
    ldp x1,lr,[sp],16         // restaur des  2 registres
    ret
qAdrszMessResult:    .quad szMessResult
qAdrszMessResult1:   .quad szMessResult1
/***************************************************/
/*     compute coefficient               */
/***************************************************/
// x0 contains a number
computeCoef:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    stp x6,x7,[sp,-16]!         // save  registres
    ldr x1,qAdrqTabCoef         // address coefficient array
    mov x2,1
    str x2,[x1]                 // store 1 to coeff [0]
    mov x3,0                    // indice 1
1:
    add x4,x3,1
    mov x5,1
    str x5,[x1,x4,lsl #3]
    mov x6,x3                   // indice 2 = indice 1
2:
    cmp x6,0                    // zero ? -> end loop
    ble 3f
    sub x4,x6,1
    ldr x5,[x1,x4,lsl 3]
    ldr x4,[x1,x6,lsl 3]
    sub x5,x5,x4
    str x5,[x1,x6,lsl 3]
    sub x6,x6,1
    b 2b
3:
    ldr x2,[x1]                 // inversion coeff [0]
    neg x2,x2
    str x2,[x1]
    add x3,x3,1
    cmp x3,x0
    blt 1b

100:
    ldp x6,x7,[sp],16         // restaur des  2 registres
    ldp x4,x5,[sp],16         // restaur des  2 registres
    ldp x2,x3,[sp],16         // restaur des  2 registres
    ldp x1,lr,[sp],16         // restaur des  2 registres
    ret
/***************************************************/
/*     verify number is prime              */
/***************************************************/
// x0 contains a number
isPrime:
    stp x1,lr,[sp,-16]!         // save  registres
    stp x2,x3,[sp,-16]!         // save  registres
    stp x4,x5,[sp,-16]!         // save  registres
    bl computeCoef
    ldr x4,qAdrqTabCoef         // address coefficient array
    ldr x2,[x4]
    add x2,x2,1
    str x2,[x4]
    ldr x2,[x4,x0,lsl 3]
    sub x2,x2,#1
    str x2,[x4,x0,lsl 3]
    mov x5,x0                  // number start
1:
    ldr x1,[x4,x5,lsl 3]       // load one coeff
    sdiv x2,x1,x0
    msub x3,x2,x0,x1           // compute remainder
    cmp x3,#0                  // remainder = zéro ?
    bne 99f                    // if <> no prime
    subs x5,x5,#1              // next coef
    bgt 1b                     // and loop
    mov x0,#1                  // prime
    b 100f
99:
    mov x0,0                   // no prime
100:
    ldp x4,x5,[sp],16         // restaur des  2 registres
    ldp x2,x3,[sp],16         // restaur des  2 registres
    ldp x1,lr,[sp],16         // restaur des  2 registres
    ret
/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"


with Ada.Text_IO;

procedure Test_For_Primes is

   type Pascal_Triangle_Type is array (Natural range <>) of Long_Long_Integer;

   function Calculate_Pascal_Triangle (N : in Natural) return Pascal_Triangle_Type is
      Pascal_Triangle : Pascal_Triangle_Type (0 .. N);
   begin
      Pascal_Triangle (0) := 1;
      for I in Pascal_Triangle'First .. Pascal_Triangle'Last - 1 loop
         Pascal_Triangle (1 + I) := 1;
         for J in reverse 1 .. I loop
            Pascal_Triangle (J) := Pascal_Triangle (J - 1) - Pascal_Triangle (J);
         end loop;
         Pascal_Triangle (0) := -Pascal_Triangle (0);
      end loop;
      return Pascal_Triangle;
   end Calculate_Pascal_Triangle;

   function Is_Prime (N : Integer) return Boolean is
      I      : Integer;
      Result : Boolean := True;
      Pascal_Triangle : constant Pascal_Triangle_Type := Calculate_Pascal_Triangle (N);
   begin
      I := N / 2;
      while Result and I > 1 loop
         Result := Result and Pascal_Triangle (I) mod Long_Long_Integer (N) = 0;
         I := I - 1;
      end loop;
      return Result;
   end Is_Prime;

   function Image (N    : in Long_Long_Integer;
                   Sign : in Boolean := False) return String is
      Image : constant String := N'Image;
   begin
      if N < 0 then
         return Image;
      else
         if Sign then
            return "+" & Image (Image'First + 1 .. Image'Last);
         else
            return Image (Image'First + 1 .. Image'Last);
         end if;
      end if;
   end Image;

   procedure Show (Triangle : in Pascal_Triangle_Type) is
      use Ada.Text_IO;
   Begin
      for I in reverse Triangle'Range loop
         Put (Image (Triangle (I), Sign => True));
         Put ("x^");
         Put (Image (Long_Long_Integer (I)));
         Put (" ");
      end loop;
   end Show;

   procedure Show_Pascal_Triangles is
      use Ada.Text_IO;
   begin
      for N in 0 .. 9 loop
         declare
            Pascal_Triangle : constant Pascal_Triangle_Type := Calculate_Pascal_Triangle (N);
         begin
            Put ("(x-1)^" & Image (Long_Long_Integer (N)) & " = ");
            Show (Pascal_Triangle);
            New_Line;
         end;
      end loop;
   end Show_Pascal_Triangles;

   procedure Show_Primes is
      use Ada.Text_IO;
   begin
      for N in 2 .. 63 loop
         if Is_Prime (N) then
            Put (N'Image);
         end if;
      end loop;
      New_Line;
   end Show_Primes;

begin
   Show_Pascal_Triangles;
   Show_Primes;
end Test_For_Primes;


BEGIN
COMMENT
   Mathematical preliminaries.

   First note that the homogeneous polynomial (a+b)^n is symmetrical
   (to see this just swap the variables a and b).  Therefore its
   coefficients need be calculated only to that of (ab)^{n/2} for even
   n or (ab)^{(n-1)/2} for odd n.

   Second, the coefficients are the binomial coefficients C(n,k) where
   the coefficient of a^k b^(n-k) is C(n,k) = n! / k!  (k-1)!.  This
   leads to an immediate and relatively efficient implementation for
   which we do not need to compute n! before dividing by k! and (k-1)!
   but, rather cancel common factors as we go along.  Further, the
   well-known symmetry identity C(n,k) = C(n, n-k) allows a
   significant reduction in computational effort.

   Third, (x-1)^n is the value of (a + b)^n when a=x and b = -1.  The
   powers of -1 alternate between +1 and -1 so we may as well compute
   (x+1)^n and negate every other coefficient when printing.
COMMENT
   PR precision=300 PR
   MODE LLI = LONG LONG INT;	CO For brevity CO
   PROC choose = (INT n, k) LLI :
   BEGIN
      LLI result := 1;
      INT sym k := (k >= n%2 | n-k | k);	CO Use symmetry CO
      IF sym k > 0 THEN
	 FOR i FROM 0 TO sym k-1
	 DO
	    result TIMESAB (n-i);
	    result OVERAB (i+1)
	 OD
      FI;
      result
   END;
   PROC coefficients = (INT n) [] LLI :
   BEGIN
      [0:n] LLI a;
      FOR i FROM 0 TO n%2
      DO
	 a[i] := a[n-i] := choose (n, i)		CO Use symmetry CO
      OD;
      a
   END;
COMMENT
   First print the polynomials (x-1)^n, remembering to alternate signs
   and to tidy up the constant term, the x^1 term and the x^n term.
   This means we must treat (x-1)^0 and (x-1)^1 specially
COMMENT
   FOR n FROM 0 TO 7
   DO
      [0:n] LLI a := coefficients (n);
      printf (($"(x-1)^", g(0), " = "$, n));
      CASE n+1 IN
         printf (($g(0)l$, a[0])),
         printf (($"x - ", g(0)l$, a[1]))
      OUT
         printf (($"x^", g(0)$, n));
         FOR i TO n-2
         DO
	    printf (($xax, g(0), "x^", g(0)$, (ODD i | "-" | "+"), a[i], n-i))
         OD;
         printf (($xax, g(0), "x"$, (ODD (n-1) | "-" | "+"), a[n-1]));
         printf (($xaxg(0)l$, (ODD n | "-" | "+"), a[n]))
      ESAC
OD;
COMMENT
   Finally, for the "AKS" portion of the task, the sign of the
   coefficient has no effect on its divisibility by p so, once again,
   we may as well use the positive coefficients.  Symmetry clearly
   reduces the necessary number of tests by a factor of two.
COMMENT
   PROC is prime = (INT n) BOOL :
   BEGIN
      BOOL prime := TRUE;
      FOR i FROM 1 TO n%2 WHILE prime DO prime := choose (n, i) MOD n = 0 OD;
      prime
   END;
   print ("Primes < 50 are ");
   FOR n FROM 2 TO 50 DO (is prime (n) | printf (($g(0)x$, n)) ) OD;
   print (newline);
   print ("And just to show off, the primes between 900 and 1000 are ");
   FOR n FROM 900 TO 1000 DO IF is prime (n) THEN printf (($g(0)x$, n)) FI OD;
   print (newline)
END


/* ARM assembly Raspberry PI  or android 32 bits */
/*  program AKS.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 */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"
.equ MAXI,       32
.equ NUMBERLOOP, 10

/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessResult:        .asciz " (x-1)^@ = "
szMessResult1:       .asciz " @ x^@   "
szMessResPrime:      .asciz "Number @ is prime. \n"
szCarriageReturn:    .asciz "\n"

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
sZoneConv:        .skip 24
iTabCoef:         .skip 4 * MAXI
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                               @ entry of program

    mov r4,#1
1:                                  @ loop
    mov r0,r4
    bl computeCoef                  @ compute coefficient
    ldr r0,iAdriTabCoef
    mov r0,r4
    bl displayCoef                  @ display coefficient
    add r4,r4,#1
    cmp r4,#NUMBERLOOP
    blt 1b

    mov r4,#1
2:
    mov r0,r4
    bl isPrime                      @ is prime ?
    cmp r0,#1
    bne 3f
    mov r0,r4
    ldr r1,iAdrsZoneConv
    bl conversion10                  @ call decimal conversion
    add r1,r0
    mov r5,#0
    strb r5,[r1]
    ldr r0,iAdrszMessResPrime
    ldr r1,iAdrsZoneConv             @ insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess

3:
    add r4,r4,#1
    cmp r4,#MAXI
    blt 2b

100:                                  @ standard end of the program
    mov r0, #0                        @ return code
    mov r7, #EXIT                     @ request to exit program
    svc #0                            @ perform the system call

iAdrszCarriageReturn:     .int szCarriageReturn
iAdrsZoneConv:            .int sZoneConv
iAdriTabCoef:             .int iTabCoef
iAdrszMessResPrime:       .int szMessResPrime
/***************************************************/
/*     display coefficients                        */
/***************************************************/
// r0 contains a number
displayCoef:
    push {r1-r6,lr}             @ save  registers
    mov r2,r0
    ldr r1,iAdrsZoneConv        @
    bl conversion10             @ call decimal conversion
    add r1,r0
    mov r5,#0
    strb r5,[r1]
    ldr r0,iAdrszMessResult
    ldr r1,iAdrsZoneConv        @ insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    ldr r3,iAdriTabCoef
1:
    ldr r0,[r3,r2,lsl #2]
    ldr r1,iAdrsZoneConv        @
    bl conversion10S            @ call decimal conversion
2:                              @ removing spaces
    ldrb r6,[r1]
    cmp r6,#' '
    addeq r1,#1
    beq 2b

    ldr r0,iAdrszMessResult1
    bl strInsertAtCharInc
    mov r4,r0
    mov r0,r2
    ldr r1,iAdrsZoneConv        @ else display odd message
    bl conversion10             @ call decimal conversion
    add r1,r0
    mov r5,#0
    strb r5,[r1]
    mov r0,r4
    ldr r1,iAdrsZoneConv        @ insert value conversion in message
    bl strInsertAtCharInc
    bl affichageMess
    subs r2,r2,#1
    bge 1b

    ldr r0,iAdrszCarriageReturn
    bl affichageMess
100:
    pop {r1-r6,lr}             @ restaur registers
    bx lr                      @ return
iAdrszMessResult:    .int szMessResult
iAdrszMessResult1:   .int szMessResult1
/***************************************************/
/*     compute coefficient               */
/***************************************************/
// r0 contains a number
computeCoef:
    push {r1-r6,lr}             @ save  registers
    ldr r1,iAdriTabCoef         @ address coefficient array
    mov r2,#1
    str r2,[r1]                 @ store 1 to coeff [0]
    mov r3,#0                   @ indice 1
1:
    add r4,r3,#1
    mov r5,#1
    str r5,[r1,r4,lsl #2]
    mov r6,r3                   @ indice 2 = indice 1
2:
    cmp r6,#0                   @ zero ? -> end loop
    ble 3f
    sub r4,r6,#1
    ldr r5,[r1,r4,lsl #2]
    ldr r4,[r1,r6,lsl #2]
    sub r5,r5,r4
    str r5,[r1,r6,lsl #2]
    sub r6,r6,#1
    b 2b
3:
    ldr r2,[r1]                 @ inversion coeff [0]
    neg r2,r2
    str r2,[r1]
    add r3,r3,#1
    cmp r3,r0
    blt 1b

100:
    pop {r1-r6,lr}             @ restaur registers
    bx lr                      @ return
/***************************************************/
/*     verify number is prime              */
/***************************************************/
// r0 contains a number
isPrime:
    push {r1-r5,lr}             @ save  registers
    bl computeCoef
    ldr r4,iAdriTabCoef         @ address coefficient array
    ldr r2,[r4]
    add r2,r2,#1
    str r2,[r4]
    ldr r2,[r4,r0,lsl #2]
    sub r2,r2,#1
    str r2,[r4,r0,lsl #2]
    mov r5,r0                  @ number start
    mov r1,r0                  @ divisor
1:
    ldr r0,[r4,r5,lsl #2]      @ load one coeff
    cmp r0,#0                  @ if negative inversion
    neglt r0,r0
    bl division                @ because this routine is number positive only
    cmp r3,#0                  @ remainder = zéro ?
    movne r0,#0                @  if <> no prime
    bne 100f
    subs r5,r5,#1              @ next coef
    bgt 1b
    mov r0,#1                  @ prime

100:
    pop {r1-r5,lr}             @ restaur registers
    bx lr                      @ return
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


; 1. Create a function/subroutine/method that given p generates the coefficients of the expanded polynomial representation of (x-1)^p.
; Function modified from http://rosettacode.org/wiki/Pascal%27s_triangle#AutoHotkey
pascalstriangle(n=8) ; n rows of Pascal's triangle
{
	p := Object(), z:=Object()
	Loop, % n
		Loop, % row := A_Index
			col := A_Index
			, p[row, col] := row = 1 and col = 1
				? 1
				: (p[row-1, col-1] = "" ; math operations on blanks return blanks; I want to assume zero
					? 0
					: p[row-1, col-1])
				- (p[row-1, col] = ""
					? 0
					: p[row-1, col])
	Return p
}

; 2. Use the function to show here the polynomial expansions of p for p in the range 0 to at least 7, inclusive.
For k, v in pascalstriangle()
{
	s .= "`n(x-1)^" k-1 . "="
	For k, w in v
		s .= "+" w "x^" k-1
}
s := RegExReplace(s, "\+-", "-")
s := RegExReplace(s, "x\^0", "")
s := RegExReplace(s, "x\^1", "x")
Msgbox % clipboard := s

; 3. Use the previous function in creating another function that when given p returns whether p is prime using the AKS test.
aks(n)
{
	isnotprime := False
	For k, v in pascalstriangle(n+1)[n+1]
		(k != 1 and k != n+1) ? isnotprime |= !(v // n = v / n) ; if any is not divisible, returns true
	Return !isnotprime
}

; 4. Use your AKS test to generate a list of all primes under 35.
i := 49
p := pascalstriangle(i+1)
Loop, % i
{
	n := A_Index
	isnotprime := False
	For k, v in p[n+1]
		(k != 1 and k != n+1) ? isnotprime |= !(v // n = v / n) ; if any is not divisible, returns true
	t .= isnotprime ? "" : A_Index " "
}
Msgbox % t
Return


( (forceExpansion=.1+!arg+-1)
& (expandx-1P=.forceExpansion$((x+-1)^!arg))
& ( isPrime
  =
    .         forceExpansion
            $ (!arg^-1*(expandx-1P$!arg+-1*(x^!arg+-1)))
          : ?+/*?+?
        & ~`
      |
  )
& out$"Polynomial representations of (x-1)^p for p <= 7 :"
& -1:?n
&   whl
  ' ( 1+!n:~>7:?n
    & out$(str$("n=" !n ":") expandx-1P$!n)
    )
& 1:?n
& :?primes
&   whl
  ' ( 1+!n:~>50:?n
    & ( isPrime$!n&!primes !n:?primes
      |
      )
    )
& out$"2 <= Primes <= 50:"
& out$!primes
);


#include <stdio.h>
#include <stdlib.h>

long long c[100];

void coef(int n)
{
	int i, j;

	if (n < 0 || n > 63) abort(); // gracefully deal with range issue

	for (c[i=0] = 1; i < n; c[0] = -c[0], i++)
		for (c[1 + (j=i)] = 1; j > 0; j--)
			c[j] = c[j-1] - c[j];
}

int is_prime(int n)
{
	int i;

	coef(n);
	c[0] += 1, c[i=n] -= 1;
	while (i-- && !(c[i] % n));

	return i < 0;
}

void show(int n)
{
	do printf("%+lldx^%d", c[n], n); while (n--);
}

int main(void)
{
	int n;

	for (n = 0; n < 10; n++) {
		coef(n);
		printf("(x-1)^%d = ", n);
		show(n);
		putchar('\n');
	}

	printf("\nprimes (never mind the 1):");
	for (n = 1; n <= 63; n++)
		if (is_prime(n))
			printf(" %d", n);

	putchar('\n');
	return 0;
}


using System;
    public class AksTest
    {
        static long[] c = new long[100];

        static void Main(string[] args)
        {
        for (int n = 0; n < 10; n++) {
		coef(n);
		Console.Write("(x-1)^" + n + " = ");
		show(n);
		Console.WriteLine("");
	}
	   Console.Write("Primes:");
	  for (int n = 1; n <= 63; n++)
	     if (is_prime(n))
	       Console.Write(n + " ");

	    Console.WriteLine('\n');
            Console.ReadLine();
        }

        static void coef(int n)
        {
            int i, j;

            if (n < 0 || n > 63) System.Environment.Exit(0);// gracefully deal with range issue

            for (c[i = 0] = 1L; i < n; c[0] = -c[0], i++)
                for (c[1 + (j = i)] = 1L; j > 0; j--)
                    c[j] = c[j - 1] - c[j];
        }

        static bool is_prime(int n)
        {
            int i;

            coef(n);
            c[0] += 1;
            c[i = n] -= 1;

            while (i-- != 0 && (c[i] % n) == 0) ;

            return i < 0;
        }

        static void show(int n)
	    {
		    do {
                Console.Write("+" + c[n] + "x^" + n);
		    }while (n-- != 0);
	    }
    }


#include <iomanip>
#include <iostream>
using namespace std;

const int pasTriMax = 61;

uint64_t pasTri[pasTriMax + 1];

void pascalTriangle(unsigned long n)
// Calculate the n'th line 0.. middle
{
    unsigned long j, k;

    pasTri[0] = 1;
    j = 1;
    while (j <= n)
    {
        j++;
        k = j / 2;
        pasTri[k] = pasTri[k - 1];
        for ( ;k >= 1; k--)
            pasTri[k] += pasTri[k - 1];
    }
}

bool isPrime(unsigned long n)
{
    if (n > pasTriMax)
    {
        cout << n << " is out of range" << endl;
        exit(1);
    }

    pascalTriangle(n);
    bool res = true;
    int i = n / 2;
    while (res && (i > 1))
    {
        res = res && (pasTri[i] % n == 0);
        i--;
    }
    return res;
}

void expandPoly(unsigned long n)
{
    const char vz[] = {'+', '-'};

    if (n > pasTriMax)
    {
        cout << n << " is out of range" << endl;
        exit(1);
    }

    switch (n)
    {
        case 0:
            cout << "(x-1)^0 = 1" << endl;
            break;
        case 1:
            cout << "(x-1)^1 = x-1" << endl;
            break;
        default:
            pascalTriangle(n);
            cout << "(x-1)^" << n << " = ";
            cout << "x^" << n;
            bool bVz = true;
            int nDiv2 = n / 2;
            for (unsigned long j = n - 1; j > nDiv2; j--, bVz = !bVz)
                cout << vz[bVz] << pasTri[n - j] << "*x^" << j;
            for (unsigned long j = nDiv2; j > 1; j--, bVz = !bVz)
                cout << vz[bVz] << pasTri[j] << "*x^" << j;
            cout << vz[bVz] << pasTri[1] << "*x";
            bVz = !bVz;
            cout << vz[bVz] << pasTri[0] << endl;
            break;
    }
}

int main()
{
    for (unsigned long n = 0; n <= 9; n++)
        expandPoly(n);
    for (unsigned long n = 2; n <= pasTriMax; n++)
        if (isPrime(n))
            cout << setw(3) << n;
    cout << endl;
}


(defn c
  "kth coefficient of (x - 1)^n"
  [n k]
  (/ (apply *' (range n (- n k) -1))
     (apply *' (range k 0 -1))
     (if (and (even? k) (< k n)) -1 1)))

(defn cs
  "coefficient series for (x - 1)^n, k=[0..n]"
  [n]
  (map #(c n %) (range (inc n))))

(defn aks? [p] (->> (cs p) rest butlast (every? #(-> % (mod p) zero?))))

(println "coefficient series n (k[0] .. k[n])")
(doseq [n (range 10)] (println n (cs n)))
(println)
(println "primes < 50 per AKS:" (filter aks? (range 2 50)))


pascal = () ->
    a = []
    return () ->
        if a.length is 0 then a = [1]
        else
            b = (a[i] + a[i+1] for i in [0 ... a.length - 1])
            a = [1].concat(b).concat [1]

show = (a) ->
    show_x = (e) ->
        switch e
            when 0 then ""
            when 1 then "x"
            else "x^#{e}"

    degree = a.length - 1
    str = "(x - 1)^#{degree} ="
    sgn = 1

    for i in [0...a.length]
        str += ' ' + (if sgn > 0 then "+" else "-") + ' ' + a[i] + show_x(degree - i)
        sgn = -sgn

    return str

primerow = (row) ->
    degree = row.length - 1
    row[1 ... degree].every (x) -> x % degree is 0

p = pascal()
console.log show p() for i in [0..7]

p = pascal()
p(); p()  # skip 0 and 1

primes = (i+1 for i in [1..49] when primerow p())

console.log ""
console.log "The primes upto 50 are: #{primes}"


(defun coefficients (p)
  (cond
    ((= p 0) #(1))

    (t (loop for i from 1 upto p
             for result = #(1 -1) then (map 'vector
                                            #'-
                                            (concatenate 'vector result #(0))
                                            (concatenate 'vector #(0) result))
             finally (return result)))))

(defun primep (p)
  (cond
    ((< p 2) nil)

    (t (let ((c (coefficients p)))
         (decf (elt c 0))
         (loop for i from 0 upto (/ (length c) 2)
               for x across c
               never (/= (mod x p) 0))))))

(defun main ()
  (format t "# p: (x-1)^p for small p:~%")
  (loop for p from 0 upto 7
        do (format t "~D: " p)
           (loop for i from 0
                 for x across (reverse (coefficients p))
                 do (when (>= x 0) (format t "+"))
                    (format t "~D" x)
                    (if (> i 0)
                        (format t "X^~D " i)
                        (format t " ")))
           (format t "~%"))
  (loop for i from 0 to 50
        do (when (primep i) (format t "~D " i)))
  (format t "~%"))


def x_minus_1_to_the(p)
  p.times.reduce([1]) do |ex, _|
    ([0_i64] + ex).zip(ex + [0]).map { |x, y| x - y }
  end
end

def prime?(p)
  return false if p < 2
  coeff = x_minus_1_to_the(p)[1..p//2] # only need half of coeff terms
  coeff.all?{ |n| n%p == 0 }
end

8.times do |n|
  puts "(x-1)^#{n} = " +
  x_minus_1_to_the(n).map_with_index{ |c, p|
    p.zero? ? c.to_s : (c < 0 ? " - " : " + ") + (c.abs == 1 ? "x" : "#{c.abs}x") + (p == 1 ? "" : "^#{p}")
  }.join
end

puts "\nPrimes below 50:", 50.times.select { |n| prime? n }.join(',')