CRCについてはNumerical Recipesの第二版以降にある、Less numerical Algorithmsの章にある原理の説明を読むのがよかろうかと思います。
もう細部はすっかり忘れてしまいました。覚えているのは、1.割り算の余りを比較する。2.余りが違ければ元の数もちがう。3.2のModuloをとることで割り算の桁下がりを避ける。4.割り算の多項式をうまく選ぶと、たとえ偶然同じ余りが出るにしても、狂っているビット同士は近くには無い(以下のCRC16なら8?ビット以内には無い)。ということくらい。
MPEG1のCRC16の生成多項式の定義は、IBMのBISYNCHというものと共通のようです。生成多項式はx^16+x^15+x^2+1、初期値はZ'FFFF'です。
MPEG1でのCRCの利用は、あくまでデータの一部に対するエラーチェックのみで、訂正機能は持ちません。MPEG1/Layer3(MP3)はISDNによる64Kbps,2ch(計128kbps)のストリーミングを念頭に置いたものですが、CRCエラーも伝送エラーを想定しているものと思われます。CRCエラーがある場合はデータの再送信を要求することが考えられます。
CRCエンコードされるのは主に音量のスケールファクターを定義する部分なので、エラーがある場合プレーヤは音声をミュートにすることで、機器を壊すような大音量が出ることを避けることができます。
ただ、世間に流通しているMP3ファイルでCRCが付いているものをほとんど見たことがありません。また、プレーヤ側でもCRCエラーを無視することが多いようです。
■ソース・コード
10年位前のプログラムを書き直したので見かけ上は動作してますが、まだチェックをしっかりやってないので、余り信じないでくださいw あくまでOOPの形式の練習ということで。
初期値付のスカラー要素割付によるインスタンス生成をやってみました。わざわざALLOCATABLEにしなくてもいいんですが、まぁ練習だからw
MODULE m_crc IMPLICIT NONE PRIVATE PUBLIC :: t_crc TYPE :: t_crc INTEGER(2) :: generator = Z'8005' !B'1000000000000101' ! x^16+x^15+x^2+1 INTEGER(2) :: crc CONTAINS PROCEDURE :: crc16 PROCEDURE :: set PROCEDURE :: get END TYPE t_crc CONTAINS !-------------------------------------------------------------------------- SUBROUTINE set(this, init) CLASS(t_crc), INTENT(IN OUT) :: this INTEGER, INTENT(IN) :: init this%crc = init RETURN END SUBROUTINE set !-------------------------------------------------------------------------- INTEGER(2) FUNCTION get(this) CLASS(t_crc), INTENT(IN OUT) :: this get = this%crc RETURN END FUNCTION get !-------------------------------------------------------------------------- SUBROUTINE crc16(this, n, in) CLASS(t_crc), INTENT(IN OUT) :: this INTEGER, INTENT(IN) :: n, in INTEGER :: i, ibit1, ibit2 DO i = n - 1, 0, -1 ibit1 = IBITS(in, i, 1) ibit2 = IBITS(this%crc, 15, 1) this%crc = ISHFT(this%crc, 1) IF ( IEOR(ibit1, ibit2) == 1 ) this%crc = IEOR(this%crc, this%generator) END DO RETURN END SUBROUTINE crc16 !-------------------------------------------------------------------------- END MODULE m_crc !=========================================================================== PROGRAM test USE m_crc IMPLICIT NONE INTEGER :: i TYPE (t_crc), ALLOCATABLE :: crc ALLOCATE( crc, SOURCE = t_crc(Z'8005', Z'FFFF') ) ! generate instance ! ALLOCATE( crc ) ! CALL crc%set( Z'FFFF' ) PRINT '(B16.16)', crc%get() DO i = 1, Z'000F' CALL crc%crc16(8, i) PRINT '(B16.16)', crc%get() END DO STOP END PROGRAM test