Mercurial > vim
comparison src/evalfunc.c @ 18732:2513e666aa82 v8.1.2356
patch 8.1.2356: rand() does not use the best algorithm
Commit: https://github.com/vim/vim/commit/f8c1f9200c4b50969a8191a4fe0b0d09edb38979
Author: Bram Moolenaar <Bram@vim.org>
Date: Thu Nov 28 22:13:14 2019 +0100
patch 8.1.2356: rand() does not use the best algorithm
Problem: rand() does not use the best algorithm.
Solution: use xoshiro128** instead of xorshift. (Kaito Udagawa,
closes #5279)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 28 Nov 2019 22:15:04 +0100 |
parents | aef98a646d3e |
children | e0cd10f750e7 |
comparison
equal
deleted
inserted
replaced
18731:e55bced76a31 | 18732:2513e666aa82 |
---|---|
5137 */ | 5137 */ |
5138 static void | 5138 static void |
5139 f_rand(typval_T *argvars, typval_T *rettv) | 5139 f_rand(typval_T *argvars, typval_T *rettv) |
5140 { | 5140 { |
5141 list_T *l = NULL; | 5141 list_T *l = NULL; |
5142 UINT32_T x, y, z, w, t; | 5142 static list_T *globl = NULL; |
5143 static int rand_seed_initialized = FALSE; | 5143 UINT32_T x, y, z, w, t, result; |
5144 static UINT32_T xyzw[4] = {123456789, 362436069, 521288629, 88675123}; | 5144 listitem_T *lx, *ly, *lz, *lw; |
5145 | |
5146 #define SHUFFLE_XORSHIFT128 \ | |
5147 t = x ^ (x << 11); \ | |
5148 x = y; y = z; z = w; \ | |
5149 w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); | |
5150 | 5145 |
5151 if (argvars[0].v_type == VAR_UNKNOWN) | 5146 if (argvars[0].v_type == VAR_UNKNOWN) |
5152 { | 5147 { |
5153 // When argument is not given, return random number initialized | 5148 // When no argument is given use the global seed list. |
5154 // statically. | 5149 if (globl == NULL) |
5155 if (!rand_seed_initialized) | 5150 { |
5156 { | 5151 // Initialize the global seed list. |
5157 xyzw[0] = (varnumber_T)time(NULL); | 5152 f_srand(argvars, rettv); |
5158 rand_seed_initialized = TRUE; | 5153 l = rettv->vval.v_list; |
5159 } | 5154 if (l == NULL || list_len(l) != 4) |
5160 | 5155 { |
5161 x = xyzw[0]; | 5156 clear_tv(rettv); |
5162 y = xyzw[1]; | 5157 goto theend; |
5163 z = xyzw[2]; | 5158 } |
5164 w = xyzw[3]; | 5159 globl = l; |
5165 SHUFFLE_XORSHIFT128; | 5160 } |
5166 xyzw[0] = x; | 5161 else |
5167 xyzw[1] = y; | 5162 l = globl; |
5168 xyzw[2] = z; | |
5169 xyzw[3] = w; | |
5170 } | 5163 } |
5171 else if (argvars[0].v_type == VAR_LIST) | 5164 else if (argvars[0].v_type == VAR_LIST) |
5172 { | 5165 { |
5173 listitem_T *lx, *ly, *lz, *lw; | |
5174 | |
5175 l = argvars[0].vval.v_list; | 5166 l = argvars[0].vval.v_list; |
5176 if (list_len(l) != 4) | 5167 if (l == NULL || list_len(l) != 4) |
5177 goto theend; | 5168 goto theend; |
5178 | |
5179 lx = list_find(l, 0L); | |
5180 ly = list_find(l, 1L); | |
5181 lz = list_find(l, 2L); | |
5182 lw = list_find(l, 3L); | |
5183 if (lx->li_tv.v_type != VAR_NUMBER) goto theend; | |
5184 if (ly->li_tv.v_type != VAR_NUMBER) goto theend; | |
5185 if (lz->li_tv.v_type != VAR_NUMBER) goto theend; | |
5186 if (lw->li_tv.v_type != VAR_NUMBER) goto theend; | |
5187 x = (UINT32_T)lx->li_tv.vval.v_number; | |
5188 y = (UINT32_T)ly->li_tv.vval.v_number; | |
5189 z = (UINT32_T)lz->li_tv.vval.v_number; | |
5190 w = (UINT32_T)lw->li_tv.vval.v_number; | |
5191 SHUFFLE_XORSHIFT128; | |
5192 lx->li_tv.vval.v_number = (varnumber_T)x; | |
5193 ly->li_tv.vval.v_number = (varnumber_T)y; | |
5194 lz->li_tv.vval.v_number = (varnumber_T)z; | |
5195 lw->li_tv.vval.v_number = (varnumber_T)w; | |
5196 } | 5169 } |
5197 else | 5170 else |
5198 goto theend; | 5171 goto theend; |
5199 | 5172 |
5173 lx = list_find(l, 0L); | |
5174 ly = list_find(l, 1L); | |
5175 lz = list_find(l, 2L); | |
5176 lw = list_find(l, 3L); | |
5177 if (lx->li_tv.v_type != VAR_NUMBER) goto theend; | |
5178 if (ly->li_tv.v_type != VAR_NUMBER) goto theend; | |
5179 if (lz->li_tv.v_type != VAR_NUMBER) goto theend; | |
5180 if (lw->li_tv.v_type != VAR_NUMBER) goto theend; | |
5181 x = (UINT32_T)lx->li_tv.vval.v_number; | |
5182 y = (UINT32_T)ly->li_tv.vval.v_number; | |
5183 z = (UINT32_T)lz->li_tv.vval.v_number; | |
5184 w = (UINT32_T)lw->li_tv.vval.v_number; | |
5185 | |
5186 // SHUFFLE_XOSHIRO128STARSTAR | |
5187 #define ROTL(x, k) ((x << k) | (x >> (32 - k))) | |
5188 result = ROTL(y * 5, 7) * 9; | |
5189 t = y << 9; | |
5190 z ^= x; | |
5191 w ^= y; | |
5192 y ^= z, x ^= w; | |
5193 z ^= t; | |
5194 w = ROTL(w, 11); | |
5195 #undef ROTL | |
5196 | |
5197 lx->li_tv.vval.v_number = (varnumber_T)x; | |
5198 ly->li_tv.vval.v_number = (varnumber_T)y; | |
5199 lz->li_tv.vval.v_number = (varnumber_T)z; | |
5200 lw->li_tv.vval.v_number = (varnumber_T)w; | |
5201 | |
5200 rettv->v_type = VAR_NUMBER; | 5202 rettv->v_type = VAR_NUMBER; |
5201 rettv->vval.v_number = (varnumber_T)w; | 5203 rettv->vval.v_number = (varnumber_T)result; |
5202 return; | 5204 return; |
5203 | 5205 |
5204 theend: | 5206 theend: |
5205 semsg(_(e_invarg2), tv_get_string(&argvars[0])); | 5207 semsg(_(e_invarg2), tv_get_string(&argvars[0])); |
5208 rettv->v_type = VAR_NUMBER; | |
5209 rettv->vval.v_number = -1; | |
5206 } | 5210 } |
5207 | 5211 |
5208 /* | 5212 /* |
5209 * "range()" function | 5213 * "range()" function |
5210 */ | 5214 */ |
7094 */ | 7098 */ |
7095 static void | 7099 static void |
7096 f_srand(typval_T *argvars, typval_T *rettv) | 7100 f_srand(typval_T *argvars, typval_T *rettv) |
7097 { | 7101 { |
7098 static int dev_urandom_state = -1; // FAIL or OK once tried | 7102 static int dev_urandom_state = -1; // FAIL or OK once tried |
7103 UINT32_T x = 0, z; | |
7099 | 7104 |
7100 if (rettv_list_alloc(rettv) == FAIL) | 7105 if (rettv_list_alloc(rettv) == FAIL) |
7101 return; | 7106 return; |
7102 if (argvars[0].v_type == VAR_UNKNOWN) | 7107 if (argvars[0].v_type == VAR_UNKNOWN) |
7103 { | 7108 { |
7121 != sizeof(UINT32_T)) | 7126 != sizeof(UINT32_T)) |
7122 dev_urandom_state = FAIL; | 7127 dev_urandom_state = FAIL; |
7123 else | 7128 else |
7124 { | 7129 { |
7125 dev_urandom_state = OK; | 7130 dev_urandom_state = OK; |
7126 list_append_number(rettv->vval.v_list, | 7131 x = buf.cont.number; |
7127 (varnumber_T)buf.cont.number); | |
7128 } | 7132 } |
7129 close(fd); | 7133 close(fd); |
7130 } | 7134 } |
7131 | 7135 |
7132 } | 7136 } |
7133 if (dev_urandom_state != OK) | 7137 if (dev_urandom_state != OK) |
7134 // Reading /dev/urandom doesn't work, fall back to time(). | 7138 // Reading /dev/urandom doesn't work, fall back to time(). |
7135 list_append_number(rettv->vval.v_list, (varnumber_T)vim_time()); | 7139 x = vim_time(); |
7136 } | 7140 } |
7137 else | 7141 else |
7138 { | 7142 { |
7139 int error = FALSE; | 7143 int error = FALSE; |
7140 UINT32_T x = (UINT32_T)tv_get_number_chk(&argvars[0], &error); | 7144 |
7141 | 7145 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error); |
7142 if (error) | 7146 if (error) |
7143 return; | 7147 return; |
7144 | 7148 } |
7145 list_append_number(rettv->vval.v_list, (varnumber_T)x); | 7149 |
7146 } | 7150 #define SPLITMIX32 ( \ |
7147 list_append_number(rettv->vval.v_list, 362436069); | 7151 z = (x += 0x9e3779b9), \ |
7148 list_append_number(rettv->vval.v_list, 521288629); | 7152 z = (z ^ (z >> 16)) * 0x85ebca6b, \ |
7149 list_append_number(rettv->vval.v_list, 88675123); | 7153 z = (z ^ (z >> 13)) * 0xc2b2ae35, \ |
7154 z ^ (z >> 16) \ | |
7155 ) | |
7156 | |
7157 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); | |
7158 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); | |
7159 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); | |
7160 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32); | |
7150 } | 7161 } |
7151 | 7162 |
7152 /* | 7163 /* |
7153 * "str2float()" function | 7164 * "str2float()" function |
7154 */ | 7165 */ |