在阅读这篇文章前,你需要一些数学基础和编程能力。
在二维码的实现原理和实现过程[数据码编码]我们了解到二维码的数据码是如何形成的。
纠错码编码,是将 数据码字多项式由 纠错码生成多项式进行 多项式除法而产生的码字。数据码字多项式,就是由二维码的实现原理和实现过程[数据码编码]生成的位流转化成的多项式。
例如根据数据码编码,版本1,数字编码模式,纠错等级Q,对"01234567"进行数据码编码。
位流
"00010000 00100000 00001100 01010110 01100001 10000000 11101100 00010001 11101100 00010001 11101100 00010001 11101100"
数据码字多项式系数
"16 32 12 86 97 128 236 17 236 17 236 17 236"/*
* @method qrcode::tools::decimal_to_binary
* @params const char * binary
* @return a number from byte
* @methodState stable
* @This function is used to encode binary string to
* decimal number.
*/
int qrcode::tools::binary_to_decimal(const char * binary){
std::string source = binary;
int dst = 0;
int length = source.length() - 1;
for (int i = length; i >= 0; i--){
if (source.at(i) == '0'){
//do nothing
}
else if (source.at(i) == '1'){
dst +=( 1 << (length - i));
}
else{
dst = 0;
break;
}
}
return dst;
}
易于发现的,我们需要一个被除数 除以 数据码字多项式。这个被除数被称为纠错码生成多项式。
纠错码生成多项式的一般表达式:f(x)=(x-a0)(x-a1)…(x-an-1)(n≥1 且n<=256),其中a可称为alpha系数,它的前几项由2的次幂组成,但不完全是2的次幂。
下列规则阐述了alpha系数如何生成:
a0=1,a1=2 … a7=128。
a8=256 ^ 285=29。
a9=29*2 =58。
当alpha系数再次超过255时,继续进行异或运算。
alpha系数最高次为255,最低次为0。
实际alpha系数来源于有限域(伽罗瓦域)GF(28) mod 100011101,此处对伽罗瓦域不作深入探究,如果你想了解更多关于纠错码的原理,请参阅《纠错码原理与方法 修订版》。
/*
* to init @member member_position , @member member_negation.
*/
void qrcode::error_correcting_encode::ErrorCorrectingEncode::init(){
if (member_negation == nullptr){
this->member_negation = new int[256];
}
if (member_position == nullptr){
this->member_position = new int[256];
}
int _operator = 1;
this->member_negation[0] = -1;
for (int i = 0; i < 256; i++){
this->member_position[i] = _operator;
this->member_negation[_operator] = i;
_operator = _operator << 1;
if (_operator > 255){
_operator = _operator ^ 285;
}
}
}
易于理解的,我们需要将纠错码生成多项式的一般表达式展开后,对其进行多项式长除法。在计算f(x)之前,我想举例如何在计算机中计算下式:g(x)=(x-1)(x-2)(x-3)…(x-n) (n≥1)。
第一次:
(x - 1)(x - 2)
(x - 1)x +
(x - 1)(-2)
x2 - x
- 2x + 2
合并同类项后为 x2 - 3x + 2;
第二次:
(x2 - 3x + 2)(x-3)
(x2 - 3x + 2)x +
(x2 - 3x + 2)(-3)
x3 - 3x2 + 2x
- 3x2 + 9x - 6
由于最终结果是由计算机计算,我不担心g(x)的最终多项式系数会算错。
不难发现的,g(x)中,无论n为多大,最终结果多项式从左往右每一项的x的次幂在等差递减。
在计算过程中,左部多项式分别与x相乘,与常数相乘又使计算出的两个多项式错位。
同理,f(x)=(x-a0)(x-a1)…(x-an-1)(n≥1) 也可以用这种方式进行编码计算。
在做乘法时,alpha系数满足如下计算法则:
a1 * a2 = a3
a254 * a2 = a256%255=a1
即a的次幂项相乘,指数相加,如果超过255,则次幂对255取余后的结果才是最终结果。
但f(x)中合并同类项时,需将alpha系数转化成十进制整数,并且不考虑正负形式,合并时的计算符号⊕ 是异或运算。
这些运算法则是由有限域(伽罗瓦域)GF(28) mod 100011101决定的。
f(x)=(x-a0)(x-a1)…(x-an-1)(n≥1)。
第一次:
(x - a0)(x - a1)
(x - a0)x +
(x - a0)(a1)
x2 - a0x
a1x +a1a0
合并同类项后为x2 - a0x⊕a1x +a1a0
结果:x2 + 3x1+ 2 注意:1^2 =3;
以此进行编码:
int * qrcode::error_correcting_encode::ErrorCorrectingEncode::get_generator_polynomial(int length){
// this function do this:
// a0 a0
// a1a0 a1a0
// a0 a0^a1a0 a1a0
init();
member_generator_polynomial = new int[2]{0, 0};
for (int temp = 2; temp < length + 1; temp++){
int * temp_polynomial = new int[temp];
int * result_polynomial = new int[temp + 1];
for (int i = 0; i < temp; i++){
temp_polynomial[i] = member_generator_polynomial[i] + temp - 1;
if (temp_polynomial[i] > 255){
temp_polynomial[i] %= 255;
}
}
for (int i = 0; i < temp + 1; i++){
if (0 == i){
result_polynomial[i] = 0;
}
else if (temp==i){
result_polynomial[i] = temp_polynomial[i - 1];
}
else{
int first_line = member_position[member_generator_polynomial[i]];
int last_line = member_position[temp_polynomial[i - 1]];
int result = first_line^last_line;
result_polynomial[i] = member_negation[result];
}
}
delete[] member_generator_polynomial;
member_generator_polynomial = nullptr;
member_generator_polynomial = new int[temp + 1];
memcpy(member_generator_polynomial, result_polynomial, sizeof(int)*(temp + 1));
delete [] temp_polynomial;
temp_polynomial = nullptr;
delete [] result_polynomial;
result_polynomial = nullptr;
}
destory();
return member_generator_polynomial;
}
由于版本1的数据总字数是26,纠错码的字数是13,数据码的字数是13。
总是需要根据数据码的字数计算计算次数,这里因为数据码的字数是13,所以要计算13次。
而纠错码生成多项式的首项的x指数是由纠错码的字数决定的。
所以有如下计算规则:
数据码字:16 32 12 86 97 128 236 17 236 17 236 17 236
纠错码字生成多项式:16 120 228 150 13 223 13 103 208 218 138 89 168 211
异或运算:16^16 32^120 12^228 86^150 97^13 128^223 236^13 17^103 236^208 17^218 236^138 17^89 236^168 0^211 16 120 228 150 13 223 13 103 208 218 138 89 168 211
结果码字:88 232 192 108 95 225 118 60 203 102 72 68 211 0
纠错码字生成多项式:88 185 33 191 177 101 177 91 223 248 221 130 102 95
异或运算:88^88 232^185 192^33 108^191 95^177 225^101 118^177 60^91 203^223 102^248 72^221 68^130 211^102 0^95 88 185 33 191 177 101 177 91 223 248 221 130 102 95
结果码字:81 225 211 238 132 199 103 20 158 149 198 181 95 0
纠错码字生成多项式:81 12 26 23 40 53 40 210 186 187 179 115 182 192
异或运算:81^81 225^12 211^26 238^23 132^40 199^53 103^40 20^210 158^186 149^187 198^179 181^115 95^182 0^192 81 12 26 23 40 53 40 210 186 187 179 115 182 192
结果码字:237 201 249 172 242 79 198 36 46 117 198 233 192 0
纠错码字生成多项式:237 65 19 148 155 224 155 9 69 131 253 153 4 100
异或运算:237^237 201^65 249^19 172^148 242^155 79^224 198^155 36^9 46^69 117^131 198^253 233^153 192^4 0^100 237 65 19 148 155 224 155 9 69 131 253 153 4 100
结果码字:136 234 56 105 175 93 45 107 246 59 112 196 100 0
纠错码字生成多项式:136 219 1 143 224 87 224 162 166 243 97 80 125 49
异或运算:136^136 234^219 56^1 105^143 175^224 93^87 45^224 107^162 246^166 59^243 112^97 196^80 100^125 0^49 136 219 1 143 224 87 224 162 166 243 97 80 125 49
结果码字:49 57 230 79 10 205 201 80 200 17 148 25 49 0
纠错码字生成多项式:49 1 120 68 6 205 6 157 96 93 168 184 97 16
异或运算:49^49 57^1 230^120 79^68 10^6 205^205 201^6 80^157 200^96 17^93 148^168 25^184 49^97 0^16 49 1 120 68 6 205 6 157 96 93 168 184 97 16
结果码字:56 158 11 12 0 207 205 168 76 60 161 80 16 0
纠错码字生成多项式:56 180 67 236 159 157 159 20 5 30 198 73 177 143
异或运算:56^56 158^180 11^67 12^236 0^159 207^157 205^159 168^20 76^5 60^30 161^198 80^73 16^177 0^143 56 180 67 236 159 157 159 20 5 30 198 73 177 143
结果码字:42 72 224 159 82 82 188 73 34 103 25 161 143 0
纠错码字生成多项式:42 195 53 161 176 61 176 27 207 152 26 182 12 172
异或运算:42^42 72^195 224^53 159^161 82^176 82^61 188^176 73^27 34^207 103^152 25^26 161^182 143^12 0^172 42 195 53 161 176 61 176 27 207 152 26 182 12 172
结果码字:139 213 62 226 111 12 82 237 255 3 23 131 172 0
纠错码字生成多项式:139 93 218 183 211 153 211 254 177 129 28 165 236 185
异或运算:139^139 213^93 62^218 226^183 111^211 12^153 82^211 237^254 255^177 3^129 23^28 131^165 172^236 0^185 139 93 218 183 211 153 211 254 177 129 28 165 236 185
结果码字:136 228 85 188 149 129 19 78 130 11 38 64 185 0
纠错码字生成多项式:136 219 1 143 224 87 224 162 166 243 97 80 125 49
异或运算:136^136 228^219 85^1 188^143 149^224 129^87 19^224 78^162 130^166 11^243 38^97 64^80 185^125 0^49 136 219 1 143 224 87 224 162 166 243 97 80 125 49
结果码字:63 84 51 117 214 243 236 36 248 71 16 196 49 0
纠错码字生成多项式:63 44 161 127 232 173 232 152 38 212 23 237 10 250
异或运算:63^63 84^44 51^161 117^127 214^232 243^173 236^232 36^152 248^38 71^212 16^23 196^237 49^10 0^250 63 44 161 127 232 173 232 152 38 212 23 237 10 250
结果码字:120 146 10 62 94 4 188 222 147 7 41 59 250 0
纠错码字生成多项式:120 73 244 142 171 198 171 149 98 81 212 48 43 228
异或运算:120^120 146^73 10^244 62^142 94^171 4^198 188^171 222^149 147^98 7^81 41^212 59^48 250^43 0^228 120 73 244 142 171 198 171 149 98 81 212 48 43 228
结果码字:219 254 176 245 194 23 75 241 86 253 11 209 228 0
纠错码字生成多项式:219 216 137 67 234 29 234 24 6 20 132 133 222 1
异或运算:219^219 254^216 176^137 245^67 194^234 23^29 75^234 241^24 86^6 253^20 11^132 209^133 228^222 0^1
纠错码字:38 57 182 40 10 161 233 80 233 143 84 58 1
std::string qrcode::error_correcting_encode::ErrorCorrectingEncode::Encode(std::string code){
// operated code length
int operate_code_length = code.length();
// operated polynomial length
int operated_polynomial_length = operate_code_length >> 3;
// get the error correcting code length
int error_correcting_code_length = qrcode::error_correcting_encode::settings::block_code_length(this->member_basic_information);
// get the generator_polynomial_length
int error_correcting_polynomial_length = error_correcting_code_length + 1;
// apply the result polynomial: the dividend polynomial(dividend)
int * operate_polynomial = new int[operated_polynomial_length + error_correcting_code_length];
// set the dividend polynomial arrays = 0;
memset(operate_polynomial, 0, sizeof(int)*(operated_polynomial_length + error_correcting_code_length));
// get decimal number from code.
for (int i = 0, term = 0; i < operate_code_length; i += 8, term++){
operate_polynomial[term] = qrcode::tools::binary_to_decimal(code.substr(i, 8).data());
std::cout << operate_polynomial[term] << " ";
}
std::cout << std::endl;
// do polynomial division
for (int j = operated_polynomial_length + error_correcting_polynomial_length; j > error_correcting_polynomial_length; j--){
// get the generator_polynomial
int * generator_polynomial = get_generator_polynomial(error_correcting_code_length);
// alpha init.
// alpha(member position and member negation) is a member of this ErrorCorrectingEncode class.
// when get_generator_polynomial() is called,
// alpha will be init from point and be destory from point,
// so that it must call this->init() function after the get_generator_polynomial() function.
// Otherwise, memory leak.
this->init();
// get the lead term of the message polynomial
int first_term_difference = member_negation[operate_polynomial[0]] - generator_polynomial[0];
// Multiply the Generator Polynomial by the Lead Term of the Message Polynomial
for (int i = 0; i < error_correcting_polynomial_length; i++){
generator_polynomial[i] += first_term_difference;
if (generator_polynomial[i] > 255){
generator_polynomial[i] %= 255;
}
}
// XOR the result with the message polynomial
for (int i = 0; i < error_correcting_polynomial_length; i++){
operate_polynomial[i] ^= this->member_position[generator_polynomial[i]];
}
// free the useless memory.
delete[] generator_polynomial;
generator_polynomial = nullptr;
int * temp = new int[j - 1];
memcpy(temp, operate_polynomial + 1, sizeof(int)*(j - 1));
delete[] operate_polynomial;
operate_polynomial = nullptr;
operate_polynomial = temp;
this->destory();
}
// handle the result.
for (int i = 0; i < error_correcting_code_length; i++){
char * temp = nullptr;
temp = new char[9];
std::string operated_data = qrcode::tools::decimal_to_binary(operate_polynomial[i]);
sprintf_s(temp, 9, "%08s", operated_data.data());
member_result += temp;
}
delete[] operate_polynomial;
operate_polynomial = nullptr;
return member_result;
}