0

I'm using bash to compute the multinomial coefficients. The code follows bellow:

#!/bin/bash

function factorial {
  declare n=$1
    (( n < 2 )) && echo 1 && return
      echo $(( n * $(factorial $((n-1))) ))
}

function binomial {
  declare n=$1
  declare k=$2
  echo $(( $(factorial $((n))) / ( $(factorial $((k))) * $(factorial $((n-k)))  ) ))
}

function multinomial {
  arr=("$@")
  declare mcoeff=1
  declare n=0
  for k in "${arr[@]}";
  do
    ((n=$n+$k))
    ((mcoeff=$mcoeff*$(binomial "$n" "$k")))
  done
  echo "$mcoeff"
}

multinomial $@

It seems I have an overflow in some situations.

$ ./multinomial.sh 4 5 6
630630
$ ./multinomial.sh 4 5 6 7
-119189070

Any idea how to fix this?

LEo
  • 477
  • 5
  • 14

1 Answers1

3

A shell is an environment from which to call tools with a language to sequence those calls. It is not meant to be a full-featured programming language nor is it meant for complicated calculations. Try this instead, I just translated your shell code into the equivalent awk:

$ cat multinomial.sh
#!/usr/bin/env bash

awk -v nums="$*" '
function factorial(n) {
    if ( n < 2 ) {
        return 1
    }
    return n * factorial(n-1)
}

function binomial(n,k) {
    return factorial(n) / ( factorial(k) * factorial(n-k) )
}

function multinomial(str,   arr, mcoeff, n, k) {
    split(str,arr)
    mcoeff = 1
    n = 0
    for (j=1; j in arr; j++) {
        k = arr[j]
        n = n + k
        mcoeff = mcoeff * binomial(n,k)
    }
    return mcoeff
}

BEGIN { print multinomial(nums) }
'

.

$ ./multinomial.sh 4 5 6
630630

$ ./multinomial.sh 4 5 6 7
107550162720

$ ./multinomial.sh 4 5 6 7 8
629483036137955968
Ed Morton
  • 188,023
  • 17
  • 78
  • 185