코딩 공부/공부

산술부호화 압축 알고리즘

fullfish 2023. 1. 20. 14:46
function makeObj() {
  let num = 0
  let obj = {}
  for (let i = 65; i <= 122; i++) {
    if (!(i > 90 && 97 > i))
      obj[String.fromCharCode(i)] = [Math.round(num * 10000) / 10000, Math.round((Math.round((num += 0.018) * 10000) / 10000 - 0.0001) * 10000) / 10000]
  }
  obj[' '] = [0.936, 0.9539]
  obj['end'] = [0.954, 1]
  return obj
}
function compression(str) {
  let obj = makeObj()
  let compressionRange = [0, 1]
  let num_2 = '0.'
  for (let i = 0; i < str.length; i++) {
    const sub = subFun(compressionRange[1], compressionRange[0])
    compressionRange[1] = rangeFun(compressionRange[0], sub, obj[str[i]][1])
    compressionRange[0] = rangeFun(compressionRange[0], sub, obj[str[i]][0])
  }
  const sub = subFun(compressionRange[1], compressionRange[0])
  compressionRange[1] = rangeFun(compressionRange[0], sub, obj['end'][1])
  compressionRange[0] = rangeFun(compressionRange[0], sub, obj['end'][0])
  while (!(compressionRange[0] <= binaryStrToDecimalNum(num_2) && binaryStrToDecimalNum(num_2) <= compressionRange[1])) {
    if (compressionRange[1] < binaryStrToDecimalNum(num_2 + '1')) num_2 += '0'
    else num_2 += '1'
  }
  return num_2
}
function decompress(binaryStr) {
  let obj = makeObj()
  let decompressRange = [0, 1]
  let finish = false
  let result = ''
  const decimalNum = binaryStrToDecimalNum(binaryStr)
  while (!finish) {
    for (let key in obj) {
      let copyDecryptRange = decompressRange.slice()
      const sub = copyDecryptRange[1] - copyDecryptRange[0]
      copyDecryptRange[1] = rangeFun(copyDecryptRange[0], sub, obj[key][1])
      copyDecryptRange[0] = rangeFun(copyDecryptRange[0], sub, obj[key][0])
      if (copyDecryptRange[0] <= decimalNum && decimalNum <= copyDecryptRange[1]) {
        decompressRange = copyDecryptRange
        if (key === 'end') finish = true
        else result += key
        break
      }
    }
  }
  return result
}
function binaryStrToDecimalNum(binaryStr) {
  let result = 0
  let underNum = binaryStr !== '0.' ? binaryStr.slice(2) : '0'
  for (let i = 0; i < underNum.length; i++) {
    if (underNum[i] === '1') result += 0.5 ** (i + 1)
  }
  return result
}
function rangeFun(range0, sub, objKey) {
  let decimalRange0Lenght = Number.isInteger(range0) ? 0 : String(range0).length - 2,
    decimalSubLenght = Number.isInteger(sub) ? 0 : String(sub).length - 2,
    decimalObjKeyLenght = Number.isInteger(objKey) ? 0 : String(objKey).length - 2
  let longLenght = Math.max(decimalRange0Lenght, decimalSubLenght + decimalObjKeyLenght)
  return Math.round((range0 + sub * objKey) * 10 ** longLenght) / 10 ** longLenght
}
function subFun(a, b) {
  let decimalALenght = Number.isInteger(a) ? 0 : String(a).length - 2,
    decimalBLenght = Number.isInteger(b) ? 0 : String(b).length - 2
  let longLenght = Math.max(decimalALenght, decimalBLenght)
  return Math.round((a - b) * 10 ** longLenght) / 10 ** longLenght
}

function compressionArr(str) {
  let compressionedArr = []
  for (let i = 0; i < str.length; i += 6) {
    compressionedArr.push(compression(str.slice(i, i + 6)))
  }
  return compressionedArr
}
function decompressArr(arr) {
  let decompressed = ''
  arr.forEach(e => {
    decompressed += decompress(e)
  })
  return decompressed
}
let compressioned = compressionArr('Hi my name is ChoiManSeon')
console.log(compressioned)
let decompressed = decompressArr(compressioned)
console.log(decompressed)
//!
// let compressioned = compression('manseon')
// console.log('compressioned', compressioned)
// let decompressed = decompress(compressioned)
// console.log('decompressed', decompressed)

 

문제점
현재 코드가 6글자씩 잘라서 압축을 하고 있는데 그 보다 더 많은 글자를 압축하면 깨진다

그 이유는 js의 경우 소수점 16번째까지만 표현이 되기때문에 더 이상 압축이 안된다

또한 현재 압축되서 나오는 값이 

[
  '0.001000110010001101100011001101010100011',
  '0.10110101111010011101101000111000010011',
  '0.1100111100001011100000110011001001101001',
  '0.0011100101111111110100111001001011101111',
  '0.1011100001'
]

이렇게 나오는데 문자열이라서 용량이 더 큰건지.. 이진수로 읽혀서 작은지 잘 모르겠다

그렇다고 Number을 씌우면

Number('0.001000110010001101100011001101010100011')
-> 
0.001000110010001101

뒤가 잘려버린다 js는 산술부호화압축에 쓰기 적합하지않아보인다

 

참고

https://ko.wikipedia.org/wiki/%EC%82%B0%EC%88%A0_%EB%B6%80%ED%98%B8%ED%99%94

 

산술 부호화 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 산술 부호화(算術符號化, 영어: Arithmetic coding)는 무손실 압축에 사용되는 엔트로피 부호화 알고리즘 가운데 하나이다. 다른 엔트로피 부호화 알고리즘이 각각

ko.wikipedia.org

 

'코딩 공부 > 공부' 카테고리의 다른 글

docker  (0) 2022.10.03
nginx  (0) 2022.10.03
nodemailer를 이용한 mail보내기  (0) 2022.06.08
환경변수 사용법 (react, webpack, aws)  (0) 2022.06.02
**연산자에대한 고찰  (1) 2022.05.31