-- The Great Computer Language Shootout
-- http://shootout.alioth.debian.org/
--
-- contributed by Adam Sampson <ats@offog.org>

#INCLUDE "course.module"

VAL INT N IS 2500:

REAL64 FUNCTION A (VAL INT i, j)
  VAL REAL64 ir IS REAL64 ROUND i:
  VAL REAL64 jr IS REAL64 ROUND j:
  VALOF
    SKIP
    RESULT 1.0 / ((((ir + jr) * ((ir + jr) + 1.0)) / 2.0) + (ir + 1.0))
:

PROC multiply.av (VAL INT n, VAL []REAL64 v, []REAL64 av)
  SEQ i = 0 FOR n
    SEQ
      av[i] := 0.0
      SEQ j = 0 FOR n
        av[i] := av[i] + (A (i, j) * v[j])
:

PROC multiply.at.v (VAL INT n, VAL []REAL64 v, []REAL64 at.v)
  SEQ i = 0 FOR n
    SEQ
      at.v[i] := 0.0
      SEQ j = 0 FOR n
        at.v[i] := at.v[i] + (A (j, i) * v[j])
:

PROC multiply.at.av (VAL INT n, VAL []REAL64 v, []REAL64 at.av)
  MOBILE []REAL64 u:
  SEQ
    u := MOBILE [n]REAL64
    multiply.av (n, v, u)
    multiply.at.v (n, u, at.av)
:

REAL64 FUNCTION approximate (VAL INT n)
  REAL64 vbv, vv:
  VALOF
    MOBILE []REAL64 u, v:
    SEQ
      u := MOBILE [n]REAL64
      v := MOBILE [n]REAL64
      SEQ i = 0 FOR n
        SEQ
          u[i] := 1.0
          v[i] := 0.0
      SEQ i = 0 FOR 10
        SEQ
          multiply.at.av (n, u, v)
          multiply.at.av (n, v, u)
      vbv := 0.0
      vv := 0.0
      SEQ i = 0 FOR n
        SEQ
          vbv := vbv + (u[i] * v[i])
          vv := vv + (v[i] * v[i])
    RESULT DSQRT (vbv / vv)
:

PROC main (CHAN BYTE out!)
  SEQ
    out.real64 (approximate (N), 9, 9, out!)
    out ! '*n'
:

