Skip to content

Commit 2c6ffa3

Browse files
authored
Merge pull request #444 from vim-jp/fix-for-64bit-number
Fix for 64bit number
2 parents 20bcbd2 + 83dac78 commit 2c6ffa3

File tree

8 files changed

+297
-92
lines changed

8 files changed

+297
-92
lines changed

autoload/vital/__vital__/Bitwise.vim

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44
let s:save_cpo = &cpo
55
set cpo&vim
66

7+
let s:bits = has('num64') ? 64 : 32
8+
let s:mask = s:bits - 1
9+
let s:mask32 = 32 - 1
10+
11+
let s:pow2 = [1]
12+
for s:i in range(s:mask)
13+
call add(s:pow2, s:pow2[-1] * 2)
14+
endfor
15+
unlet s:i
16+
17+
let s:min = s:pow2[-1]
18+
719
" compare as unsigned int
820
function! s:compare(a, b) abort
921
if (a:a >= 0 && a:b >= 0) || (a:a < 0 && a:b < 0)
@@ -14,34 +26,52 @@ function! s:compare(a, b) abort
1426
endfunction
1527

1628
function! s:lshift(a, n) abort
17-
return a:a * s:pow2[s:and(a:n, 0x1F)]
29+
return a:a * s:pow2[s:and(a:n, s:mask)]
1830
endfunction
1931

2032
function! s:rshift(a, n) abort
21-
let n = s:and(a:n, 0x1F)
33+
let n = s:and(a:n, s:mask)
2234
return n == 0 ? a:a :
23-
\ a:a < 0 ? (a:a - 0x80000000) / s:pow2[n] + 0x40000000 / s:pow2[n - 1]
35+
\ a:a < 0 ? (a:a - s:min) / s:pow2[n] + s:pow2[-2] / s:pow2[n - 1]
2436
\ : a:a / s:pow2[n]
2537
endfunction
2638

27-
let s:pow2 = [
28-
\ 0x1, 0x2, 0x4, 0x8,
29-
\ 0x10, 0x20, 0x40, 0x80,
30-
\ 0x100, 0x200, 0x400, 0x800,
31-
\ 0x1000, 0x2000, 0x4000, 0x8000,
32-
\ 0x10000, 0x20000, 0x40000, 0x80000,
33-
\ 0x100000, 0x200000, 0x400000, 0x800000,
34-
\ 0x1000000, 0x2000000, 0x4000000, 0x8000000,
35-
\ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
36-
\ ]
39+
if has('num64')
40+
function! s:sign_extension(n) abort
41+
if and(a:n, 0x80000000)
42+
return or(a:n, 0xFFFFFFFF00000000)
43+
else
44+
return and(a:n, 0xFFFFFFFF)
45+
endif
46+
endfunction
47+
function! s:lshift32(a, n) abort
48+
return and(s:lshift(a:a, and(a:n, s:mask32)), 0xFFFFFFFF)
49+
endfunction
50+
function! s:rshift32(a, n) abort
51+
return s:rshift(and(a:a, 0xFFFFFFFF), and(a:n, s:mask32))
52+
endfunction
53+
else
54+
function! s:sign_extension(n) abort
55+
return a:n
56+
endfunction
57+
endif
58+
3759

38-
if exists('*and')
39-
function! s:_vital_created(module) abort
60+
let s:builtin_functions_exist = exists('*and')
61+
function! s:_vital_created(module) abort
62+
if s:builtin_functions_exist
4063
for op in ['and', 'or', 'xor', 'invert']
4164
let a:module[op] = function(op)
4265
let s:[op] = a:module[op]
4366
endfor
44-
endfunction
67+
endif
68+
if !has('num64')
69+
let a:module.lshift32 = a:module.lshift
70+
let a:module.rshift32 = a:module.rshift
71+
endif
72+
endfunction
73+
74+
if s:builtin_functions_exist
4575
finish
4676
endif
4777

@@ -51,8 +81,8 @@ function! s:invert(a) abort
5181
endfunction
5282

5383
function! s:and(a, b) abort
54-
let a = a:a < 0 ? a:a - 0x80000000 : a:a
55-
let b = a:b < 0 ? a:b - 0x80000000 : a:b
84+
let a = a:a < 0 ? a:a - s:min : a:a
85+
let b = a:b < 0 ? a:b - s:min : a:b
5686
let r = 0
5787
let n = 1
5888
while a && b
@@ -62,14 +92,14 @@ function! s:and(a, b) abort
6292
let n = n * 0x10
6393
endwhile
6494
if (a:a < 0) && (a:b < 0)
65-
let r += 0x80000000
95+
let r += s:min
6696
endif
6797
return r
6898
endfunction
6999

70100
function! s:or(a, b) abort
71-
let a = a:a < 0 ? a:a - 0x80000000 : a:a
72-
let b = a:b < 0 ? a:b - 0x80000000 : a:b
101+
let a = a:a < 0 ? a:a - s:min : a:a
102+
let b = a:b < 0 ? a:b - s:min : a:b
73103
let r = 0
74104
let n = 1
75105
while a || b
@@ -79,14 +109,14 @@ function! s:or(a, b) abort
79109
let n = n * 0x10
80110
endwhile
81111
if (a:a < 0) || (a:b < 0)
82-
let r += 0x80000000
112+
let r += s:min
83113
endif
84114
return r
85115
endfunction
86116

87117
function! s:xor(a, b) abort
88-
let a = a:a < 0 ? a:a - 0x80000000 : a:a
89-
let b = a:b < 0 ? a:b - 0x80000000 : a:b
118+
let a = a:a < 0 ? a:a - s:min : a:a
119+
let b = a:b < 0 ? a:b - s:min : a:b
90120
let r = 0
91121
let n = 1
92122
while a || b
@@ -96,7 +126,7 @@ function! s:xor(a, b) abort
96126
let n = n * 0x10
97127
endwhile
98128
if (a:a < 0) != (a:b < 0)
99-
let r += 0x80000000
129+
let r += s:min
100130
endif
101131
return r
102132
endfunction

autoload/vital/__vital__/Random/Mt19937ar.vim

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,21 @@ function! s:Generator.seed(seeds) abort
7575
call s:_init_by_array(self, a:seeds)
7676
endfunction
7777

78+
" 0x80000000 in 32bit and 0xFFFFFFFF80000000 in 64bit
7879
function! s:Generator.min() abort
79-
return 0x80000000
80+
return -2147483648
8081
endfunction
8182

83+
" 0x7FFFFFFF in 32bit/64bit
8284
function! s:Generator.max() abort
83-
return 0x7FFFFFFF
85+
return 2147483647
8486
endfunction
8587

8688
function! s:_init_genrand(g, s) abort
8789
let a:g._mt[0] = a:s
8890
let a:g._mti = 1
8991
while a:g._mti < a:g._N
90-
let a:g._mt[a:g._mti] = 1812433253 * s:B.xor(a:g._mt[a:g._mti-1], s:B.rshift(a:g._mt[a:g._mti-1], 30)) + a:g._mti
92+
let a:g._mt[a:g._mti] = 1812433253 * s:B.xor(a:g._mt[a:g._mti-1], s:B.rshift32(a:g._mt[a:g._mti-1], 30)) + a:g._mti
9193
let a:g._mti += 1
9294
endwhile
9395
endfunction
@@ -99,7 +101,7 @@ function! s:_init_by_array(g, init_key) abort
99101
let j = 0
100102
let k = a:g._N > key_length ? a:g._N : key_length
101103
while k
102-
let a:g._mt[i] = s:B.xor(a:g._mt[i], s:B.xor(a:g._mt[i-1], s:B.rshift(a:g._mt[i-1], 30)) * 1664525) + a:init_key[j] + j
104+
let a:g._mt[i] = s:B.xor(a:g._mt[i], s:B.xor(a:g._mt[i-1], s:B.rshift32(a:g._mt[i-1], 30)) * 1664525) + a:init_key[j] + j
103105
let i += 1
104106
let j += 1
105107
if i >= a:g._N
@@ -113,7 +115,7 @@ function! s:_init_by_array(g, init_key) abort
113115
endwhile
114116
let k = a:g._N - 1
115117
while k
116-
let a:g._mt[i] = s:B.xor(a:g._mt[i], s:B.xor(a:g._mt[i-1], s:B.rshift(a:g._mt[i-1], 30)) * 1566083941) - i
118+
let a:g._mt[i] = s:B.xor(a:g._mt[i], s:B.xor(a:g._mt[i-1], s:B.rshift32(a:g._mt[i-1], 30)) * 1566083941) - i
117119
let i += 1
118120
if i >= a:g._N
119121
let a:g._mt[0] = a:g._mt[a:g._N-1]
@@ -136,29 +138,29 @@ function! s:Generator.next() abort
136138
let kk = 0
137139
while kk < self._N - self._M
138140
let y = s:B.or(s:B.and(self._mt[kk], self._UPPER_MASK), s:B.and(self._mt[kk+1], self._LOWER_MASK))
139-
let self._mt[kk] = s:B.xor(s:B.xor(self._mt[kk+self._M], s:B.rshift(y, 1)), mag01[y % 2])
141+
let self._mt[kk] = s:B.xor(s:B.xor(self._mt[kk+self._M], s:B.rshift32(y, 1)), mag01[y % 2])
140142
let kk += 1
141143
endwhile
142144
while kk < self._N - 1
143145
let y = s:B.or(s:B.and(self._mt[kk], self._UPPER_MASK), s:B.and(self._mt[kk+1], self._LOWER_MASK))
144-
let self._mt[kk] = s:B.xor(s:B.xor(self._mt[kk+(self._M-self._N)], s:B.rshift(y, 1)), mag01[y % 2])
146+
let self._mt[kk] = s:B.xor(s:B.xor(self._mt[kk+(self._M-self._N)], s:B.rshift32(y, 1)), mag01[y % 2])
145147
let kk += 1
146148
endwhile
147149
let y = s:B.or(s:B.and(self._mt[self._N-1], self._UPPER_MASK), s:B.and(self._mt[0], self._LOWER_MASK))
148-
let self._mt[self._N-1] = s:B.xor(s:B.xor(self._mt[self._M-1], s:B.rshift(y, 1)), mag01[y % 2])
150+
let self._mt[self._N-1] = s:B.xor(s:B.xor(self._mt[self._M-1], s:B.rshift32(y, 1)), mag01[y % 2])
149151

150152
let self._mti = 0
151153
endif
152154

153155
let y = self._mt[self._mti]
154156
let self._mti += 1
155157

156-
let y = s:B.xor(y, s:B.rshift(y, 11))
158+
let y = s:B.xor(y, s:B.rshift32(y, 11))
157159
let y = s:B.xor(y, s:B.and(s:B.lshift(y, 7), 0x9d2c5680))
158160
let y = s:B.xor(y, s:B.and(s:B.lshift(y, 15), 0xefc60000))
159-
let y = s:B.xor(y, s:B.rshift(y, 18))
161+
let y = s:B.xor(y, s:B.rshift32(y, 18))
160162

161-
return y
163+
return s:B.sign_extension(y)
162164
endfunction
163165

164166
function! s:new_generator() abort

autoload/vital/__vital__/Random/Xor128.vim

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,18 @@ function! s:Generator.next() abort
2222
let self._x = self._y
2323
let self._y = self._z
2424
let self._z = self._w
25-
let self._w = s:B.xor(s:B.xor(w, s:B.rshift(w, 19)), s:B.xor(t, s:B.rshift(t, 8)))
26-
return self._w
25+
let self._w = s:B.xor(s:B.xor(w, s:B.rshift32(w, 19)), s:B.xor(t, s:B.rshift32(t, 8)))
26+
return s:B.sign_extension(self._w)
2727
endfunction
2828

29+
" 0x80000000 in 32bit and 0xFFFFFFFF80000000 in 64bit
2930
function! s:Generator.min() abort
30-
return 0x80000000
31+
return -2147483648
3132
endfunction
3233

34+
" 0x7FFFFFFF in 32bit/64bit
3335
function! s:Generator.max() abort
34-
return 0x7FFFFFFF
36+
return 2147483647
3537
endfunction
3638

3739
function! s:Generator.seed(seeds) abort

doc/vital-bitwise.txt

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,34 @@ invert({expr}) *Vital.Bitwise.invert()*
3838
Bitwise invert.
3939

4040
lshift({expr}, {bits}) *Vital.Bitwise.lshift()*
41-
Bitwise shifts to left. {bits} is masked by 0x1F.
41+
Bitwise shifts to left. {bits} is masked by 0x1F or 0x3F(|+num64|).
4242

4343
rshift({expr}, {bits}) *Vital.Bitwise.rshift()*
44-
Bitwise shifts to right. {bits} is masked by 0x1F.
44+
Bitwise logical shifts to right. {bits} is masked by 0x1F or
45+
0x3F(|+num64|).
4546

4647
compare({expr}, {expr}) *Vital.Bitwise.compare()*
4748
Compares as unsigned integer. Returns -1, 0, or 1.
4849

50+
sign_extension({expr}) *Vital.Bitwise.sign_extension()*
51+
Apply sign extension to {expr}.
52+
This reappears 32bit number in |+num64| environment.
53+
With |+num64|, when the 32nd bit is 0, upper 32bits are filled by 0.
54+
Otherwise, it is filled by 1.
55+
Without |+num64|, returns {expr}.
56+
Example(with |+num64|): >
57+
echo B.sign_extension(4294967295)
58+
" => -1
59+
" 4294967295 == 0xFFFFFFFF
60+
" -1 == 0xFFFFFFFFFFFFFFFF
61+
62+
lshift32({expr}, {bits}) *Vital.Bitwise.lshift32()*
63+
Similar to |Vital.Bitwise.lshift()|, but always treats 32bit number.
64+
With |+num64|, upper 32bits of results are always 0.
65+
66+
rshift32({expr}, {bits}) *Vital.Bitwise.rshift32()*
67+
Similar to |Vital.Bitwise.rshift()|, but always treats 32bit number.
68+
With |+num64|, upper 32bits of {expr} is ignored.
4969

5070

5171
==============================================================================

doc/vital-random-mt19937ar.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ imported from the implementation.
2525

2626
https://github.com/ynkdir/vim-funlib/blob/master/autoload/random/mt19937ar.vim
2727

28+
This implementation always generates 32bit number [-2147483648, 2147483647],
29+
even when you use Vim with |+num64|.
30+
2831
>
2932
let s:V = vital#of("vital")
3033
let s:M = s:V.import("Random.Mt19937ar")

doc/vital-random-xor128.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ INTRODUCTION *Vital.Random.Xor128-introduction*
1818
xorshift algorithm. Although xorshift has a reasonable period (2^128-1), it
1919
is fast and has less internal states.
2020
The paper about xorshift is http://www.jstatsoft.org/v08/i14/paper .
21+
This implementation always generates 32bit number [-2147483648, 2147483647],
22+
even when you use Vim with |+num64|.
2123

2224
>
2325
let s:V = vital#of("vital")

0 commit comments

Comments
 (0)