gf_poly.go (4361B)
1 // go-qrcode 2 // Copyright 2014 Tom Harwood 3 4 package reedsolomon 5 6 import ( 7 "fmt" 8 "log" 9 10 bitset "github.com/skip2/go-qrcode/bitset" 11 ) 12 13 // gfPoly is a polynomial over GF(2^8). 14 type gfPoly struct { 15 // The ith value is the coefficient of the ith degree of x. 16 // term[0]*(x^0) + term[1]*(x^1) + term[2]*(x^2) ... 17 term []gfElement 18 } 19 20 // newGFPolyFromData returns |data| as a polynomial over GF(2^8). 21 // 22 // Each data byte becomes the coefficient of an x term. 23 // 24 // For an n byte input the polynomial is: 25 // data[n-1]*(x^n-1) + data[n-2]*(x^n-2) ... + data[0]*(x^0). 26 func newGFPolyFromData(data *bitset.Bitset) gfPoly { 27 numTotalBytes := data.Len() / 8 28 if data.Len()%8 != 0 { 29 numTotalBytes++ 30 } 31 32 result := gfPoly{term: make([]gfElement, numTotalBytes)} 33 34 i := numTotalBytes - 1 35 for j := 0; j < data.Len(); j += 8 { 36 result.term[i] = gfElement(data.ByteAt(j)) 37 i-- 38 } 39 40 return result 41 } 42 43 // newGFPolyMonomial returns term*(x^degree). 44 func newGFPolyMonomial(term gfElement, degree int) gfPoly { 45 if term == gfZero { 46 return gfPoly{} 47 } 48 49 result := gfPoly{term: make([]gfElement, degree+1)} 50 result.term[degree] = term 51 52 return result 53 } 54 55 func (e gfPoly) data(numTerms int) []byte { 56 result := make([]byte, numTerms) 57 58 i := numTerms - len(e.term) 59 for j := len(e.term) - 1; j >= 0; j-- { 60 result[i] = byte(e.term[j]) 61 i++ 62 } 63 64 return result 65 } 66 67 // numTerms returns the number of 68 func (e gfPoly) numTerms() int { 69 return len(e.term) 70 } 71 72 // gfPolyMultiply returns a * b. 73 func gfPolyMultiply(a, b gfPoly) gfPoly { 74 numATerms := a.numTerms() 75 numBTerms := b.numTerms() 76 77 result := gfPoly{term: make([]gfElement, numATerms+numBTerms)} 78 79 for i := 0; i < numATerms; i++ { 80 for j := 0; j < numBTerms; j++ { 81 if a.term[i] != 0 && b.term[j] != 0 { 82 monomial := gfPoly{term: make([]gfElement, i+j+1)} 83 monomial.term[i+j] = gfMultiply(a.term[i], b.term[j]) 84 85 result = gfPolyAdd(result, monomial) 86 } 87 } 88 } 89 90 return result.normalised() 91 } 92 93 // gfPolyRemainder return the remainder of numerator / denominator. 94 func gfPolyRemainder(numerator, denominator gfPoly) gfPoly { 95 if denominator.equals(gfPoly{}) { 96 log.Panicln("Remainder by zero") 97 } 98 99 remainder := numerator 100 101 for remainder.numTerms() >= denominator.numTerms() { 102 degree := remainder.numTerms() - denominator.numTerms() 103 coefficient := gfDivide(remainder.term[remainder.numTerms()-1], 104 denominator.term[denominator.numTerms()-1]) 105 106 divisor := gfPolyMultiply(denominator, 107 newGFPolyMonomial(coefficient, degree)) 108 109 remainder = gfPolyAdd(remainder, divisor) 110 } 111 112 return remainder.normalised() 113 } 114 115 // gfPolyAdd returns a + b. 116 func gfPolyAdd(a, b gfPoly) gfPoly { 117 numATerms := a.numTerms() 118 numBTerms := b.numTerms() 119 120 numTerms := numATerms 121 if numBTerms > numTerms { 122 numTerms = numBTerms 123 } 124 125 result := gfPoly{term: make([]gfElement, numTerms)} 126 127 for i := 0; i < numTerms; i++ { 128 switch { 129 case numATerms > i && numBTerms > i: 130 result.term[i] = gfAdd(a.term[i], b.term[i]) 131 case numATerms > i: 132 result.term[i] = a.term[i] 133 default: 134 result.term[i] = b.term[i] 135 } 136 } 137 138 return result.normalised() 139 } 140 141 func (e gfPoly) normalised() gfPoly { 142 numTerms := e.numTerms() 143 maxNonzeroTerm := numTerms - 1 144 145 for i := numTerms - 1; i >= 0; i-- { 146 if e.term[i] != 0 { 147 break 148 } 149 150 maxNonzeroTerm = i - 1 151 } 152 153 if maxNonzeroTerm < 0 { 154 return gfPoly{} 155 } else if maxNonzeroTerm < numTerms-1 { 156 e.term = e.term[0 : maxNonzeroTerm+1] 157 } 158 159 return e 160 } 161 162 func (e gfPoly) string(useIndexForm bool) string { 163 var str string 164 numTerms := e.numTerms() 165 166 for i := numTerms - 1; i >= 0; i-- { 167 if e.term[i] > 0 { 168 if len(str) > 0 { 169 str += " + " 170 } 171 172 if !useIndexForm { 173 str += fmt.Sprintf("%dx^%d", e.term[i], i) 174 } else { 175 str += fmt.Sprintf("a^%dx^%d", gfLogTable[e.term[i]], i) 176 } 177 } 178 } 179 180 if len(str) == 0 { 181 str = "0" 182 } 183 184 return str 185 } 186 187 // equals returns true if e == other. 188 func (e gfPoly) equals(other gfPoly) bool { 189 var minecPoly *gfPoly 190 var maxecPoly *gfPoly 191 192 if e.numTerms() > other.numTerms() { 193 minecPoly = &other 194 maxecPoly = &e 195 } else { 196 minecPoly = &e 197 maxecPoly = &other 198 } 199 200 numMinTerms := minecPoly.numTerms() 201 numMaxTerms := maxecPoly.numTerms() 202 203 for i := 0; i < numMinTerms; i++ { 204 if e.term[i] != other.term[i] { 205 return false 206 } 207 } 208 209 for i := numMinTerms; i < numMaxTerms; i++ { 210 if maxecPoly.term[i] != 0 { 211 return false 212 } 213 } 214 215 return true 216 }