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 */