Created
March 16, 2012 09:02
-
-
Save s-yukikaze/2049225 to your computer and use it in GitHub Desktop.
64bit unsigned integer implementation@vim script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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