mirror of
https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
synced 2025-08-29 08:45:58 +02:00
274 lines
7.0 KiB
JavaScript
274 lines
7.0 KiB
JavaScript
/**
|
|
* @name CeL Hamming function
|
|
* @fileoverview 本檔案包含了 Hamming Code, 漢明碼的 functions。
|
|
* @since 2010/3/21 14:26:08
|
|
* @example <code>
|
|
CeL.run('data.math.Hamming');
|
|
var hc = CeL.Hamming.encode('1100');
|
|
|
|
|
|
TODO:
|
|
最佳化
|
|
calculate generator matrix
|
|
SEC-DED ("single error correction, double error detection") 版本(加在最後)
|
|
http://www.ee.unb.ca/cgi-bin/tervo/hamming.pl
|
|
最小漢明距離3
|
|
http://phpbb.godfat.org/viewtopic.php?t=66&sid=6e34dd040aa98c64c75bfe099008c82a
|
|
BCH碼
|
|
|
|
</code>
|
|
*/
|
|
|
|
// More examples: see /_test suite/test.js
|
|
'use strict';
|
|
// 'use asm';
|
|
|
|
// --------------------------------------------------------------------------------------------
|
|
|
|
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
|
|
typeof CeL === 'function' && CeL.run({
|
|
// module name
|
|
name : 'data.math.Hamming',
|
|
|
|
// require : '',
|
|
|
|
// 設定不匯出的子函式。
|
|
no_extend : '*',
|
|
|
|
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
|
|
code : module_code
|
|
});
|
|
|
|
function module_code(library_namespace) {
|
|
|
|
// nothing required
|
|
|
|
var module_name = this.id;
|
|
|
|
// ============================================================================
|
|
// definition of module Hamming
|
|
|
|
var
|
|
/**
|
|
* Hamming code
|
|
*
|
|
* @class Hamming Code 的 constructor
|
|
* @constructor
|
|
*/
|
|
_// JSDT:_module_
|
|
= function() {
|
|
return this.encode.apply(this, arguments);
|
|
};
|
|
|
|
// class public interface ---------------------------
|
|
|
|
_// JSDT:_module_
|
|
.
|
|
/**
|
|
* 是否左右顛倒。 default: data[1,2,..] 左至右, reverse: data[..,2,1] 右至左
|
|
*
|
|
* @_memberOf _module_
|
|
*/
|
|
reverse = false;
|
|
|
|
_// JSDT:_module_
|
|
.
|
|
/**
|
|
* encode data to Hamming Code.
|
|
*
|
|
* @param data
|
|
* data stream
|
|
* @param no_reverse
|
|
* forced NO reverse
|
|
* @return {String} encoded Hamming Code
|
|
* @_memberOf _module_
|
|
*/
|
|
encode = function(data, no_reverse) {
|
|
data = (Array.isArray(data) ? data.join('') : '' + data).replace(
|
|
/[ ,]/g, '');
|
|
if (!/^[01]{1,20}$/.test(data))
|
|
return '';
|
|
if (this.reverse && !no_reverse)
|
|
data = data.split('').reverse().join('');
|
|
if (false)
|
|
library_namespace.debug('encode [' + d + ']', 1, module_name
|
|
+ '.encode');
|
|
var g = [ '' ], i_g = 1, bin = 1, i, i_d = 0, l_d = data.length, ch;
|
|
for (;; i_g++) {
|
|
if (i_g === bin) {
|
|
if (false)
|
|
library_namespace.debug('initial [' + g.length + '] as 0',
|
|
1, module_name + '.encode');
|
|
g.push(0);
|
|
bin *= 2;
|
|
} else {
|
|
if (false)
|
|
library_namespace.debug('initial [' + g.length + '] as '
|
|
+ d.charAt(i_d) + ' (' + i_d + '/' + l_d + ')', 1,
|
|
module_name + '.encode');
|
|
g.push(ch = data.charAt(i_d));
|
|
for (i = 1; i < bin; i *= 2)
|
|
if (i_g & i)
|
|
g[i] ^= ch;
|
|
if (++i_d === l_d)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (library_namespace.is_debug(2)) {
|
|
// for debug print
|
|
for (bin = i = 1, i_d = []; i < g.length; i++) {
|
|
ch = g[i];
|
|
if (i === bin)
|
|
ch = '<span style="color: #292;">' + ch + '</span>',
|
|
bin *= 2;
|
|
// i_d 在這表示一個專門用於顯示的 array
|
|
i_d.push(ch);
|
|
}
|
|
library_namespace.log('Hamming code of [' + data + ']: ['
|
|
+ i_d.join('') + ']');
|
|
}
|
|
|
|
if (this.reverse && !no_reverse)
|
|
g = g.reverse();
|
|
return g.join('');
|
|
};
|
|
|
|
_// JSDT:_module_
|
|
.
|
|
/**
|
|
* 將 Hamming Code 分成 data & check bits
|
|
*
|
|
* @param code
|
|
* Hamming Code to split
|
|
* @return [資料位元 data bits, 檢查位元 check bits (parity bits)]
|
|
* @_memberOf _module_
|
|
*/
|
|
split_code = function(code) {
|
|
if (Array.isArray(code))
|
|
code = code.join('');
|
|
code = (' ' + code).split('');
|
|
library_namespace.debug('split [' + code + ']', 1, module_name
|
|
+ '.split_code', 3);
|
|
var i = 1, l = code.length, cb = [];
|
|
while (i < l) {
|
|
cb.push(code[i]);
|
|
code[i] = '';
|
|
i *= 2;
|
|
}
|
|
library_namespace.debug('→ data [' + code.join('').replace(/ +/g, '')
|
|
+ '], check bits [' + cb + ']', 1,
|
|
module_name + '.split_code', 3);
|
|
return [ code.join('').replace(/ +/g, ''), cb ];
|
|
};
|
|
|
|
_// JSDT:_module_
|
|
.
|
|
/**
|
|
* decode Hamming Code to data
|
|
*
|
|
* @param code
|
|
* @return
|
|
* @_memberOf _module_
|
|
*/
|
|
decode = function(code) {
|
|
if (!code
|
|
|| !/^[01]{3,30}$/
|
|
.test(code = ('' + code).replace(/[ ,]/g, '')))
|
|
return '';
|
|
code = code.split('');
|
|
if (this.reverse)
|
|
code = code.reverse();
|
|
|
|
var i = 0, l = code.length, ch, bin = 1, split_c = this
|
|
.split_code(code), test_c, cb;
|
|
|
|
if (!split_c)
|
|
return;
|
|
// check bits (parity bits)
|
|
cb = split_c[1];
|
|
test_c = this.encode(split_c[0], 1);
|
|
if (!test_c || !(test_c = this.split_code(test_c)))
|
|
return;
|
|
|
|
library_namespace.debug('received check bits: [' + cb.join('')
|
|
+ '], calculated: [' + test_c[1].join('') + ']', 1, module_name
|
|
+ '.decode');
|
|
test_c = parseInt(test_c[1].reverse().join(''), 2)
|
|
^ parseInt(cb.reverse().join(''), 2);
|
|
library_namespace.debug('error bit'
|
|
+ (this.reverse ? ' (do reversed XOR)' : '') + ': ' + test_c
|
|
+ '(' + test_c.toString(2) + '), ' + code.join(''), 1,
|
|
module_name + '.decode');
|
|
if (test_c)
|
|
if (test_c < code.length) {
|
|
code[test_c - 1] ^= 1;
|
|
split_c = this.split_code(code);
|
|
} else {
|
|
// 這算是能檢測出 2 bits 以上錯誤的特殊例子,機率通常也不大:已經超過 index 了。
|
|
// e.g., reversed 011010001100
|
|
library_namespace.debug(
|
|
'<em>Out of index!</em> More than 2 errors occurred.',
|
|
1, module_name + '.decode');
|
|
}
|
|
|
|
if (library_namespace.is_debug())
|
|
if (test_c) {
|
|
cb = code.join('\0').split('\0');
|
|
cb[test_c - 1] = '<span style="color:#f33;">' + cb[test_c - 1]
|
|
+ '</span>';
|
|
library_namespace.debug('→ ' + cb.join(''), 1, module_name
|
|
+ '.decode');
|
|
} else
|
|
library_namespace.debug('The Hamming code is correct.', 1,
|
|
module_name + '.decode');
|
|
|
|
split_c = split_c[0];
|
|
if (this.reverse)
|
|
split_c = split_c.split('').reverse().join('');
|
|
return split_c;
|
|
};
|
|
|
|
_// JSDT:_module_
|
|
.
|
|
/**
|
|
* 顯示 Hamming Code 的計算方法
|
|
*
|
|
* @param {Number}
|
|
* bit_length bit length. e.g., 8, 16.
|
|
* @_memberOf _module_
|
|
*/
|
|
show = function(bit_length) {
|
|
var code = [], bit = [], parity = [], i = 1, j, k, d = 1, a = 1, cc = 1, dc = 1;
|
|
for (;; i++) {
|
|
bit[i] = i.toString(2);
|
|
if (i === a) {
|
|
code[i] = 'C' + Math.pow(2, cc++ - 1);
|
|
a *= 2;
|
|
} else {
|
|
code[i] = 'D' + dc++;
|
|
for (j = 1, k = 1; j < cc; j++, k *= 2)
|
|
if (i & k)
|
|
if (parity[j])
|
|
parity[j] += '<span style="color:#aaa;">⊕</span>'
|
|
+ code[i];
|
|
else
|
|
parity[j] = code[i];
|
|
if (dc > bit_length)
|
|
break;
|
|
}
|
|
}
|
|
for (i = 1; i < code.length; i++) {
|
|
a = code[i];
|
|
if (j = a.match(/^C(\d+)$/))
|
|
a += ' = '
|
|
+ parity[Math.round(Math.log(j[1]) * Math.LOG2E) + 1];
|
|
library_namespace.debug(bit[i] + ': ' + a);
|
|
}
|
|
|
|
};
|
|
|
|
return (_// JSDT:_module_
|
|
);
|
|
}
|