diff --git a/bose_chaudhuri_hocquenghem_decoder.hh b/bose_chaudhuri_hocquenghem_decoder.hh index 7eb507d..e169ef8 100644 --- a/bose_chaudhuri_hocquenghem_decoder.hh +++ b/bose_chaudhuri_hocquenghem_decoder.hh @@ -62,6 +62,52 @@ public: corrections_count += !!magnitudes[i]; return corrections_count; } + int compute_syndromes(uint8_t *code, ValueType *syndromes) + { + // $syndromes_i = code(pe^{FCR+i})$ + for (int i = 0; i < NR; ++i) + syndromes[i] = ValueType((code[0] >> 7) & 1); + for (int j = 1; j < N; ++j) { + IndexType root(FCR), pe(1); + for (int i = 0; i < NR; ++i) { + syndromes[i] = fma(root, syndromes[i], ValueType((code[j / 8] >> (7 - j % 8)) & 1)); + root *= pe; + } + } + int nonzero = 0; + for (int i = 0; i < NR; ++i) + nonzero += !!syndromes[i]; + return nonzero; + } + int compute_syndromes(uint8_t *code, value_type *syndromes) + { + return compute_syndromes(code, reinterpret_cast(syndromes)); + } + int operator()(uint8_t *code, value_type *erasures = 0, int erasures_count = 0) + { + assert(0 <= erasures_count && erasures_count <= NR); + if (0) { + for (int i = 0; i < erasures_count; ++i) + code[erasures[i] / 8] &= ~(128 >> (erasures[i] % 8)); + } + ValueType syndromes[NR]; + if (!compute_syndromes(code, syndromes)) + return 0; + IndexType locations[NR]; + ValueType magnitudes[NR]; + int count = algorithm(syndromes, locations, magnitudes, reinterpret_cast(erasures), erasures_count); + if (count <= 0) + return count; + for (int i = 0; i < count; ++i) + if (1 < (int)magnitudes[i]) + return -1; + for (int i = 0; i < count; ++i) + code[(int)locations[i] / 8] ^= (int)magnitudes[i] << (7 - (int)locations[i] % 8); + int corrections_count = 0; + for (int i = 0; i < count; ++i) + corrections_count += !!magnitudes[i]; + return corrections_count; + } }; } diff --git a/tests/bch_decoder_test.cc b/tests/bch_decoder_test.cc index 204ada5..5f7aac6 100644 --- a/tests/bch_decoder_test.cc +++ b/tests/bch_decoder_test.cc @@ -18,41 +18,49 @@ int main() // NASA INTRO BCH(15, 5) T=3 typedef CODE::GaloisField<4, 0b10011, uint8_t> GF; typedef CODE::BoseChaudhuriHocquenghemDecoder<6, 1, 5, GF> BCH; + const int L = (BCH::N + 7) / 8; GF instance; BCH decode; - uint8_t target[BCH::N] = { 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0 }; - uint8_t code[BCH::N]; - for (int i = 0; i < BCH::N; ++i) + uint8_t target[L] = { 0b11001000, 0b11110100 }; + uint8_t code[L]; + for (int i = 0; i < L; ++i) code[i] = target[i]; - std::uniform_int_distribution distribution(0, BCH::N-1); + std::uniform_int_distribution distribution(0, BCH::N-1); auto noise = std::bind(distribution, generator); - for (int i = 0; i < 3; ++i) - code[noise()] ^= 1; - decode(reinterpret_cast(code)); - for (int i = 0; i < BCH::N; ++i) + for (int i = 0; i < 3; ++i) { + int n = noise(); + code[n / 8] ^= 128 >> (n % 8); + } + decode(code); + for (int i = 0; i < L; ++i) assert(code[i] == target[i]); } if (1) { // DVB-S2 FULL BCH(65535, 65343) T=12 typedef CODE::GaloisField<16, 0b10000000000101101, uint16_t> GF; typedef CODE::BoseChaudhuriHocquenghemDecoder<24, 1, 65343, GF> BCH; + const int L = (BCH::N + 7) / 8; GF *instance = new GF(); BCH *decode = new BCH(); - uint16_t *target = new uint16_t[BCH::N]; + uint8_t *target = new uint8_t[L]; + for (int i = 0; i < L; ++i) + target[i] = 0; for (int i = 0, s = 0; i < BCH::K; ++i, s=(s*(s*s*51767+71287)+35149)&0xffffff) - target[i] = (s^=s>>7)&1; - uint16_t parity[BCH::NP] = { 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0 }; + target[i/8] |= ((s^=s>>7)&1) << (7-i%8); + bool parity[BCH::NP] = { 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0 }; for (int i = 0; i < BCH::NP; ++i) - target[BCH::K+i] = parity[i]; - uint16_t *code = new uint16_t[BCH::N]; - for (int i = 0; i < BCH::N; ++i) + target[(BCH::K+i)/8] |= parity[i] << (7-(BCH::K+i)%8); + uint8_t *code = new uint8_t[L]; + for (int i = 0; i < L; ++i) code[i] = target[i]; - std::uniform_int_distribution distribution(0, BCH::N-1); + std::uniform_int_distribution distribution(0, BCH::N-1); auto noise = std::bind(distribution, generator); - for (int i = 0; i < 12; ++i) - code[noise()] ^= 1; - (*decode)(reinterpret_cast(code)); - for (int i = 0; i < BCH::N; ++i) + for (int i = 0; i < 12; ++i) { + int n = noise(); + code[n / 8] ^= 128 >> (n % 8); + } + (*decode)(code); + for (int i = 0; i < L; ++i) assert(code[i] == target[i]); delete[] target; delete[] code;