続・ISBNのチェックデジット

昨日の続き。Schemeで、ISBNのチェックデジットを求めるプログラムを最適化。

shiroさんからいただいたヒントを使い、無駄なlambdaを省いたり、同じ意味の数値を変数で名前付けしてしまうなどして、

(define (isbn-check-digit4 n)
  (let ((isbn-check-digit-base 11)
        (isbn-base-vector '(10 9 8 7 6 5 4 3 2)))
    (modulo
      (- isbn-check-digit-base
         (apply + (map * n isbn-base-vector)))
      isbn-check-digit-base)))

と、かなりよくなった。

さらに、nishioさんのコメントをふまえて計算式自体をもう少し解析してみると、

c = (11 - (10n1 + 9n2 + ... + 2n9)) mod 11
= (11 - 10n1 - 9n2 - ... - 2n9) mod 11
= (1n1 + 2n2 + ... + 9n9) mod 11
= (n1 n2 ... n9)・(1 2 ... 9) mod 11 //

ということで、(1 2 3 4 5 6 7 8 9) との内積値の mod 11 にまとまる。

(define (isbn-check-digit5 n)
  (let ((isbn-check-digit-base 11)
        (isbn-base-vector '(1 2 3 4 5 6 7 8 9)))
    (modulo (apply + (map * n isbn-base-vector))
            isbn-check-digit-base)))

とても分かりやすい。本来こんなに分かりやすい計算なのに、なんであんな小難しい形に定義したんだろう・・・。