二維碼的實現原理和實現過程[糾錯碼編碼]

糾錯碼編碼

在閱讀這篇文章前,你需要一些數學基礎和編程能力。

二維碼的實現原理和實現過程[數據碼編碼]我們瞭解到二維碼的數據碼是如何形成的。

糾錯碼編碼,是將數據碼字多項式糾錯碼生成多項式進行多項式除法而產生的碼字。

流程圖

糾錯碼編碼
結束編碼

多項式長除法

例如: 4x2+3 被 x+1 除。
多項式長除法例

數據碼字多項式

數據碼字多項式,就是由二維碼的實現原理和實現過程[數據碼編碼]生成的位流轉化成的多項式。
例如根據數據碼編碼,版本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係數

下列規則闡述了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,此處對伽羅瓦域不作深入探究,如果你想了解更多關於糾錯碼的原理,請參閱《糾錯碼原理與方法 修訂版》

alpha工具類

/*
* 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)

易於理解的,我們需要將糾錯碼生成多項式的一般表達式展開後,對其進行多項式長除法。在計算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.
			// <code>alpha(member position and member negation)<code> 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章