Skip to content

Instantly share code, notes, and snippets.

@s-yukikaze
Created March 16, 2012 09:02
Show Gist options
  • Save s-yukikaze/2049225 to your computer and use it in GitHub Desktop.
Save s-yukikaze/2049225 to your computer and use it in GitHub Desktop.
64bit unsigned integer implementation@vim script
function! uint64#unit()
let a = copy(s:UInt64).init(0x1234,0x56789ABC)
let b = copy(s:UInt64).init(0x8765,0x43210FED)
let c = a.add(b)
echo printf("%x%x", c._high, c._low)
let d = b.sub(a)
echo printf("%x%x", d._high, d._low)
let e = a.mul(b)
echo printf("%x%x", e._high, e._low)
endfunction
let s:UInt64 = {}
function! s:UInt64.init(...)"{{{
if a:0 == 0
self.initWithWords(0, 0)
elseif a:0 == 1
let vauint32_ltype = type(a:1)
if vauint32_ltype == "int"
self.initWithWords(0, a:1)
elseif vauint32_ltype == "string"
self.initWithString(a:1)
else
echoerr "Invalid argument type."
endif
elseif a:0 == 2
self.initWithWords(a:1, a:2)
else
echoerr "Invalid number of argument."
endif
return self
endfunction"}}}
function! s:UInt64.initWithWords(high, low)"{{{
self._high = a:high
self._low = a:low
endfunction"}}}
function! s:UInt64.initWithString(val)"{{{
if s =~ "^0x\x\+$"
" Hexadecimal
elseif s == "^\d\+$"
" Decimal
endif
endfunction"}}}
function! s:UInt64.add(rval)"{{{
let [low, carry] = s:uint32_add(self._low, a:rval._low)
let [high, carry] = s:uint32_add(self._high, a:rval._high, carry)
return copy(s:UInt64).init(high, low)
endfunction"}}}
function! s:UInt64.sub(rval)"{{{
let [low, borrow] = s:uint32_sub(self._low, a:rval._low)
let [high, borrow] = s:uint32_sub(self._high, a:rval._high, borrow)
return copy(s:UInt64).init(high, low)
endfunction"}}}
function! s:UInt64.mul(rval)"{{{
let l = self._as_words()
let r = a:rval._as_words()
let [a0, carry] = s:uint16_add(l[0] * r[0], 0)
let [a1, carry] = s:uint16_add(l[1] * r[0], l[0] * r[1], carry)
let [a2, carry] = s:uint16_add(l[2] * r[0], l[1] * r[1], l[0] * r[2], carry)
let [a3, carry] = s:uint16_add(l[3] * r[0], l[2] * r[1], l[1] * r[2], l[0] * r[3], carry)
let low = a0 + a1 * 0x10000
let high = a2 + a3 * 0x10000
return copy(s:UInt64).init(high, low)
endfunction"}}}
function! s:UInt64.divmod(rval)"{{{
if a:rval._high == 0 && a:rval._low == 0
throw "UInt64: divided by zero"
endif
if self.lt(a:rval)
return [copy(s:UInt64).init(0), copy(self)]
endif
let divisor = a:rval
let reminder = self
let shift = 0
let divisor_cache = [divisor]
" Normalize the divisor.
while divisor._high >= 0
let divisor = divisor.shl(1)
call add(divisor_cache, divisor)
let shift += 1
endwhile
" Do division.
while shift
let quotient = quotient.shl(1)
if divisor_cache[shift - 1].lt_eq(reminder)
let quotient = quotient.add_int(1)
let reminder = reminder.sub(divisor_cache[shift - 1])
endif
let shift -= 1
endwhile
return [
endfunction"}}}
function! s:UInt64.and(rval)"{{{
let high = and(self._high, a:rval._high)
let low = and(self._low, a:rval._low)
return copy(s:UInt64).init(high, low)
endfunction"}}}
function! s:UInt64.or(rval)"{{{
let high = or(self._high, a:rval._high)
let low = or(self._low, a:rval._low)
return copy(s:UInt64).init(high, low)
endfunction"}}}
function! s:UInt64.lt(rval)"{{{
return s:uint32_lt(this._high, a:rval._high) ? 1 :
\ s:uint32_lt(this._low, a:rval._low) ? 1 : 0
endfunction"}}}
function! s:UInt64.gt(rval)"{{{
return s:uint32_lt(a:rval._high, self._high) ? 1 :
\ s:uint32_lt(a:rval._low, self._low) ? 1 : 0
endfunction"}}}
function! s:UInt64._as_words()
return [
\ and(self._low, 0xFFFF), s:uint32_shr(self._low, 16),
\ and(self._high, 0xFFFF), s:uint32_shr(self._high, 16)
\]
endfunction"}}}
function! s:uint32_remove_msb(val)"{{{
return a:val < 0 ? [a:val + 0x80000000, 1] : [a:val, 0]
endfunction"}}}
function! s:uint32_lt(lval, rval)"{{{
let [lval, lmsb] = s:uint32_remove_msb(a:lval)
let [rval, rmsb] = s:uint32_remove_msb(a:rval)
return lmsb < rmsb ? 1 : lval < rval ? 1 : 0
endfunction"}}}
function! s:uint32_shl(val, shift)"{{{
return a:val * s:pow2[a:shift]
endfunction"}}}
function! s:uint32_shr(val, shift)"{{{
let [val, msb] = s:uint32_remove_msb(a:val)
return val / s:pow2[a:shift] + msb * s:pow2[31 - a:shift]
endfunction"}}}
let s:pow2 = [
\ 0x1, 0x2, 0x4, 0x8,
\ 0x10, 0x20, 0x40, 0x80,
\ 0x100, 0x200, 0x400, 0x800,
\ 0x1000, 0x2000, 0x4000, 0x8000,
\ 0x10000, 0x20000, 0x40000, 0x80000,
\ 0x100000, 0x20000, 0x400000, 0x800000,
\ 0x1000000, 0x2000000, 0x4000000, 0x8000000,
\ 0x10000000, 0x20000000, 0x40000000, 0x80000000
\]
function! s:uint16_add(...)"{{{
if a:0 == 2
let ans = a:1 + a:2
return [and(ans, 0xFFFF), s:uint32_shr(ans, 16)]
else
let [ans, carry1] = call("s:uint16_add", a:000[1:])
let [ans, carry2] = s:uint16_add(a:1, ans)
return [ans, carry1 + carry2]
endif
endfunction"}}}
function! s:uint32_add(...)"{{{
if a:0 == 2
let [a1, msb1] = s:uint32_remove_msb(a:1)
let [a2, msb2] = s:uint32_remove_msb(a:2)
let [ans, msb3] = s:uint32_remove_msb(a1 + a2)
let msb = msb1 + msb2 + msb3
let carry = s:uint32_shr(msb, 1)
let ans = ans + s:uint32_shl(and(msb, 1), 31)
return [ans, carry]
else
let [ans, carry1] = call("s:uint32_add", a:000[1:])
let [ans, carry2] = s:uint32_add(a:1, ans)
return [ans, carry1 + carry2]
endif
endfunction"}}}
function! s:uint32_sub(...)"{{{
if a:0 == 2
let borrow = s:uint32_lt(a:1, a:2) ? 1 : 0
return [a:1 - a:2, borrow]
else
let [ans, carry] = call("s:uint32_add", a:000[1:])
let [ans, borrow] = s:uint32_sub(a:1, ans)
return [ans, carry + borrow]
endif
endfunction"}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment