fork download
  1. /*
  2.  * Copyright (c) 2013, Ambroz Bizjak <ambrop7@gmail.com>
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright notice, this
  9.  * list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17.  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  18.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24.  */
  25.  
  26. /*
  27.  * Asymptotically efficient computation of a weighted sum of last N received numbers,
  28.  * with worst case time complexity O(sqrt(N*log(N))) per received number.
  29.  * See: http://c...content-available-to-author-only...e.com/questions/10612/weighted-sum-of-last-n-numbers/10670#10670
  30.  *
  31.  * Initialization:
  32.  * WSum state;
  33.  * WSum_Init(&state, number_of_weights, pointer_to_weights);
  34.  * The weights need to be specified in "reverse", meaning that the first weight
  35.  * applies to the most recent number.
  36.  *
  37.  * Operation:
  38.  * double current_wsum = WSum_AddNumber(&state, your_number);
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <complex.h>
  43. #include <string.h>
  44. #include <math.h>
  45. #include <assert.h>
  46. #include <stdlib.h>
  47.  
  48. /*
  49.  * Probably not the fastest FFT.
  50.  */
  51. static void fft_rec (int exp, double complex *data, double complex *temp, double complex rou)
  52. {
  53. if (exp == 0) {
  54. return;
  55. }
  56. size_t half = ((size_t)1) << (exp - 1);
  57. for (size_t i = 0; i < half; i++) {
  58. temp[i] = data[2 * i];
  59. temp[half + i] = data[2 * i + 1];
  60. }
  61. double complex rou_2 = rou * rou;
  62. fft_rec(exp - 1, temp, data, rou_2);
  63. fft_rec(exp - 1, temp + half, data, rou_2);
  64. double complex f = 1;
  65. for (size_t i = 0; i < half; i++) {
  66. data[i] = temp[i] + f * temp[half + i];
  67. data[half + i] = temp[i] - f * temp[half + i];
  68. f *= rou;
  69. }
  70. }
  71.  
  72. static void fft (int exp, double complex *data, double complex *temp)
  73. {
  74. size_t n = ((size_t)1) << exp;
  75. double complex rou = cexp(I * (-2 * 3.14159265358979323846 / n));
  76. fft_rec(exp, data, temp, rou);
  77. }
  78.  
  79. // Input: m weights, 2m-1 numbers.
  80. // Output: m sums, sums[i] = sum (k=0 to m-1) weights[k]*numbers[i+m-1-k]
  81. // This function implements everything FFT-related that the WSum code needs.
  82. static void compute_sums (size_t m, const double *weights, const double *numbers, double *sums)
  83. {
  84. int dft_exp = 0;
  85. size_t dft_n = 1;
  86. while (dft_n < 2 * m) {
  87. dft_exp++;
  88. dft_n *= 2;
  89. }
  90.  
  91. double complex *a = malloc(dft_n * sizeof(*a));
  92. double complex *b = malloc(dft_n * sizeof(*b));
  93. double complex *c = malloc(dft_n * sizeof(*c));
  94.  
  95. for (size_t i = 0; i < m; i++) {
  96. a[i] = weights[i];
  97. }
  98. for (size_t i = m; i < dft_n; i++) {
  99. a[i] = 0;
  100. }
  101.  
  102. for (size_t i = 0; i < 2 * m - 1; i++) {
  103. b[i] = numbers[i];
  104. }
  105. for (size_t i = 2 * m - 1; i < dft_n; i++) {
  106. b[i] = 0;
  107. }
  108.  
  109. fft(dft_exp, a, c);
  110. fft(dft_exp, b, c);
  111.  
  112. for (size_t i = 0; i < dft_n; i++) {
  113. c[i] = conj(a[i] * b[i]);
  114. }
  115.  
  116. fft(dft_exp, c, a);
  117.  
  118. for (size_t i = 0; i < m; i++) {
  119. sums[i] = creal(c[m - 1 + i]) / dft_n;
  120. }
  121.  
  122. free(c);
  123. free(b);
  124. free(a);
  125. }
  126.  
  127. typedef struct {
  128. size_t n;
  129. size_t pos;
  130. double *weights;
  131. double *inputs;
  132. } SimpleWSum;
  133.  
  134. void SimpleWSum_Init (SimpleWSum *o, size_t n, const double *weights)
  135. {
  136. assert(n > 0);
  137.  
  138. o->n = n;
  139. o->pos = n - 1;
  140. o->weights = malloc(n * sizeof(o->weights[0]));
  141. for (size_t i = 0; i < n; i++) {
  142. o->weights[i] = weights[i];
  143. }
  144. o->inputs = malloc(n * sizeof(o->inputs[0]));
  145. for (size_t i = 0; i < n; i++) {
  146. o->inputs[i] = 0;
  147. }
  148. }
  149.  
  150. void SimpleWSum_Free (SimpleWSum *o)
  151. {
  152. free(o->inputs);
  153. free(o->weights);
  154. }
  155.  
  156. double SimpleWSum_AddNumber (SimpleWSum *o, double x)
  157. {
  158. o->inputs[o->pos] = x;
  159.  
  160. size_t n_minus_pos = o->n - o->pos;
  161. double sum = 0;
  162. for (size_t i = 0; i < n_minus_pos; i++) {
  163. sum += o->weights[i] * o->inputs[o->pos + i];
  164. }
  165. for (size_t i = n_minus_pos; i < o->n; i++) {
  166. sum += o->weights[i] * o->inputs[i - n_minus_pos];
  167. }
  168.  
  169. if (o->pos == 0) {
  170. o->pos = o->n - 1;
  171. } else {
  172. o->pos--;
  173. }
  174.  
  175. return sum;
  176. }
  177.  
  178. typedef struct {
  179. size_t m;
  180. size_t n;
  181. size_t num_m;
  182. double *weights;
  183. double *inputs;
  184. double *sums;
  185. double *new_sums;
  186. size_t m_pos;
  187. size_t num_m_pos;
  188. } WSum;
  189.  
  190. void WSum_Init (WSum *o, size_t orig_n, const double *orig_weights)
  191. {
  192. assert(orig_n > 0);
  193.  
  194. // choose m
  195. o->m = sqrt(orig_n * log(orig_n));
  196. if (o->m == 0) {
  197. o->m = 1;
  198. } else if (o->m > orig_n) {
  199. o->m = orig_n;
  200. }
  201.  
  202. // choose n, taking care it's a multiple of m
  203. o->n = orig_n;
  204. if (o->n % o->m) {
  205. o->n += o->m - (o->n % o->m);
  206. }
  207. o->num_m = o->n / o->m;
  208.  
  209. // allocate and initialize weights
  210. o->weights = malloc((o->n + 1) * sizeof(o->weights[0]));
  211. for (size_t i = 0; i < orig_n; i++) {
  212. o->weights[i] = orig_weights[i];
  213. }
  214. for (size_t i = orig_n; i < o->n + 1; i++) {
  215. o->weights[i] = 0;
  216. }
  217.  
  218. // allocate and initialize inputs
  219. o->inputs = malloc((o->n + o->m) * sizeof(o->inputs[0]));
  220. for (size_t i = 0; i < o->n; i++) {
  221. o->inputs[i] = 0;
  222. }
  223.  
  224. // allocate and initialize sums
  225. o->sums = malloc(o->n * sizeof(o->sums[0]));
  226. o->new_sums = malloc(o->n * sizeof(o->new_sums[0]));
  227. for (size_t i = 0; i < o->n; i++) {
  228. o->sums[i] = 0;
  229. o->new_sums[i] = 0;
  230. }
  231.  
  232. o->m_pos = 0;
  233. o->num_m_pos = 0;
  234. }
  235.  
  236. void WSum_Free (WSum *o)
  237. {
  238. free(o->new_sums);
  239. free(o->sums);
  240. free(o->inputs);
  241. free(o->weights);
  242. }
  243.  
  244. double WSum_AddNumber (WSum *o, double x)
  245. {
  246. assert(o->m_pos < o->m);
  247.  
  248. double sum = 0;
  249.  
  250. // add from sums
  251. for (size_t i = 0; i < o->num_m; i++) {
  252. sum += o->sums[i * o->m + o->m_pos];
  253. }
  254.  
  255. // push this number to inputs
  256. o->inputs[o->n + o->m_pos] = x;
  257. o->m_pos++;
  258.  
  259. // add from pending inputs (incl. this number)
  260. for (size_t i = 0; i < o->m_pos; i++) {
  261. sum += o->inputs[o->n + i] * o->weights[o->m_pos - 1 - i];
  262. }
  263.  
  264. // decide up to which block we would like to update
  265. size_t end_update_pos = o->num_m * ((double)o->m_pos / o->m);
  266. if (o->m_pos == o->m) {
  267. end_update_pos = o->num_m; // don't assume any FP precision
  268. }
  269.  
  270. // cannot compute last two new_sums blocks unless we have the new inputs
  271. if (o->m_pos < o->m) {
  272. while (end_update_pos > 0 && end_update_pos >= o->num_m - 1) {
  273. end_update_pos--;
  274. }
  275. }
  276.  
  277. // compute new_sums blocks
  278. while (o->num_m_pos < end_update_pos) {
  279. if (o->num_m_pos == o->num_m - 1) {
  280. for (size_t j = 0; j < o->m; j++) {
  281. o->inputs[o->n + j] = 0;
  282. }
  283. } else {
  284. memcpy(o->inputs + (o->num_m_pos + 1) * o->m, o->inputs + (o->num_m_pos + 2) * o->m, o->m * sizeof(o->inputs[0]));
  285. }
  286. compute_sums(o->m, o->weights + (o->num_m - 1 - o->num_m_pos) * o->m + 1, o->inputs + o->num_m_pos * o->m, o->new_sums + o->num_m_pos * o->m);
  287. o->num_m_pos++;
  288. }
  289.  
  290. // switch at end of input block
  291. if (o->m_pos == o->m) {
  292. assert(o->num_m_pos == o->num_m);
  293. memcpy(o->inputs, o->inputs + o->m, o->m * sizeof(o->inputs[0]));
  294. double *old_sums = o->sums;
  295. o->sums = o->new_sums;
  296. o->new_sums = old_sums;
  297. o->m_pos = 0;
  298. o->num_m_pos = 0;
  299. }
  300.  
  301. return sum;
  302. }
  303.  
  304. static void test (size_t n, int num_iter, int use_wsum, int use_simple_wsum)
  305. {
  306. double *w = malloc(n * sizeof(w[0]));
  307. for (size_t i = 0; i < n; i++) {
  308. w[i] = (double)rand() / RAND_MAX;
  309. }
  310.  
  311. double dummy = 0; // prevent optimizations
  312.  
  313. WSum state;
  314. SimpleWSum simple_state;
  315. if (use_wsum) {
  316. WSum_Init(&state, n, w);
  317. printf("WSum m=%zu n=%zu num_m=%zu\n", state.m, state.n, state.num_m);
  318. }
  319. if (use_simple_wsum) {
  320. SimpleWSum_Init(&simple_state, n, w);
  321. }
  322.  
  323. for (int k = 0; k < num_iter; k++) {
  324. double x = rand();
  325.  
  326. double sum = 0;
  327. double simple_sum = 0;
  328. if (use_wsum) {
  329. sum = WSum_AddNumber(&state, x);
  330. }
  331. if (use_simple_wsum) {
  332. simple_sum = SimpleWSum_AddNumber(&simple_state, x);
  333. }
  334.  
  335. if (use_wsum && use_simple_wsum) {
  336. int failed = (fabs(sum - simple_sum) > 0.02);
  337. printf("%f %f %f %s\n", x, sum, simple_sum, (failed ? "FAILED" : "OK"));
  338. if (failed) {
  339. exit(1);
  340. }
  341. }
  342.  
  343. dummy += sum + simple_sum;
  344. }
  345.  
  346. printf("dummy %f\n", dummy);
  347.  
  348. if (use_simple_wsum) {
  349. SimpleWSum_Free(&simple_state);
  350. }
  351. if (use_wsum) {
  352. WSum_Free(&state);
  353. }
  354. free(w);
  355. }
  356.  
  357. // Around here it WSum starts to beat SimpleWSum
  358. //#define NUM_WEIGHTS 17000
  359. //#define NUM_ITER 80000
  360. #define NUM_WEIGHTS 50
  361. #define NUM_ITER 200
  362.  
  363. int main ()
  364. {
  365. // Run both, comparing the results.
  366. test(NUM_WEIGHTS, NUM_ITER, 1, 1);
  367.  
  368. // Run just WSum or just SimpleWSum for benchmarking
  369. //test(NUM_WEIGHTS, NUM_ITER, 1, 0); // WSum
  370. //test(NUM_WEIGHTS, NUM_ITER, 0, 1); // SimpleWSum
  371. }
  372.  
Success #stdin #stdout 0.01s 1972KB
stdin
Standard input is empty
stdout
WSum m=13 n=52 num_m=4
1129566413.000000 949047825.913104 949047825.913104 OK
184803526.000000 600751360.627565 600751360.627565 OK
412776091.000000 1304255338.267796 1304255338.267796 OK
1424268980.000000 2406055688.177612 2406055688.177612 OK
1911759956.000000 3668510008.049201 3668510008.049201 OK
749241873.000000 3220013232.084301 3220013232.084301 OK
137806862.000000 3837033733.307724 3837033733.307724 OK
42999170.000000 4513324690.094375 4513324690.094376 OK
982906996.000000 4167251336.939565 4167251336.939564 OK
135497281.000000 3177536975.638875 3177536975.638875 OK
511702305.000000 4052371847.683286 4052371847.683286 OK
2084420925.000000 6053136727.503074 6053136727.503074 OK
1937477084.000000 6530514226.709923 6530514226.709923 OK
1827336327.000000 7632304003.624146 7632304003.624147 OK
572660336.000000 8821866085.696461 8821866085.696465 OK
1159126505.000000 10570111047.046713 10570111047.046715 OK
805750846.000000 9038159032.289394 9038159032.289394 OK
1632621729.000000 10801188009.693251 10801188009.693254 OK
1100661313.000000 11087639887.423223 11087639887.423223 OK
1433925857.000000 12841527472.642935 12841527472.642935 OK
1141616124.000000 11896164975.563143 11896164975.563143 OK
84353895.000000 11195109590.530487 11195109590.530491 OK
939819582.000000 11953888338.928909 11953888338.928907 OK
2001100545.000000 12952979433.947742 12952979433.947741 OK
1998898814.000000 12785290674.573799 12785290674.573803 OK
1548233367.000000 14330279707.297676 14330279707.297676 OK
610515434.000000 16334933593.614840 16334933593.614840 OK
1585990364.000000 18340984201.270885 18340984201.270885 OK
1374344043.000000 17466117220.187504 17466117220.187508 OK
760313750.000000 15839269950.453691 15839269950.453691 OK
1477171087.000000 16959010050.427362 16959010050.427362 OK
356426808.000000 17883927874.192337 17883927874.192341 OK
945117276.000000 18321744717.101524 18321744717.101521 OK
1889947178.000000 17910570840.431992 17910570840.431995 OK
1780695788.000000 21324236667.429626 21324236667.429623 OK
709393584.000000 19384789016.619362 19384789016.619366 OK
491705403.000000 21027231326.743980 21027231326.743977 OK
1918502651.000000 21220168963.889530 21220168963.889526 OK
752392754.000000 20681509340.507252 20681509340.507256 OK
1474612399.000000 23469184306.545193 23469184306.545200 OK
2053999932.000000 24659151699.081760 24659151699.081768 OK
1264095060.000000 25855744362.300022 25855744362.300026 OK
1411549676.000000 25535706483.414356 25535706483.414352 OK
1843993368.000000 27710379277.210434 27710379277.210434 OK
943947739.000000 26536328247.183487 26536328247.183472 OK
1984210012.000000 27323468085.976616 27323468085.976620 OK
855636226.000000 27811924162.004112 27811924162.004105 OK
1749698586.000000 31454749591.649639 31454749591.649635 OK
1469348094.000000 29967793666.808739 29967793666.808762 OK
1956297539.000000 31717947708.782829 31717947708.782833 OK
1036140795.000000 31602796291.225231 31602796291.225224 OK
463480570.000000 32471644418.885357 32471644418.885361 OK
2040651434.000000 33036048036.149742 33036048036.149754 OK
1975960378.000000 32824508317.528946 32824508317.528954 OK
317097467.000000 32828999084.461094 32828999084.461098 OK
1892066601.000000 33344756060.421570 33344756060.421581 OK
1376710097.000000 34939920510.470360 34939920510.470360 OK
927612902.000000 33572430954.112854 33572430954.112862 OK
1330573317.000000 34651971770.729454 34651971770.729469 OK
603570492.000000 34525619001.556847 34525619001.556847 OK
1687926652.000000 35730618658.839867 35730618658.839859 OK
660260756.000000 32781797505.867199 32781797505.867210 OK
959997301.000000 35482875089.928825 35482875089.928818 OK
485560280.000000 31683539066.982071 31683539066.982067 OK
402724286.000000 33803052116.307415 33803052116.307411 OK
593209441.000000 31691704889.180420 31691704889.180420 OK
1194953865.000000 32611972661.701683 32611972661.701698 OK
894429689.000000 31152755382.286968 31152755382.286976 OK
364228444.000000 31259218159.870289 31259218159.870304 OK
1947346619.000000 32401365329.573185 32401365329.573196 OK
221558440.000000 31640082970.042225 31640082970.042240 OK
270744729.000000 32548896064.526348 32548896064.526352 OK
1063958031.000000 31154353072.002552 31154353072.002552 OK
1633108117.000000 31820605313.211845 31820605313.211853 OK
2114738097.000000 31619191268.321247 31619191268.321251 OK
2007905771.000000 31499368127.419144 31499368127.419151 OK
1469834481.000000 34139010478.024952 34139010478.024952 OK
822890675.000000 32933704572.661854 32933704572.661854 OK
1610120709.000000 31313952322.688938 31313952322.688946 OK
791698927.000000 32007599682.576302 32007599682.576309 OK
631704567.000000 33146467955.750751 33146467955.750759 OK
498777856.000000 31649371587.915428 31649371587.915443 OK
1255179497.000000 30868938103.702629 30868938103.702633 OK
524872353.000000 33313391892.313446 33313391892.313457 OK
327254586.000000 31496265500.710312 31496265500.710320 OK
1572276965.000000 30197255672.321270 30197255672.321270 OK
269455306.000000 32840706062.194408 32840706062.194412 OK
1703964683.000000 30466086216.217541 30466086216.217545 OK
352406219.000000 32205522628.501389 32205522628.501389 OK
1600028624.000000 34096447724.196075 34096447724.196079 OK
160051528.000000 31116716956.623207 31116716956.623199 OK
2040332871.000000 31239687284.758480 31239687284.758495 OK
112805732.000000 31650885305.295605 31650885305.295609 OK
1120048829.000000 28098126857.759750 28098126857.759754 OK
378409503.000000 28809028461.046436 28809028461.046444 OK
515530019.000000 27255397887.564098 27255397887.564106 OK
1713258270.000000 27904147183.905041 27904147183.905045 OK
1573363368.000000 28193648799.133347 28193648799.133343 OK
1409959708.000000 28041450448.429722 28041450448.429722 OK
2077486715.000000 28842652761.044029 28842652761.044033 OK
1373226340.000000 27883313934.765934 27883313934.765934 OK
1631518149.000000 29799108704.880093 29799108704.880096 OK
200747796.000000 28467154965.122955 28467154965.122955 OK
289700723.000000 27769347637.135082 27769347637.135075 OK
1117142618.000000 28251743748.561947 28251743748.561951 OK
168002245.000000 25991085871.954094 25991085871.954105 OK
150122846.000000 27409666069.793068 27409666069.793068 OK
439493451.000000 24545970924.681160 24545970924.681156 OK
990892921.000000 26474662031.011467 26474662031.011475 OK
1760243555.000000 24440903258.406059 24440903258.406059 OK
1231192379.000000 28146018266.023445 28146018266.023453 OK
1622597488.000000 25837171749.293583 25837171749.293583 OK
111537764.000000 28311671002.129978 28311671002.129971 OK
338888228.000000 27544672347.828289 27544672347.828293 OK
2147469841.000000 27924906503.001205 27924906503.001209 OK
438792350.000000 28284682559.173355 28284682559.173359 OK
1911165193.000000 28159913024.996292 28159913024.996296 OK
269441500.000000 24945859713.691940 24945859713.691948 OK
2142757034.000000 28293434718.771858 28293434718.771858 OK
116087764.000000 26210242254.943932 26210242254.943935 OK
1869470124.000000 26503777141.328575 26503777141.328571 OK
155324914.000000 27187425328.915455 27187425328.915451 OK
8936987.000000 26831295888.791248 26831295888.791256 OK
1982275856.000000 27019559254.001411 27019559254.001423 OK
1275373743.000000 27948871580.747646 27948871580.747658 OK
387346491.000000 26634918991.461510 26634918991.461502 OK
350322227.000000 24673318126.259502 24673318126.259495 OK
841148365.000000 26834046053.629311 26834046053.629318 OK
1960709859.000000 27317534271.129520 27317534271.129524 OK
1760281936.000000 25038535915.012535 25038535915.012524 OK
771151432.000000 27398819510.014389 27398819510.014404 OK
1186452551.000000 27197544393.529522 27197544393.529537 OK
1244316437.000000 29021698532.547783 29021698532.547783 OK
971899228.000000 26493490872.732388 26493490872.732391 OK
1476153275.000000 28237202269.400368 28237202269.400368 OK
213975407.000000 25816319544.183563 25816319544.183556 OK
1139901474.000000 26296337371.033310 26296337371.033314 OK
1626276121.000000 27803720139.562511 27803720139.562515 OK
653468858.000000 27247981026.711498 27247981026.711494 OK
2130794395.000000 28783872494.670078 28783872494.670071 OK
1239036029.000000 27898922632.750221 27898922632.750225 OK
1884661237.000000 28071630813.191494 28071630813.191498 OK
1605908235.000000 29578760407.230679 29578760407.230679 OK
1350573793.000000 30404190334.912613 30404190334.912621 OK
76065818.000000 28347589883.810974 28347589883.810982 OK
1605894428.000000 29927081615.161644 29927081615.161655 OK
1789366143.000000 31953311181.276993 31953311181.276985 OK
1987231011.000000 29045174012.803028 29045174012.803028 OK
1875335928.000000 32109660422.774197 32109660422.774216 OK
1784639529.000000 28175440832.453476 28175440832.453457 OK
2103318776.000000 31062557783.443359 31062557783.443344 OK
1597322404.000000 31993372169.765224 31993372169.765224 OK
1939964443.000000 31108719226.562798 31108719226.562805 OK
2112255763.000000 32427619325.753418 32427619325.753422 OK
1432114613.000000 32145044339.171501 32145044339.171486 OK
1067854538.000000 34054200270.725224 34054200270.725208 OK
352118606.000000 32741516004.403179 32741516004.403179 OK
1782436840.000000 35982784816.703575 35982784816.703575 OK
1909002904.000000 31425638080.740719 31425638080.740723 OK
165344818.000000 32128779157.430012 32128779157.430023 OK
1395235128.000000 34499071873.019218 34499071873.019218 OK
532670688.000000 32568508080.207703 32568508080.207714 OK
1351797369.000000 33356396113.531139 33356396113.531116 OK
492067917.000000 32338780235.051796 32338780235.051792 OK
1504569917.000000 34256512354.898975 34256512354.898975 OK
680466996.000000 33961500559.817513 33961500559.817524 OK
706043324.000000 31179005032.657600 31179005032.657616 OK
496987743.000000 33104625412.701782 33104625412.701786 OK
159259470.000000 29604688193.349823 29604688193.349827 OK
1359512183.000000 32415260521.567577 32415260521.567585 OK
480298490.000000 30206321628.673302 30206321628.673302 OK
1398295499.000000 31618005793.887188 31618005793.887196 OK
1096689772.000000 30064420061.533051 30064420061.533062 OK
2086206725.000000 32932456994.953987 32932456994.953991 OK
601385644.000000 30905931055.316769 30905931055.316761 OK
1172755590.000000 32253907313.604771 32253907313.604778 OK
1544617505.000000 33299049867.839394 33299049867.839397 OK
243268139.000000 32708645367.560497 32708645367.560501 OK
1012502954.000000 32572365415.196484 32572365415.196491 OK
1272469786.000000 31728902669.605263 31728902669.605267 OK
2027907669.000000 34450165877.485970 34450165877.485977 OK
968338082.000000 32171803071.463585 32171803071.463589 OK
722308542.000000 32673239866.155209 32673239866.155212 OK
1820388464.000000 35267091836.929237 35267091836.929237 OK
933110197.000000 31881714736.555294 31881714736.555313 OK
6939507.000000 33328979547.233952 33328979547.233955 OK
740759355.000000 34717786720.180382 34717786720.180382 OK
1285228804.000000 32932643937.885239 32932643937.885239 OK
1789376348.000000 35635492955.376892 35635492955.376892 OK
502278611.000000 32788861355.634949 32788861355.634945 OK
1450573622.000000 34696488055.929443 34696488055.929443 OK
1037127828.000000 31060783594.236267 31060783594.236275 OK
1034949299.000000 34028733809.184822 34028733809.184814 OK
654887343.000000 29807236441.883823 29807236441.883823 OK
1529195746.000000 34482915531.419861 34482915531.419868 OK
392035568.000000 31867827897.055611 31867827897.055618 OK
1335354340.000000 31065363822.093292 31065363822.093304 OK
87755422.000000 30958109753.623806 30958109753.623821 OK
889023311.000000 28994770970.954575 28994770970.954582 OK
1494613810.000000 29830579669.926353 29830579669.926357 OK
dummy 10666808940740.187500