diff options
| author | chenzizhan <[email protected]> | 2024-07-26 18:02:29 +0800 |
|---|---|---|
| committer | chenzizhan <[email protected]> | 2024-07-26 18:02:29 +0800 |
| commit | 240bbbb0e0409a6bca409eb319a0a00960cbc6fb (patch) | |
| tree | b15ddd24d6b851ccf797a5919df52d7994e4dbc9 /src/cells | |
| parent | 3f46275f81d2d5af416f27fb24ab2c5ac21ec418 (diff) | |
| parent | 97e8724310c1a0d51600d723c6d3dcb6c4495d5f (diff) | |
Merge branch 'refactor-heavykeeper-newkey' into develop-version4
Diffstat (limited to 'src/cells')
| -rw-r--r-- | src/cells/hash_table.c | 233 | ||||
| -rw-r--r-- | src/cells/hash_table.h | 30 | ||||
| -rw-r--r-- | src/cells/heavy_keeper.c | 825 | ||||
| -rw-r--r-- | src/cells/heavy_keeper.h | 48 | ||||
| -rw-r--r-- | src/cells/hll_common.c | 384 | ||||
| -rw-r--r-- | src/cells/hll_common.h | 28 | ||||
| -rw-r--r-- | src/cells/spread_sketch.c | 719 | ||||
| -rw-r--r-- | src/cells/spread_sketch.h | 55 |
8 files changed, 2322 insertions, 0 deletions
diff --git a/src/cells/hash_table.c b/src/cells/hash_table.c new file mode 100644 index 0000000..255a3ef --- /dev/null +++ b/src/cells/hash_table.c @@ -0,0 +1,233 @@ +#include "hash_table.h" + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "uthash.h" + +#include "fieldstat.h" +#include "exdata.h" + +struct entry { + char *key; + size_t key_len; + void *exdata; + bool dying; + UT_hash_handle hh; +}; + +struct hash_table { + struct entry *key_exdata_map; + int current_cell_num; + int max_cell_num; + + exdata_new_cb new_fn; + exdata_free_cb free_fn; + exdata_merge_cb merge_fn; + exdata_reset_cb reset_fn; + exdata_copy_cb copy_fn; +}; +static void *default_new_fn(void *arg) { + return NULL; +} + +static void default_free_fn(void *exdata) { + return; +} + +static void default_merge_fn(void *dest, void *src) { + return; +} + +static void default_reset_fn(void *exdata) { + return; +} + +static void *default_copy_fn(void *exdata) { + return exdata; +} + + +struct hash_table *hash_table_new(int max_query_num) { + struct hash_table *pthis = calloc(1, sizeof(struct hash_table)); + + pthis->max_cell_num = max_query_num; + + pthis->new_fn = default_new_fn; + pthis->free_fn = default_free_fn; + pthis->merge_fn = default_merge_fn; + pthis->reset_fn = default_reset_fn; + pthis->copy_fn = default_copy_fn; + return pthis; +} + +void hash_table_free(struct hash_table *pthis) { + if (pthis == NULL) { + return; + } + struct entry *item, *tmp; + HASH_ITER(hh, pthis->key_exdata_map, item, tmp) { + HASH_DEL(pthis->key_exdata_map, item); + free(item->key); + pthis->free_fn(item->exdata); + free(item); + } + free(pthis); +} + +void hash_table_reset(struct hash_table *pthis) { + struct entry *node, *tmp; + HASH_ITER(hh, pthis->key_exdata_map, node, tmp) { + if (!node->dying) { + node->dying = true; + pthis->reset_fn(node->exdata); + continue; + } + HASH_DEL(pthis->key_exdata_map, node); + free(node->key); + pthis->free_fn(node->exdata); + free(node); + } + + pthis->current_cell_num = 0; +} + +static char *my_keydup(const char *key, size_t key_len) { + char *ret = calloc(1, key_len + 1); + memcpy(ret, key, key_len); + return ret; +} + +int hash_table_add(struct hash_table *pthis, const char *key, size_t key_len, void *arg) { + struct entry *item; + HASH_FIND(hh, pthis->key_exdata_map, key, key_len, item); + if (item != NULL && !item->dying) { + return 1; + } + + if (pthis->current_cell_num >= pthis->max_cell_num) { + return 0; + } + + if (item != NULL) { + assert(item->dying); + item->dying = false; + pthis->current_cell_num++; + return 1; + } + + item = calloc(1, sizeof(struct entry)); + item->key = my_keydup(key, key_len); + item->key_len = key_len; + item->exdata = pthis->new_fn(arg); + item->dying = false; + HASH_ADD_KEYPTR(hh, pthis->key_exdata_map, item->key, key_len, item); + + pthis->current_cell_num++; + return 1; +} + +void hash_table_set_exdata_schema(struct hash_table *pthis, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn) { + pthis->new_fn = new_fn; + pthis->free_fn = free_fn; + pthis->merge_fn = merge_fn; + pthis->reset_fn = reset_fn; + pthis->copy_fn = copy_fn; +} + +void *hash_table_get0_exdata(struct hash_table *pthis, const char *key, size_t key_len) { + struct entry *item; + HASH_FIND(hh, pthis->key_exdata_map, key, key_len, item); + if (item == NULL || item->dying) { + return NULL; + } + return item->exdata; +} + +int hash_table_get_count(const struct hash_table *pthis) { + return pthis->current_cell_num; +} + +size_t hash_table_list(const struct hash_table *pthis, void **exdatas, size_t n_exdatas) { + size_t actual_len = pthis->current_cell_num; + if (actual_len == 0) { + return 0; + } + + struct entry *item, *tmp; + size_t i = 0; + HASH_ITER(hh, pthis->key_exdata_map, item, tmp) { + if (item->dying) { + continue; + } + if (i >= n_exdatas) { + break; + } + exdatas[i] = item->exdata; + i++; + } + return actual_len < n_exdatas ? actual_len : n_exdatas; +} + +int hash_table_merge(struct hash_table *dest, struct hash_table *src) { + struct entry *item_src, *tmp; + struct entry *item_dst; + HASH_ITER(hh, src->key_exdata_map, item_src, tmp) { + if (item_src->dying) { + continue; + } + + HASH_FIND(hh, dest->key_exdata_map, item_src->key, item_src->key_len, item_dst); + if (item_dst != NULL && !item_dst->dying) { + dest->merge_fn(item_dst->exdata, item_src->exdata); + continue; + } + + if (dest->current_cell_num >= dest->max_cell_num) { + continue; // cannot add more cells + } + + if (item_dst == NULL) { + item_dst = calloc(1, sizeof(struct entry)); + item_dst->key = my_keydup(item_src->key, item_src->key_len); + item_dst->key_len = item_src->key_len; + item_dst->dying = false; + item_dst->exdata = dest->copy_fn(item_src->exdata); + HASH_ADD_KEYPTR(hh, dest->key_exdata_map, item_dst->key, item_dst->key_len, item_dst); + dest->current_cell_num++; + } else { + assert(item_dst->dying); + item_dst->dying = false; + dest->merge_fn(item_dst->exdata, item_src->exdata); //item_dst->exdata should be empty, but just merge to it. + dest->current_cell_num++; + } + } + return 0; +} + +struct hash_table *hash_table_copy(const struct hash_table *src) { + struct hash_table *pthis = calloc(1, sizeof(struct hash_table)); + pthis->max_cell_num = src->max_cell_num; + pthis->current_cell_num = src->current_cell_num; + pthis->new_fn = src->new_fn; + pthis->free_fn = src->free_fn; + pthis->merge_fn = src->merge_fn; + pthis->reset_fn = src->reset_fn; + pthis->copy_fn = src->copy_fn; + + struct entry *item, *tmp; + HASH_ITER(hh, src->key_exdata_map, item, tmp) { + if (item->dying) { + continue; + } + struct entry *new_item = calloc(1, sizeof(struct entry)); + new_item->key = my_keydup(item->key, item->key_len); + new_item->key_len = item->key_len; + new_item->exdata = pthis->copy_fn(item->exdata); + new_item->dying = false; + HASH_ADD_KEYPTR(hh, pthis->key_exdata_map, new_item->key, new_item->key_len, new_item); + } + return pthis; +} diff --git a/src/cells/hash_table.h b/src/cells/hash_table.h new file mode 100644 index 0000000..59fc8e8 --- /dev/null +++ b/src/cells/hash_table.h @@ -0,0 +1,30 @@ +#pragma once + +#include <stddef.h> + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "exdata.h" + +struct hash_table; + +struct hash_table *hash_table_new(int max_query_num); +void hash_table_set_exdata_schema(struct hash_table *pthis, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn); +void hash_table_free(struct hash_table *pthis); +void hash_table_reset(struct hash_table *pthis); +int hash_table_merge(struct hash_table *dest, struct hash_table *src); +struct hash_table *hash_table_copy(const struct hash_table *src); + +// int hash_table_add(struct hash_table *pthis, const char *key, size_t key_len, int count, void *arg); +int hash_table_add(struct hash_table *pthis, const char *key, size_t key_len, void *arg); + +// void *hash_table_get0_exdata(struct hash_table *pthis, const char *key, size_t key_len); +void *hash_table_get0_exdata(struct hash_table *pthis, const char *key, size_t key_len); +int hash_table_get_count(const struct hash_table *pthis); +size_t hash_table_list(const struct hash_table *pthis, void **exdatas, size_t n_exdatas); + +#ifdef __cplusplus +} +#endif
\ No newline at end of file diff --git a/src/cells/heavy_keeper.c b/src/cells/heavy_keeper.c new file mode 100644 index 0000000..c62e550 --- /dev/null +++ b/src/cells/heavy_keeper.c @@ -0,0 +1,825 @@ +#include "heavy_keeper.h" + +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "minheap/heap.h" +#include "mpack/mpack.h" +#include "xxhash/xxhash.h" +// XXHASH is faster +#define HASH_FUNCTION(keyptr, keylen, hashv) \ + do { \ + hashv = XXH3_64bits(keyptr, keylen); \ + } while (0) + +#include "uthash.h" + +#include "exdata.h" + +#define FP_HASH_KEY 0 +#define NOT_FIND (-1) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +struct entry_data { // the value constitute of a sorted set entry + char *key; + size_t key_len; + + void *exdata; +}; + +struct sorted_set { + heap *heap; + struct hash_node *hash_tbl; + + int n_living_entry; + + exdata_new_cb new_fn; + exdata_free_cb free_fn; + exdata_merge_cb merge_fn; + exdata_reset_cb reset_fn; + exdata_copy_cb copy_fn; +}; + +struct hash_node { + const char *key; // value is equal to entry_data::key(point to the same memory) + size_t key_len; + heap_entry *val; + UT_hash_handle hh; +}; + +struct Bucket { + uint64_t finger_print; + long long count; // the actual count, sum of all uuid_hash_node->count +}; + +// Parameters used in algorithm +struct heavy_keeper_options{ + int r; // the size of the array. Default value: 4 + // Set it by how accurate you want. Value of 4 guarantees an accuracy more than 90% and around 97% in all tests. + // Not too big because it have an impact on both time and memory efficiency. + int w; // M2, the maximum number of buckets every array keeps. Default value: k*log(k) and no less than 100. + // Basically, as long as big enough, it won't affect the accuracy significantly. + double b; // b, bigger variance of flow size is(elephant flows take more ratio), smaller it should be. + // Must bigger than 1. Better not bigger than 1.3, otherwise some elephant flow will be missed. +}; + +struct heavy_keeper { + int K; + struct sorted_set *top_K_heap; + struct heavy_keeper_options params; + struct Bucket *sketch; + + unsigned int rand_state; + + exdata_new_cb new_fn; + exdata_free_cb free_fn; + exdata_merge_cb merge_fn; + exdata_reset_cb reset_fn; + exdata_copy_cb copy_fn; +}; + +static void *default_new_fn(void *arg) { + return NULL; +} + +static void default_free_fn(void *exdata) { + return; +} + +static void default_merge_fn(void *dest, void *src) { + return; +} + +static void default_reset_fn(void *exdata) { + return; +} + +static void *default_copy_fn(void *exdata) { + return exdata; +} + +struct entry_data *entry_data_construct(const char *key, size_t key_len, void *exdata) +{ + struct entry_data *entry_data = (struct entry_data *)malloc(sizeof(struct entry_data)); + + entry_data->key = (char *)malloc(key_len); + memcpy(entry_data->key, key, key_len); + entry_data->key_len = key_len; + entry_data->exdata = exdata; + return entry_data; +} + +void entry_data_destroy(struct entry_data *entry_data, exdata_free_cb free_fn) +{ + if (entry_data == NULL) { + return; + } + free(entry_data->key); + free_fn(entry_data->exdata); + free(entry_data); +} + +static inline long long sorted_set_entry_get_score(const heap_entry *entry) +{ + long long score = *(long long *)entry->key; + if (score == 0) { + return 0; + } + return score - 1; // sorted set will let the count start from 1, 0 for dying entry. +} + +struct entry_data *sorted_set_entry_get_data(const heap_entry *entry) +{ + return entry->value; +} + +/* + dying: To reduce the time of HASH_ADD, and to support merely recording a key without any value, give a dying status. +*/ +static inline bool sorted_set_entry_dying(const heap_entry *entry) +{ + long long score = *(long long *)entry->key; + return score == 0; +} + +static inline long long safe_add(long long a, long long b) +{ + if (INT64_MAX - a < b) { + return INT64_MAX; + } + return a + b; +} + +// cppcheck-suppress [constParameterCallback, unmatchedSuppression] +static bool cmp_entry_cb(void *aa, void *bb) +{ + heap_entry *a = (heap_entry *)aa; + heap_entry *b = (heap_entry *)bb; + long long score_a = *(long long *)a->key; + long long score_b = *(long long *)b->key; + + if (score_a < score_b) { + return true; + } + return false; +} + +static int entry_get_index_cb(void *a) +{ + return ((heap_entry *)a)->index; +} + +void entry_set_index_cb(int index, void *a) +{ + ((heap_entry *)a)->index = index; +} + +struct sorted_set *sorted_set_new(int set_size) +{ + struct sorted_set *ret = (struct sorted_set *)malloc(sizeof(struct sorted_set)); + ret->hash_tbl = NULL; + ret->n_living_entry = 0; + heap *h = (heap *)malloc(sizeof(heap)); + init_heap(h, set_size, cmp_entry_cb, entry_get_index_cb, entry_set_index_cb); + + ret->heap = h; + + ret->new_fn = default_new_fn; + ret->free_fn = default_free_fn; + ret->merge_fn = default_merge_fn; + ret->reset_fn = default_reset_fn; + ret->copy_fn = default_copy_fn; + + return ret; +} + +void sorted_set_schema_set(struct sorted_set *ss, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn) +{ + ss->new_fn = new_fn; + ss->free_fn = free_fn; + ss->merge_fn = merge_fn; + ss->reset_fn = reset_fn; + ss->copy_fn = copy_fn; +} + +void sorted_set_free(struct sorted_set *ss) +{ + struct hash_node *tbl = ss->hash_tbl; + struct hash_node *h_node, *tmp; + HASH_ITER(hh, tbl, h_node, tmp) { + HASH_DEL(tbl, h_node); + free(h_node); + } + + heap *heap = ss->heap; + heap_entry *node; + for (int i = 0; i < heap->cur_size; i++) { + node = (heap_entry *)heap->nodes[i]; + entry_data_destroy(node->value, ss->free_fn); + free(node->key); + free(node); + } + free(heap->nodes); + free(heap); + + free(ss); +} + +heap_entry *sorted_set_find_entry(const struct sorted_set *ss, const char *key, size_t key_len) +{ + struct hash_node *hash_tbl = ss->hash_tbl; + struct hash_node *s = NULL; + HASH_FIND(hh, hash_tbl, key, key_len, s); + + if (s == NULL) { + return NULL; + } + return (heap_entry *)s->val; +} + +static inline void sorted_set_entry_set_score(struct sorted_set *ss, heap_entry *entry, long long score) +{ + *(long long *)(entry->key) = score; + + adjust_heap_node(ss->heap, entry); +} + +int sorted_set_pop(struct sorted_set *ss) +{ + struct hash_node *hash_tbl = ss->hash_tbl; + heap_entry *entry = (heap_entry *)pop_heap(ss->heap); + if (entry == NULL) { + return -1; + } + struct entry_data *tmp_data = sorted_set_entry_get_data(entry); + + struct hash_node *s = NULL; + HASH_FIND(hh, hash_tbl, tmp_data->key, tmp_data->key_len, s); + assert(s!=NULL); + + HASH_DEL(hash_tbl, s); + free(s); + ss->hash_tbl = hash_tbl; + + int ret; + if (sorted_set_entry_dying(entry)) { + ret = 0; + } else { + ss->n_living_entry--; + ret = 1; + } + + entry_data_destroy(tmp_data, ss->free_fn); + free(entry->key); + free(entry); + + return ret; +} + +static inline bool sorted_set_check_is_full(const struct sorted_set *ss) +{ + return ss->heap->cur_size >= ss->heap->max_size; +} + +long long sorted_set_get_min_score(const struct sorted_set *ss) +{ + heap *heap = ss->heap; + if (heap->cur_size == 0) { + return NOT_FIND; + } + const heap_entry *ret = (heap_entry *)(heap->nodes[0]); + + long long score = *(long long *)ret->key; + if (score == 0) { + return NOT_FIND; + } + return score - 1; // sorted set will let the score start from 1, 0 for dying entry. +} + +void sorted_set_insert_to_available_heap(struct sorted_set *ss, const char *key, size_t key_len, long long cnt, void *exdata) +{ + cnt = safe_add(cnt, 1); // sorted set will let the score start from 1, 0 for dying entry. + long long *tmp_cnt = (long long*)malloc(sizeof(long long)); + *tmp_cnt = cnt; + struct entry_data *tmp_data = entry_data_construct(key, key_len, exdata); + heap_entry *node = (heap_entry *)malloc(sizeof(heap_entry)); + node->key = tmp_cnt; + node->value = tmp_data; + + push_heap(ss->heap, (void *)node); + + struct hash_node *hash_tbl = ss->hash_tbl; + struct hash_node *s = (struct hash_node *)malloc(sizeof(struct hash_node)); + s->key = sorted_set_entry_get_data(node)->key; + s->key_len = key_len; + s->val = node; + HASH_ADD_KEYPTR(hh, hash_tbl, s->key, key_len, s); + ss->hash_tbl = hash_tbl; + + ss->n_living_entry++; +} + +int sorted_set_insert(struct sorted_set *ss, const char *key, size_t key_len, long long cnt, void *args) +{ + // if there is a dying record, reborn it to use. + heap_entry *entry = sorted_set_find_entry(ss, key, key_len); + if (entry != NULL) { + if (!sorted_set_entry_dying(entry)) { + assert(0); + return -1; + } + sorted_set_entry_set_score(ss, entry, safe_add(cnt, 1)); // sorted set will let the score start from 1, 0 for dying entry. + + ss->n_living_entry++; + return 1; + } + + if (sorted_set_check_is_full(ss)) { + long long tmp_mincnt = sorted_set_get_min_score(ss); + if (tmp_mincnt != NOT_FIND && cnt <= tmp_mincnt) { // even if all cells in sorted set are dying, the sorted set can still be a full one, in which case, the min score is invalid. + return 0; + } + sorted_set_pop(ss); + } + sorted_set_insert_to_available_heap(ss, key, key_len, cnt, ss->new_fn(args)); + return 1; +} + +static inline int sorted_set_cardinality(const struct sorted_set *ss) +{ + return ss->n_living_entry; +} + +long long sorted_set_get_score(const struct sorted_set *ss, const char *key, size_t key_len) +{ + if (sorted_set_cardinality(ss) == 0) { + return NOT_FIND; + } + const heap_entry *entry = sorted_set_find_entry(ss, key, key_len); + if (entry == NULL) { + return NOT_FIND; + } + if (sorted_set_entry_dying(entry)) { + return NOT_FIND; + } + + return sorted_set_entry_get_score(entry); +} + +int sorted_set_incrby(struct sorted_set *ss, const char *key, size_t key_len, long long score) +{ + heap_entry *entry = sorted_set_find_entry(ss, key, key_len); + if (entry == NULL) { + return -1; + } + long long cnt_old; + if (sorted_set_entry_dying(entry) == false) { + cnt_old = sorted_set_entry_get_score(entry); + cnt_old += 1; // sorted set will let the score start from 1, 0 for dying entry. + } else { + cnt_old = 0; + } + sorted_set_entry_set_score(ss, entry, safe_add(score, cnt_old)); + return 0; +} + +typedef struct { + long long key; + struct entry_data *val; +} tmp_heap_node; + +int cmp_tmp_heap_node(const void *a, const void *b) +{ + const tmp_heap_node *aa = (tmp_heap_node *)a; + const tmp_heap_node *bb = (tmp_heap_node *)b; + + if (aa->key < bb->key) { + return 1; + } else if (aa->key > bb->key) { + return -1; + } else { + return 0; + } +} + +void sorted_set_dump(const struct sorted_set *ss, char **key_out, size_t *key_len_out, void **exdata_out) +{ + struct minheap *h = ss->heap; + tmp_heap_node *tmp_nodes = (tmp_heap_node *)malloc(sizeof(tmp_heap_node) * h->cur_size); + size_t n_living_entry = 0; + for (int i = 0; i < h->cur_size; i++) { + const heap_entry *entry = (heap_entry *)h->nodes[i]; + if (sorted_set_entry_dying(entry)) { + continue; + } + tmp_nodes[n_living_entry].key = sorted_set_entry_get_score(entry); + tmp_nodes[n_living_entry].val = sorted_set_entry_get_data(entry); + n_living_entry++; + } + + assert(n_living_entry == ss->n_living_entry); + qsort(tmp_nodes, n_living_entry, sizeof(tmp_heap_node), cmp_tmp_heap_node); + for (int i = 0; i < n_living_entry; i++) { + key_out[i] = tmp_nodes[i].val->key; + key_len_out[i] = tmp_nodes[i].val->key_len; + exdata_out[i] = tmp_nodes[i].val->exdata; + } + free(tmp_nodes); +} + +struct sorted_set *sorted_set_copy(const struct sorted_set *ss) +{ + struct sorted_set *ret = sorted_set_new(ss->heap->max_size); + sorted_set_schema_set(ret, ss->new_fn, ss->free_fn, ss->merge_fn, ss->reset_fn, ss->copy_fn); + + for (int i = 0; i < ss->heap->cur_size; i++) { + const heap_entry *entry = (heap_entry *)ss->heap->nodes[i]; + if (sorted_set_entry_dying(entry)) { + continue; + } + const struct entry_data *data = sorted_set_entry_get_data(entry); + sorted_set_insert_to_available_heap(ret, data->key, data->key_len, sorted_set_entry_get_score(entry), ss->copy_fn(data->exdata)); + } + + return ret; +} + +// set all the entry to dying status. They will be the first to be popped. +void sorted_set_reset(struct sorted_set *ss) +{ + heap *heap = ss->heap; + heap_entry *entry; + for (int i = 0; i < heap->cur_size; i++) { + entry = (heap_entry *)heap->nodes[i]; + *(long long *)entry->key = 0; + + ss->reset_fn(sorted_set_entry_get_data(entry)->exdata); + } + + ss->n_living_entry = 0; +} + +/* -------------------------------------------------------------------------- */ +/* heavy keeper */ +/* -------------------------------------------------------------------------- */ + +struct Bucket *new_sketch(struct heavy_keeper_options *params) { + size_t array_len = (size_t)params->r * (size_t)params->w; + + struct Bucket *ret = (struct Bucket *)calloc(array_len, sizeof(struct Bucket)); + + return ret; +} + +void params_set_to_default(struct heavy_keeper_options *p, int K) { + if (K > 5000) { // don't let the sketch too large when K gets insanely large + K = 5000; + } + double log_ret = log((double)K) / 2.3; // 2.3: log_e(10), log_ret = log_10(K) + + if (log_ret < 3) { + p->r = 3; + } else { + p->r = (int)(log_ret); + } + p->b = 1.17; // by test, 1.17 is the best + p->w = (int)(log_ret * K * 2); + if (p->w < 150) { + p->w = 150; // determined through test, too small max_bucket_num will let accuracy decrease severely. + } else if (p->w > 600) { + p->w = p->w / 4 + 450; + } +} + +struct heavy_keeper *heavy_keeper_new(int max_query_num) { + struct heavy_keeper *hk = (struct heavy_keeper *)malloc(sizeof(struct heavy_keeper)); + hk->K = max_query_num; + hk->rand_state = 0; + + hk->top_K_heap = sorted_set_new(max_query_num); + + params_set_to_default(&(hk->params), max_query_num); + + hk->sketch = new_sketch(&(hk->params)); + + hk->new_fn = default_new_fn; + hk->free_fn = default_free_fn; + hk->merge_fn = default_merge_fn; + hk->reset_fn = default_reset_fn; + + return hk; +} + +void heavy_keeper_free(struct heavy_keeper *hk) { + if (hk == NULL) { + return; + } + sorted_set_free(hk->top_K_heap); + free(hk->sketch); + + free(hk); +} + +void heavy_keeper_reset(struct heavy_keeper *hk) { + sorted_set_reset(hk->top_K_heap); + memset(hk->sketch, 0, sizeof(struct Bucket) * (size_t)hk->params.r * (size_t)hk->params.w); +} + +const int DECAY_POW_TABLE[128] = { // 1.17 ^ exp * RAND_MAX, exp is in [0,127] +2147483647,1835456109,1568765905,1340825560,1146004752,979491241,837172001,715531625,611565491,522705548,446756879,381843486,326361954,278941841,238411830,203770795,174163072,148857327,127228484,108742294,92942132, +79437720,67895487,58030331,49598573,42391943,36232430,30967889,26468281,22622462,19335438,16526015,14124799,12072478,10318357,8819109,7537700,6442479,5506392,4706318,4022494,3438029,2938486,2511527,2146604, +1834704,1568123,1340276,1145535,979090,836829,715239,611315,522491,446574,381687,326228,278828,238314,203687,174092,148796,127176,108698,92904,79405,67868,58007,49578,42375,36218,30955,26457,22613,19328,16519, +14119,12068,10314,8815,7535,6440,5504,4704,4021,3437,2937,2510,2146,1834,1567,1340,1145,979,836,715,611,522,446,382,326,279,238,204,174,149,127,109,93,79,68,58,50,42,36,31,26,23,19,17,14,12,10,9,8,6,6,5, +}; +bool if_need_to_decay(struct heavy_keeper *hk, const struct Bucket *bucket, long long count) { + if (count == 0) { + return false; + } + if (bucket->count < count) { // the exp is 0, so the decay rate is 1 + return true; + } + + long long exp = bucket->count / count; + if (exp > 127) { // decay_rate too small, almost no chance to decay + return false; + } + + // double decay_rate = pow(hk->params.b, -exp); + // p->b = 1.17 is fixed, search table to get result directly. + int decay_rate = DECAY_POW_TABLE[exp]; + + if (rand_r(&(hk->rand_state)) < decay_rate) { + return true; + } + return false; +} + +static inline uint64_t cal_hash_val_with_seed(const char *key, size_t key_len, unsigned int seed) { + return XXH3_64bits_withSeed(key, key_len, seed); +} + +/* +1 for newly add something. 0 for not add. -1 for unexpected cases. +*/ +int heavy_keeper_add(struct heavy_keeper *heavy_keeper, const char *key, size_t key_len, long long count, void *arg) { + assert(count >= 0); + if (count == 0) { + if (sorted_set_cardinality(heavy_keeper->top_K_heap) < heavy_keeper->K) { + const struct heap_entry *entry = sorted_set_find_entry(heavy_keeper->top_K_heap, key, key_len); + + if (entry != NULL && !sorted_set_entry_dying(entry)) { + return 0; + } + + sorted_set_insert(heavy_keeper->top_K_heap, key, key_len, count, arg); + return 1; + } + return 0; + } + + struct sorted_set *summary = heavy_keeper->top_K_heap; + + long long old_cnt = sorted_set_get_score(summary, key, key_len); + bool not_in_sorted_set = (old_cnt == NOT_FIND); + long long maxv = 0; + uint64_t fp = cal_hash_val_with_seed(key, key_len, FP_HASH_KEY); + uint64_t h1 = fp; + uint64_t h2 = cal_hash_val_with_seed(key, key_len, FP_HASH_KEY+1); + + for (uint64_t j = 0; j < heavy_keeper->params.r; j++) { + uint64_t hashv = h1 + j * h2; // use `double hashing` strategy + struct Bucket *bucket = &(heavy_keeper->sketch[j * heavy_keeper->params.w + (hashv % heavy_keeper->params.w)]); + + if (bucket->finger_print == fp) { + // If a key is not in the min-heap, then the estimated key size should be no larger than nmin. + // or if the min-heap is not full(min_value == NOT_FIND), every key should be taken into account, so of course it should be added. + // in neither case, bucket->count > nMin && not_in_sorted_set happen. + // The keys whose counts are both larger than nmin and not in min-heap must have the same xxhash value, and its FP stored in bucket represents another field, + // In this case, the sketch won't be updated. This key is expected to be taken into account in another array, + // where its FP is different from the one it should collided with, so that element keys won't be missed. + if (not_in_sorted_set) { + long long min_value = sorted_set_get_min_score(summary); + if (min_value != NOT_FIND && bucket->count > min_value) { + continue; + } + } + bucket->count = safe_add(bucket->count, count); + maxv = MAX(maxv, bucket->count); + } else { + if (!if_need_to_decay(heavy_keeper, bucket, count)) { + continue; + } + + if (bucket->count < count) { + bucket->finger_print = fp; + bucket->count = count; + + maxv = MAX(maxv, count); + } else { + bucket->count -= count; + } + } + } + + if (not_in_sorted_set) { + if (sorted_set_cardinality(summary) != heavy_keeper->K) { + sorted_set_insert(summary, key, key_len, maxv, arg); + return 1; + } + long long min_value = sorted_set_get_min_score(summary); + if (maxv > min_value || min_value == NOT_FIND) { + sorted_set_insert(summary, key, key_len, maxv, arg); + return 1; + } + return 0; + } else { + if (maxv > old_cnt) { + sorted_set_incrby(summary, key, key_len, maxv - old_cnt); + } + return 1; // no popped, but the exdata definitely exists in the sorted set + } +} + +int heavy_keeper_set_exdata_schema(struct heavy_keeper *hk, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn) { + sorted_set_schema_set(hk->top_K_heap, new_fn, free_fn, merge_fn, reset_fn, copy_fn); + hk->new_fn = new_fn; + hk->free_fn = free_fn; + hk->merge_fn = merge_fn; + hk->reset_fn = reset_fn; + hk->copy_fn = copy_fn; + + return 0; +} + +void *heavy_keeper_get0_exdata(const struct heavy_keeper *hk, const char *key, size_t key_len) { + const heap_entry *entry = sorted_set_find_entry(hk->top_K_heap, key, key_len); + if (entry == NULL || sorted_set_entry_dying(entry)) { + return NULL; + } + return sorted_set_entry_get_data(entry)->exdata; +} + +int heavy_keeper_get_count(const struct heavy_keeper *hk) { + return sorted_set_cardinality(hk->top_K_heap); +} + +size_t heavy_keeper_list(const struct heavy_keeper *hk, void **exdatas, size_t n_exdatas) { + size_t actual_len = sorted_set_cardinality(hk->top_K_heap); + if (actual_len == 0) { + return 0; + } + + char **keys_dummy = (char **)malloc(sizeof(char *) * actual_len); + size_t *key_lens_dummy = (size_t *)malloc(sizeof(size_t) * actual_len); + if (n_exdatas < actual_len) { + void **exdatas_ret = (void **)malloc(sizeof(void *) * actual_len); + sorted_set_dump(hk->top_K_heap, keys_dummy, key_lens_dummy, exdatas_ret); + memcpy(exdatas, exdatas_ret, sizeof(void *) * n_exdatas); + free(exdatas_ret); + } else { + sorted_set_dump(hk->top_K_heap, keys_dummy, key_lens_dummy, exdatas); + } + + free(keys_dummy); + free(key_lens_dummy); + + return actual_len < n_exdatas ? actual_len : n_exdatas; +} + +static void heavy_keeper_merge_sketch(struct heavy_keeper *dest, const struct heavy_keeper *src) { + int w = dest->params.w; + int d = dest->params.r; + //idx + for (int array_id = 0; array_id < d; array_id++) { + for (int bucket_id = 0; bucket_id < w; bucket_id++) { + struct Bucket *bucket_dest = &(dest->sketch[array_id * w + bucket_id]); + const struct Bucket *bucket_src = &(src->sketch[array_id * w + bucket_id]); + + if (bucket_dest->finger_print == bucket_src->finger_print) { + bucket_dest->count = safe_add(bucket_dest->count, bucket_src->count); + } else { + if (bucket_dest->count < bucket_src->count) { + bucket_dest->count = bucket_src->count; + bucket_dest->finger_print = bucket_src->finger_print; + } + } + } + } +} + +long long find_count_in_sketch(struct heavy_keeper *hk, const char *key, size_t key_len) { + struct Bucket *bucket; + uint64_t fp = cal_hash_val_with_seed(key, key_len, FP_HASH_KEY); + uint64_t h1 = fp; + uint64_t h2 = cal_hash_val_with_seed(key, key_len, FP_HASH_KEY+1); + + long long maxv = 0; + for (uint64_t array_id = 0; array_id < hk->params.r; array_id++) { + uint64_t hash = h1 + array_id * h2; + bucket = &(hk->sketch[array_id * hk->params.w + (hash % hk->params.w)]); + + if (bucket->finger_print == fp) { + maxv = MAX(maxv, bucket->count); + } + } + + return maxv; +} + +void heavy_keeper_merge(struct heavy_keeper *dest, const struct heavy_keeper *src) { + assert(dest->K == src->K); + + heavy_keeper_merge_sketch(dest, src); + + struct sorted_set *new_rec = sorted_set_new(dest->K); // merging result + sorted_set_schema_set(new_rec, dest->new_fn, dest->free_fn, dest->merge_fn, dest->reset_fn, dest->copy_fn); + const struct sorted_set *ss_dest = dest->top_K_heap; // original ss in dest + const struct sorted_set *ss_src = src->top_K_heap; // the ss to be merged + int size_dest = sorted_set_cardinality(ss_dest); + int size_src = sorted_set_cardinality(ss_src); + int max_size = size_dest > size_src ? size_dest : size_src; + + void **exdatas_dst = (void **)calloc(size_dest, sizeof(void *)); + char **key_arr = (char **)malloc(sizeof(char *) * max_size); + size_t *key_lens = (size_t *)malloc(sizeof(size_t) * max_size); + sorted_set_dump(ss_dest, key_arr, key_lens, exdatas_dst); + + + /* ------------------------------ merge dest ------------------------------ */ + for (int i = 0; i < size_dest; i++) { + long long maxv = find_count_in_sketch(dest, key_arr[i], key_lens[i]); + sorted_set_insert_to_available_heap(new_rec, key_arr[i], key_lens[i], maxv, dest->copy_fn(exdatas_dst[i])); + } + + /* ------------------------------ merge src ------------------------------ */ + void **exdatas_src = (void **)calloc(size_src, sizeof(void *)); + sorted_set_dump(ss_src, key_arr, key_lens, exdatas_src); + + for (int i = 0; i < size_src; i++) { + const heap_entry *entry = sorted_set_find_entry(new_rec, key_arr[i], key_lens[i]); + if (entry != NULL) { // the key is in both dest and src, so has been processed in the previous loop. The reason why no need to sum up result is that merged sketch already keeps its summed up count + void *exdata_new = sorted_set_entry_get_data(entry)->exdata; + void *exdata_src = exdatas_src[i]; + dest->merge_fn(exdata_new, exdata_src); + + continue; + } + + long long cnt = find_count_in_sketch(dest, key_arr[i], key_lens[i]);// the cnt is the estimated count in the merged sketch, since the dest heavy keeper has been merged + if (sorted_set_check_is_full(new_rec)) { + long long mincnt_new = sorted_set_get_min_score(new_rec); + if (cnt > mincnt_new) { + sorted_set_pop(new_rec); + sorted_set_insert_to_available_heap(new_rec, key_arr[i], key_lens[i], cnt, dest->copy_fn(exdatas_src[i])); + } + } else { + sorted_set_insert_to_available_heap(new_rec, key_arr[i], key_lens[i], cnt, dest->copy_fn(exdatas_src[i])); + } + } + + free(key_arr); + free(key_lens); + free(exdatas_dst); + free(exdatas_src); + sorted_set_free(dest->top_K_heap); + dest->top_K_heap = new_rec; +} + +struct heavy_keeper *heavy_keeper_copy(const struct heavy_keeper *src) { + struct heavy_keeper *ret = (struct heavy_keeper *)malloc(sizeof(struct heavy_keeper)); + ret->K = src->K; + ret->rand_state = 0; + + ret->top_K_heap = sorted_set_copy(src->top_K_heap); + + ret->params = src->params; + ret->sketch = (struct Bucket *)malloc(sizeof(struct Bucket) * (size_t)ret->params.r * (size_t)ret->params.w); + memcpy(ret->sketch, src->sketch, sizeof(struct Bucket) * (size_t)ret->params.r * (size_t)ret->params.w); + + ret->new_fn = src->new_fn; + ret->free_fn = src->free_fn; + ret->merge_fn = src->merge_fn; + ret->reset_fn = src->reset_fn; + ret->copy_fn = src->copy_fn; + + return ret; +} + +void heavy_keeper_one_point_query(const struct heavy_keeper *hk, const char *key, size_t key_len, long long *count_out, void **exdata_out) { + *count_out = 0; + *exdata_out = NULL; + + const heap_entry *entry = sorted_set_find_entry(hk->top_K_heap, key, key_len); + if (entry == NULL) { + return; + } + *count_out = sorted_set_entry_get_score(entry); + *exdata_out = sorted_set_entry_get_data(entry)->exdata; +}
\ No newline at end of file diff --git a/src/cells/heavy_keeper.h b/src/cells/heavy_keeper.h new file mode 100644 index 0000000..3b09598 --- /dev/null +++ b/src/cells/heavy_keeper.h @@ -0,0 +1,48 @@ +#pragma once + +#include <stddef.h> + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "exdata.h" + + +struct heavy_keeper; + +struct heavy_keeper *heavy_keeper_new(int max_query_num); +/** + * @brief free a heavy keeper. + * @param hk the pointer to the heavy keeper. + */ +void heavy_keeper_free(struct heavy_keeper *hk); + +/* + * @brief clear a heavy keeper. It will clear all the data in the heavy keeper. as for every exdata, use the reset function `exdata_reset_cb` to reset it. + * @param hk the pointer to the heavy keeper. +*/ +void heavy_keeper_reset(struct heavy_keeper *hk); + +int heavy_keeper_add(struct heavy_keeper *hk, const char *key, size_t key_len, long long count, void *arg); + +int heavy_keeper_set_exdata_schema(struct heavy_keeper *hk, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn); + +void *heavy_keeper_get0_exdata(const struct heavy_keeper *hk, const char *key, size_t key_len); + +// get the number of cells in the heavy keeper +int heavy_keeper_get_count(const struct heavy_keeper *hk); + +size_t heavy_keeper_list(const struct heavy_keeper *hk, void **exdatas, size_t n_exdatas); + +void heavy_keeper_merge(struct heavy_keeper *dest, const struct heavy_keeper *src); + +struct heavy_keeper *heavy_keeper_copy(const struct heavy_keeper *src); + +// for test +void heavy_keeper_one_point_query(const struct heavy_keeper *hk, const char *key, size_t key_len, long long *count_out, void **exdata_out); + + +#ifdef __cplusplus +} +#endif
\ No newline at end of file diff --git a/src/cells/hll_common.c b/src/cells/hll_common.c new file mode 100644 index 0000000..47dc113 --- /dev/null +++ b/src/cells/hll_common.c @@ -0,0 +1,384 @@ + +#include "hll_common.h" +#include "crdt_utils.h" + +#include "base64/b64.h" + +#include <string.h> +#include <math.h> +#include <assert.h> +#define REG_WIDTH 6 // Bits per register +#define INT_WIDTH 32 // Bits in an int +#define REG_PER_WORD 5 // floor(INT_WIDTH / REG_WIDTH) + +#define NUM_REG(precision) ((1 << precision)) +#define INT_CEIL(num, denom) (((num) + (denom) - 1) / (denom)) + +#define PRECISION_TO_WORD(precision) INT_CEIL(NUM_REG(precision), REG_PER_WORD) +#define RESET_TIME_SLOT_US(time_window_ms, precision) (time_window_ms*2*1000/NUM_REG(precision)) +#define REGISTER_SIZE(precision) INT_WIDTH*INT_CEIL(NUM_REG(precision), REG_PER_WORD) + +static int get_register(const uint32_t *registers, int idx) { + uint32_t word = *(registers + (idx / REG_PER_WORD)); + word = word >> REG_WIDTH * (idx % REG_PER_WORD); + return word & ((1 << REG_WIDTH) - 1); +} + +static void set_register(uint32_t *registers, int idx, int val) { + uint32_t *word = registers + (idx / REG_PER_WORD); + + // Shift the val into place + unsigned shift = REG_WIDTH * (idx % REG_PER_WORD); + val = val << shift; + uint32_t val_mask = ((1 << REG_WIDTH) - 1) << shift; + + // Store the word + *word = (*word & ~val_mask) | val; + return; +} +static void reset_register(uint32_t *registers, int idx) +{ + uint32_t *word = registers + (idx / REG_PER_WORD); + unsigned shift = REG_WIDTH * (idx % REG_PER_WORD); + uint32_t val_mask = ((1 << REG_WIDTH) - 1) << shift; + *word &= ~val_mask; +} +uint32_t *hll_create_register(int precision) +{ + return ALLOC(uint32_t, PRECISION_TO_WORD(precision)); +} +uint32_t *hll_duplicate(const uint32_t *registers, unsigned char precision) +{ + int words = PRECISION_TO_WORD(precision); + uint32_t *new_registers = ALLOC(uint32_t, words); + memcpy(new_registers, registers, sizeof(uint32_t)*words); + return new_registers; +} +void hll_free_register(uint32_t *registers) +{ + free(registers); + return; +} +static void clear_register(uint32_t *registers, int precision) +{ + memset(registers, 0, PRECISION_TO_WORD(precision)*sizeof(uint32_t)); + return; +} +int hll_add_hash(uint32_t *registers, unsigned char precision, uint64_t hash) +{ + // Determine the index using the first p bits + int idx = hash >> (64 - precision); + + // Shift out the index bits + hash = hash << precision | (1 << (precision -1)); + + // Determine the count of leading zeros. The __builtin_clzll() is provided by GCC + int leading = __builtin_clzll(hash) + 1; + + // Update the register if the new value is larger + if (leading > get_register(registers, idx)) { + set_register(registers, idx, leading); + return 1; + } + return 0; +} + + +static const double *g_rawEstimateData[] = { + // precision 4 + (double[]) { 11, 11.717, 12.207, 12.7896, 13.2882, 13.8204, 14.3772, 14.9342, 15.5202, 16.161, 16.7722, 17.4636, 18.0396, 18.6766, 19.3566, 20.0454, 20.7936, 21.4856, 22.2666, 22.9946, 23.766, 24.4692, 25.3638, 26.0764, 26.7864, 27.7602, 28.4814, 29.433, 30.2926, 31.0664, 31.9996, 32.7956, 33.5366, 34.5894, 35.5738, 36.2698, 37.3682, 38.0544, 39.2342, 40.0108, 40.7966, 41.9298, 42.8704, 43.6358, 44.5194, 45.773, 46.6772, 47.6174, 48.4888, 49.3304, 50.2506, 51.4996, 52.3824, 53.3078, 54.3984, 55.5838, 56.6618, 57.2174, 58.3514, 59.0802, 60.1482, 61.0376, 62.3598, 62.8078, 63.9744, 64.914, 65.781, 67.1806, 68.0594, 68.8446, 69.7928, 70.8248, 71.8324, 72.8598, 73.6246, 74.7014, 75.393, 76.6708, 77.2394, }, + // precision 5 + (double[]) { 23, 23.1194, 23.8208, 24.2318, 24.77, 25.2436, 25.7774, 26.2848, 26.8224, 27.3742, 27.9336, 28.503, 29.0494, 29.6292, 30.2124, 30.798, 31.367, 31.9728, 32.5944, 33.217, 33.8438, 34.3696, 35.0956, 35.7044, 36.324, 37.0668, 37.6698, 38.3644, 39.049, 39.6918, 40.4146, 41.082, 41.687, 42.5398, 43.2462, 43.857, 44.6606, 45.4168, 46.1248, 46.9222, 47.6804, 48.447, 49.3454, 49.9594, 50.7636, 51.5776, 52.331, 53.19, 53.9676, 54.7564, 55.5314, 56.4442, 57.3708, 57.9774, 58.9624, 59.8796, 60.755, 61.472, 62.2076, 63.1024, 63.8908, 64.7338, 65.7728, 66.629, 67.413, 68.3266, 69.1524, 70.2642, 71.1806, 72.0566, 72.9192, 73.7598, 74.3516, 75.5802, 76.4386, 77.4916, 78.1524, 79.1892, 79.8414, 80.8798, 81.8376, 82.4698, 83.7656, 84.331, 85.5914, 86.6012, 87.7016, 88.5582, 89.3394, 90.3544, 91.4912, 92.308, 93.3552, 93.9746, 95.2052, 95.727, 97.1322, 98.3944, 98.7588, 100.242, 101.1914, 102.2538, 102.8776, 103.6292, 105.1932, 105.9152, 107.0868, 107.6728, 108.7144, 110.3114, 110.8716, 111.245, 112.7908, 113.7064, 114.636, 115.7464, 116.1788, 117.7464, 118.4896, 119.6166, 120.5082, 121.7798, 122.9028, 123.4426, 124.8854, 125.705, 126.4652, 128.3464, 128.3462, 130.0398, 131.0342, 131.0042, 132.4766, 133.511, 134.7252, 135.425, 136.5172, 138.0572, 138.6694, 139.3712, 140.8598, 141.4594, 142.554, 143.4006, 144.7374, 146.1634, 146.8994, 147.605, 147.9304, 149.1636, 150.2468, 151.5876, 152.2096, 153.7032, 154.7146, 155.807, 156.9228, 157.0372, 158.5852, }, + // precision 6 + (double[]) { 46, 46.1902, 47.271, 47.8358, 48.8142, 49.2854, 50.317, 51.354, 51.8924, 52.9436, 53.4596, 54.5262, 55.6248, 56.1574, 57.2822, 57.837, 58.9636, 60.074, 60.7042, 61.7976, 62.4772, 63.6564, 64.7942, 65.5004, 66.686, 67.291, 68.5672, 69.8556, 70.4982, 71.8204, 72.4252, 73.7744, 75.0786, 75.8344, 77.0294, 77.8098, 79.0794, 80.5732, 81.1878, 82.5648, 83.2902, 84.6784, 85.3352, 86.8946, 88.3712, 89.0852, 90.499, 91.2686, 92.6844, 94.2234, 94.9732, 96.3356, 97.2286, 98.7262, 100.3284, 101.1048, 102.5962, 103.3562, 105.1272, 106.4184, 107.4974, 109.0822, 109.856, 111.48, 113.2834, 114.0208, 115.637, 116.5174, 118.0576, 119.7476, 120.427, 122.1326, 123.2372, 125.2788, 126.6776, 127.7926, 129.1952, 129.9564, 131.6454, 133.87, 134.5428, 136.2, 137.0294, 138.6278, 139.6782, 141.792, 143.3516, 144.2832, 146.0394, 147.0748, 148.4912, 150.849, 151.696, 153.5404, 154.073, 156.3714, 157.7216, 158.7328, 160.4208, 161.4184, 163.9424, 165.2772, 166.411, 168.1308, 168.769, 170.9258, 172.6828, 173.7502, 175.706, 176.3886, 179.0186, 180.4518, 181.927, 183.4172, 184.4114, 186.033, 188.5124, 189.5564, 191.6008, 192.4172, 193.8044, 194.997, 197.4548, 198.8948, 200.2346, 202.3086, 203.1548, 204.8842, 206.6508, 206.6772, 209.7254, 210.4752, 212.7228, 214.6614, 215.1676, 217.793, 218.0006, 219.9052, 221.66, 223.5588, 225.1636, 225.6882, 227.7126, 229.4502, 231.1978, 232.9756, 233.1654, 236.727, 238.1974, 237.7474, 241.1346, 242.3048, 244.1948, 245.3134, 246.879, 249.1204, 249.853, 252.6792, 253.857, 254.4486, 257.2362, 257.9534, 260.0286, 260.5632, 262.663, 264.723, 265.7566, 267.2566, 267.1624, 270.62, 272.8216, 273.2166, 275.2056, 276.2202, 278.3726, 280.3344, 281.9284, 283.9728, 284.1924, 286.4872, 287.587, 289.807, 291.1206, 292.769, 294.8708, 296.665, 297.1182, 299.4012, 300.6352, 302.1354, 304.1756, 306.1606, 307.3462, 308.5214, 309.4134, 310.8352, 313.9684, 315.837, 316.7796, 318.9858, }, + // precision 7 + (double[]) { 92, 93.4934, 94.9758, 96.4574, 97.9718, 99.4954, 101.5302, 103.0756, 104.6374, 106.1782, 107.7888, 109.9522, 111.592, 113.2532, 114.9086, 116.5938, 118.9474, 120.6796, 122.4394, 124.2176, 125.9768, 128.4214, 130.2528, 132.0102, 133.8658, 135.7278, 138.3044, 140.1316, 142.093, 144.0032, 145.9092, 148.6306, 150.5294, 152.5756, 154.6508, 156.662, 159.552, 161.3724, 163.617, 165.5754, 167.7872, 169.8444, 172.7988, 174.8606, 177.2118, 179.3566, 181.4476, 184.5882, 186.6816, 189.0824, 191.0258, 193.6048, 196.4436, 198.7274, 200.957, 203.147, 205.4364, 208.7592, 211.3386, 213.781, 215.8028, 218.656, 221.6544, 223.996, 226.4718, 229.1544, 231.6098, 234.5956, 237.0616, 239.5758, 242.4878, 244.5244, 248.2146, 250.724, 252.8722, 255.5198, 258.0414, 261.941, 264.9048, 266.87, 269.4304, 272.028, 274.4708, 278.37, 281.0624, 283.4668, 286.5532, 289.4352, 293.2564, 295.2744, 298.2118, 300.7472, 304.1456, 307.2928, 309.7504, 312.5528, 315.979, 318.2102, 322.1834, 324.3494, 327.325, 330.6614, 332.903, 337.2544, 339.9042, 343.215, 345.2864, 348.0814, 352.6764, 355.301, 357.139, 360.658, 363.1732, 366.5902, 369.9538, 373.0828, 375.922, 378.9902, 382.7328, 386.4538, 388.1136, 391.2234, 394.0878, 396.708, 401.1556, 404.1852, 406.6372, 409.6822, 412.7796, 416.6078, 418.4916, 422.131, 424.5376, 428.1988, 432.211, 434.4502, 438.5282, 440.912, 444.0448, 447.7432, 450.8524, 453.7988, 456.7858, 458.8868, 463.9886, 466.5064, 468.9124, 472.6616, 475.4682, 478.582, 481.304, 485.2738, 488.6894, 490.329, 496.106, 497.6908, 501.1374, 504.5322, 506.8848, 510.3324, 513.4512, 516.179, 520.4412, 522.6066, 526.167, 528.7794, 533.379, 536.067, 538.46, 542.9116, 545.692, 547.9546, 552.493, 555.2722, 557.335, 562.449, 564.2014, 569.0738, 571.0974, 574.8564, 578.2996, 581.409, 583.9704, 585.8098, 589.6528, 594.5998, 595.958, 600.068, 603.3278, 608.2016, 609.9632, 612.864, 615.43, 620.7794, 621.272, 625.8644, 629.206, 633.219, 634.5154, 638.6102, }, + // precision 8 + (double[]) { 184.2152, 187.2454, 190.2096, 193.6652, 196.6312, 199.6822, 203.249, 206.3296, 210.0038, 213.2074, 216.4612, 220.27, 223.5178, 227.4412, 230.8032, 234.1634, 238.1688, 241.6074, 245.6946, 249.2664, 252.8228, 257.0432, 260.6824, 264.9464, 268.6268, 272.2626, 276.8376, 280.4034, 284.8956, 288.8522, 292.7638, 297.3552, 301.3556, 305.7526, 309.9292, 313.8954, 318.8198, 322.7668, 327.298, 331.6688, 335.9466, 340.9746, 345.1672, 349.3474, 354.3028, 358.8912, 364.114, 368.4646, 372.9744, 378.4092, 382.6022, 387.843, 392.5684, 397.1652, 402.5426, 407.4152, 412.5388, 417.3592, 422.1366, 427.486, 432.3918, 437.5076, 442.509, 447.3834, 453.3498, 458.0668, 463.7346, 469.1228, 473.4528, 479.7, 484.644, 491.0518, 495.5774, 500.9068, 506.432, 512.1666, 517.434, 522.6644, 527.4894, 533.6312, 538.3804, 544.292, 550.5496, 556.0234, 562.8206, 566.6146, 572.4188, 579.117, 583.6762, 590.6576, 595.7864, 601.509, 607.5334, 612.9204, 619.772, 624.2924, 630.8654, 636.1836, 642.745, 649.1316, 655.0386, 660.0136, 666.6342, 671.6196, 678.1866, 684.4282, 689.3324, 695.4794, 702.5038, 708.129, 713.528, 720.3204, 726.463, 732.7928, 739.123, 744.7418, 751.2192, 756.5102, 762.6066, 769.0184, 775.2224, 781.4014, 787.7618, 794.1436, 798.6506, 805.6378, 811.766, 819.7514, 824.5776, 828.7322, 837.8048, 843.6302, 849.9336, 854.4798, 861.3388, 867.9894, 873.8196, 880.3136, 886.2308, 892.4588, 899.0816, 905.4076, 912.0064, 917.3878, 923.619, 929.998, 937.3482, 943.9506, 947.991, 955.1144, 962.203, 968.8222, 975.7324, 981.7826, 988.7666, 994.2648, 1000.3128, 1007.4082, 1013.7536, 1020.3376, 1026.7156, 1031.7478, 1037.4292, 1045.393, 1051.2278, 1058.3434, 1062.8726, 1071.884, 1076.806, 1082.9176, 1089.1678, 1095.5032, 1102.525, 1107.2264, 1115.315, 1120.93, 1127.252, 1134.1496, 1139.0408, 1147.5448, 1153.3296, 1158.1974, 1166.5262, 1174.3328, 1175.657, 1184.4222, 1190.9172, 1197.1292, 1204.4606, 1210.4578, 1218.8728, 1225.3336, 1226.6592, 1236.5768, 1241.363, 1249.4074, 1254.6566, 1260.8014, 1266.5454, 1274.5192, }, + // precision 9 + (double[]) { 369, 374.8294, 381.2452, 387.6698, 394.1464, 400.2024, 406.8782, 413.6598, 420.462, 427.2826, 433.7102, 440.7416, 447.9366, 455.1046, 462.285, 469.0668, 476.306, 483.8448, 491.301, 498.9886, 506.2422, 513.8138, 521.7074, 529.7428, 537.8402, 545.1664, 553.3534, 561.594, 569.6886, 577.7876, 585.65, 594.228, 602.8036, 611.1666, 620.0818, 628.0824, 637.2574, 646.302, 655.1644, 664.0056, 672.3802, 681.7192, 690.5234, 700.2084, 708.831, 718.485, 728.1112, 737.4764, 746.76, 756.3368, 766.5538, 775.5058, 785.2646, 795.5902, 804.3818, 814.8998, 824.9532, 835.2062, 845.2798, 854.4728, 864.9582, 875.3292, 886.171, 896.781, 906.5716, 916.7048, 927.5322, 937.875, 949.3972, 958.3464, 969.7274, 980.2834, 992.1444, 1003.4264, 1013.0166, 1024.018, 1035.0438, 1046.34, 1057.6856, 1068.9836, 1079.0312, 1091.677, 1102.3188, 1113.4846, 1124.4424, 1135.739, 1147.1488, 1158.9202, 1169.406, 1181.5342, 1193.2834, 1203.8954, 1216.3286, 1226.2146, 1239.6684, 1251.9946, 1262.123, 1275.4338, 1285.7378, 1296.076, 1308.9692, 1320.4964, 1333.0998, 1343.9864, 1357.7754, 1368.3208, 1380.4838, 1392.7388, 1406.0758, 1416.9098, 1428.9728, 1440.9228, 1453.9292, 1462.617, 1476.05, 1490.2996, 1500.6128, 1513.7392, 1524.5174, 1536.6322, 1548.2584, 1562.3766, 1572.423, 1587.1232, 1596.5164, 1610.5938, 1622.5972, 1633.1222, 1647.7674, 1658.5044, 1671.57, 1683.7044, 1695.4142, 1708.7102, 1720.6094, 1732.6522, 1747.841, 1756.4072, 1769.9786, 1782.3276, 1797.5216, 1808.3186, 1819.0694, 1834.354, 1844.575, 1856.2808, 1871.1288, 1880.7852, 1893.9622, 1906.3418, 1920.6548, 1932.9302, 1945.8584, 1955.473, 1968.8248, 1980.6446, 1995.9598, 2008.349, 2019.8556, 2033.0334, 2044.0206, 2059.3956, 2069.9174, 2082.6084, 2093.7036, 2106.6108, 2118.9124, 2132.301, 2144.7628, 2159.8422, 2171.0212, 2183.101, 2193.5112, 2208.052, 2221.3194, 2233.3282, 2247.295, 2257.7222, 2273.342, 2286.5638, 2299.6786, 2310.8114, 2322.3312, 2335.516, 2349.874, 2363.5968, 2373.865, 2387.1918, 2401.8328, 2414.8496, 2424.544, 2436.7592, 2447.1682, 2464.1958, 2474.3438, 2489.0006, 2497.4526, 2513.6586, 2527.19, 2540.7028, 2553.768 }, + // precision 10 + (double[]) { 738.1256, 750.4234, 763.1064, 775.4732, 788.4636, 801.0644, 814.488, 827.9654, 841.0832, 854.7864, 868.1992, 882.2176, 896.5228, 910.1716, 924.7752, 938.899, 953.6126, 968.6492, 982.9474, 998.5214, 1013.1064, 1028.6364, 1044.2468, 1059.4588, 1075.3832, 1091.0584, 1106.8606, 1123.3868, 1139.5062, 1156.1862, 1172.463, 1189.339, 1206.1936, 1223.1292, 1240.1854, 1257.2908, 1275.3324, 1292.8518, 1310.5204, 1328.4854, 1345.9318, 1364.552, 1381.4658, 1400.4256, 1419.849, 1438.152, 1456.8956, 1474.8792, 1494.118, 1513.62, 1532.5132, 1551.9322, 1570.7726, 1590.6086, 1610.5332, 1630.5918, 1650.4294, 1669.7662, 1690.4106, 1710.7338, 1730.9012, 1750.4486, 1770.1556, 1791.6338, 1812.7312, 1833.6264, 1853.9526, 1874.8742, 1896.8326, 1918.1966, 1939.5594, 1961.07, 1983.037, 2003.1804, 2026.071, 2047.4884, 2070.0848, 2091.2944, 2114.333, 2135.9626, 2158.2902, 2181.0814, 2202.0334, 2224.4832, 2246.39, 2269.7202, 2292.1714, 2314.2358, 2338.9346, 2360.891, 2384.0264, 2408.3834, 2430.1544, 2454.8684, 2476.9896, 2501.4368, 2522.8702, 2548.0408, 2570.6738, 2593.5208, 2617.0158, 2640.2302, 2664.0962, 2687.4986, 2714.2588, 2735.3914, 2759.6244, 2781.8378, 2808.0072, 2830.6516, 2856.2454, 2877.2136, 2903.4546, 2926.785, 2951.2294, 2976.468, 3000.867, 3023.6508, 3049.91, 3073.5984, 3098.162, 3121.5564, 3146.2328, 3170.9484, 3195.5902, 3221.3346, 3242.7032, 3271.6112, 3296.5546, 3317.7376, 3345.072, 3369.9518, 3394.326, 3418.1818, 3444.6926, 3469.086, 3494.2754, 3517.8698, 3544.248, 3565.3768, 3588.7234, 3616.979, 3643.7504, 3668.6812, 3695.72, 3719.7392, 3742.6224, 3770.4456, 3795.6602, 3819.9058, 3844.002, 3869.517, 3895.6824, 3920.8622, 3947.1364, 3973.985, 3995.4772, 4021.62, 4046.628, 4074.65, 4096.2256, 4121.831, 4146.6406, 4173.276, 4195.0744, 4223.9696, 4251.3708, 4272.9966, 4300.8046, 4326.302, 4353.1248, 4374.312, 4403.0322, 4426.819, 4450.0598, 4478.5206, 4504.8116, 4528.8928, 4553.9584, 4578.8712, 4603.8384, 4632.3872, 4655.5128, 4675.821, 4704.6222, 4731.9862, 4755.4174, 4781.2628, 4804.332, 4832.3048, 4862.8752, 4883.4148, 4906.9544, 4935.3516, 4954.3532, 4984.0248, 5011.217, 5035.3258, 5057.3672, 5084.1828, }, + // precision 11 + (double[]) { 1477, 1501.6014, 1526.5802, 1551.7942, 1577.3042, 1603.2062, 1629.8402, 1656.2292, 1682.9462, 1709.9926, 1737.3026, 1765.4252, 1793.0578, 1821.6092, 1849.626, 1878.5568, 1908.527, 1937.5154, 1967.1874, 1997.3878, 2027.37, 2058.1972, 2089.5728, 2120.1012, 2151.9668, 2183.292, 2216.0772, 2247.8578, 2280.6562, 2313.041, 2345.714, 2380.3112, 2414.1806, 2447.9854, 2481.656, 2516.346, 2551.5154, 2586.8378, 2621.7448, 2656.6722, 2693.5722, 2729.1462, 2765.4124, 2802.8728, 2838.898, 2876.408, 2913.4926, 2951.4938, 2989.6776, 3026.282, 3065.7704, 3104.1012, 3143.7388, 3181.6876, 3221.1872, 3261.5048, 3300.0214, 3339.806, 3381.409, 3421.4144, 3461.4294, 3502.2286, 3544.651, 3586.6156, 3627.337, 3670.083, 3711.1538, 3753.5094, 3797.01, 3838.6686, 3882.1678, 3922.8116, 3967.9978, 4009.9204, 4054.3286, 4097.5706, 4140.6014, 4185.544, 4229.5976, 4274.583, 4316.9438, 4361.672, 4406.2786, 4451.8628, 4496.1834, 4543.505, 4589.1816, 4632.5188, 4678.2294, 4724.8908, 4769.0194, 4817.052, 4861.4588, 4910.1596, 4956.4344, 5002.5238, 5048.13, 5093.6374, 5142.8162, 5187.7894, 5237.3984, 5285.6078, 5331.0858, 5379.1036, 5428.6258, 5474.6018, 5522.7618, 5571.5822, 5618.59, 5667.9992, 5714.88, 5763.454, 5808.6982, 5860.3644, 5910.2914, 5953.571, 6005.9232, 6055.1914, 6104.5882, 6154.5702, 6199.7036, 6251.1764, 6298.7596, 6350.0302, 6398.061, 6448.4694, 6495.933, 6548.0474, 6597.7166, 6646.9416, 6695.9208, 6742.6328, 6793.5276, 6842.1934, 6894.2372, 6945.3864, 6996.9228, 7044.2372, 7094.1374, 7142.2272, 7192.2942, 7238.8338, 7288.9006, 7344.0908, 7394.8544, 7443.5176, 7490.4148, 7542.9314, 7595.6738, 7641.9878, 7694.3688, 7743.0448, 7797.522, 7845.53, 7899.594, 7950.3132, 7996.455, 8050.9442, 8092.9114, 8153.1374, 8197.4472, 8252.8278, 8301.8728, 8348.6776, 8401.4698, 8453.551, 8504.6598, 8553.8944, 8604.1276, 8657.6514, 8710.3062, 8758.908, 8807.8706, 8862.1702, 8910.4668, 8960.77, 9007.2766, 9063.164, 9121.0534, 9164.1354, 9218.1594, 9267.767, 9319.0594, 9372.155, 9419.7126, 9474.3722, 9520.1338, 9572.368, 9622.7702, 9675.8448, 9726.5396, 9778.7378, 9827.6554, 9878.1922, 9928.7782, 9978.3984, 10026.578, 10076.5626, 10137.1618, 10177.5244, 10229.9176, }, + // precision 12 + (double[]) { 2954, 3003.4782, 3053.3568, 3104.3666, 3155.324, 3206.9598, 3259.648, 3312.539, 3366.1474, 3420.2576, 3474.8376, 3530.6076, 3586.451, 3643.38, 3700.4104, 3757.5638, 3815.9676, 3875.193, 3934.838, 3994.8548, 4055.018, 4117.1742, 4178.4482, 4241.1294, 4304.4776, 4367.4044, 4431.8724, 4496.3732, 4561.4304, 4627.5326, 4693.949, 4761.5532, 4828.7256, 4897.6182, 4965.5186, 5034.4528, 5104.865, 5174.7164, 5244.6828, 5316.6708, 5387.8312, 5459.9036, 5532.476, 5604.8652, 5679.6718, 5753.757, 5830.2072, 5905.2828, 5980.0434, 6056.6264, 6134.3192, 6211.5746, 6290.0816, 6367.1176, 6447.9796, 6526.5576, 6606.1858, 6686.9144, 6766.1142, 6847.0818, 6927.9664, 7010.9096, 7091.0816, 7175.3962, 7260.3454, 7344.018, 7426.4214, 7511.3106, 7596.0686, 7679.8094, 7765.818, 7852.4248, 7936.834, 8022.363, 8109.5066, 8200.4554, 8288.5832, 8373.366, 8463.4808, 8549.7682, 8642.0522, 8728.3288, 8820.9528, 8907.727, 9001.0794, 9091.2522, 9179.988, 9269.852, 9362.6394, 9453.642, 9546.9024, 9640.6616, 9732.6622, 9824.3254, 9917.7484, 10007.9392, 10106.7508, 10196.2152, 10289.8114, 10383.5494, 10482.3064, 10576.8734, 10668.7872, 10764.7156, 10862.0196, 10952.793, 11049.9748, 11146.0702, 11241.4492, 11339.2772, 11434.2336, 11530.741, 11627.6136, 11726.311, 11821.5964, 11918.837, 12015.3724, 12113.0162, 12213.0424, 12306.9804, 12408.4518, 12504.8968, 12604.586, 12700.9332, 12798.705, 12898.5142, 12997.0488, 13094.788, 13198.475, 13292.7764, 13392.9698, 13486.8574, 13590.1616, 13686.5838, 13783.6264, 13887.2638, 13992.0978, 14081.0844, 14189.9956, 14280.0912, 14382.4956, 14486.4384, 14588.1082, 14686.2392, 14782.276, 14888.0284, 14985.1864, 15088.8596, 15187.0998, 15285.027, 15383.6694, 15495.8266, 15591.3736, 15694.2008, 15790.3246, 15898.4116, 15997.4522, 16095.5014, 16198.8514, 16291.7492, 16402.6424, 16499.1266, 16606.2436, 16697.7186, 16796.3946, 16902.3376, 17005.7672, 17100.814, 17206.8282, 17305.8262, 17416.0744, 17508.4092, 17617.0178, 17715.4554, 17816.758, 17920.1748, 18012.9236, 18119.7984, 18223.2248, 18324.2482, 18426.6276, 18525.0932, 18629.8976, 18733.2588, 18831.0466, 18940.1366, 19032.2696, 19131.729, 19243.4864, 19349.6932, 19442.866, 19547.9448, 19653.2798, 19754.4034, 19854.0692, 19965.1224, 20065.1774, 20158.2212, 20253.353, 20366.3264, 20463.22, }, + // precision 13 + (double[]) { 5908.5052, 6007.2672, 6107.347, 6208.5794, 6311.2622, 6414.5514, 6519.3376, 6625.6952, 6732.5988, 6841.3552, 6950.5972, 7061.3082, 7173.5646, 7287.109, 7401.8216, 7516.4344, 7633.3802, 7751.2962, 7870.3784, 7990.292, 8110.79, 8233.4574, 8356.6036, 8482.2712, 8607.7708, 8735.099, 8863.1858, 8993.4746, 9123.8496, 9255.6794, 9388.5448, 9522.7516, 9657.3106, 9792.6094, 9930.5642, 10068.794, 10206.7256, 10347.81, 10490.3196, 10632.0778, 10775.9916, 10920.4662, 11066.124, 11213.073, 11358.0362, 11508.1006, 11659.1716, 11808.7514, 11959.4884, 12112.1314, 12265.037, 12420.3756, 12578.933, 12734.311, 12890.0006, 13047.2144, 13207.3096, 13368.5144, 13528.024, 13689.847, 13852.7528, 14018.3168, 14180.5372, 14346.9668, 14513.5074, 14677.867, 14846.2186, 15017.4186, 15184.9716, 15356.339, 15529.2972, 15697.3578, 15871.8686, 16042.187, 16216.4094, 16389.4188, 16565.9126, 16742.3272, 16919.0042, 17094.7592, 17273.965, 17451.8342, 17634.4254, 17810.5984, 17988.9242, 18171.051, 18354.7938, 18539.466, 18721.0408, 18904.9972, 19081.867, 19271.9118, 19451.8694, 19637.9816, 19821.2922, 20013.1292, 20199.3858, 20387.8726, 20572.9514, 20770.7764, 20955.1714, 21144.751, 21329.9952, 21520.709, 21712.7016, 21906.3868, 22096.2626, 22286.0524, 22475.051, 22665.5098, 22862.8492, 23055.5294, 23249.6138, 23437.848, 23636.273, 23826.093, 24020.3296, 24213.3896, 24411.7392, 24602.9614, 24805.7952, 24998.1552, 25193.9588, 25389.0166, 25585.8392, 25780.6976, 25981.2728, 26175.977, 26376.5252, 26570.1964, 26773.387, 26962.9812, 27163.0586, 27368.164, 27565.0534, 27758.7428, 27961.1276, 28163.2324, 28362.3816, 28565.7668, 28758.644, 28956.9768, 29163.4722, 29354.7026, 29561.1186, 29767.9948, 29959.9986, 30164.0492, 30366.9818, 30562.5338, 30762.9928, 30976.1592, 31166.274, 31376.722, 31570.3734, 31770.809, 31974.8934, 32179.5286, 32387.5442, 32582.3504, 32794.076, 32989.9528, 33191.842, 33392.4684, 33595.659, 33801.8672, 34000.3414, 34200.0922, 34402.6792, 34610.0638, 34804.0084, 35011.13, 35218.669, 35418.6634, 35619.0792, 35830.6534, 36028.4966, 36229.7902, 36438.6422, 36630.7764, 36833.3102, 37048.6728, 37247.3916, 37453.5904, 37669.3614, 37854.5526, 38059.305, 38268.0936, 38470.2516, 38674.7064, 38876.167, 39068.3794, 39281.9144, 39492.8566, 39684.8628, 39898.4108, 40093.1836, 40297.6858, 40489.7086, 40717.2424, }, + // precision 14 + (double[]) { 11817.475, 12015.0046, 12215.3792, 12417.7504, 12623.1814, 12830.0086, 13040.0072, 13252.503, 13466.178, 13683.2738, 13902.0344, 14123.9798, 14347.394, 14573.7784, 14802.6894, 15033.6824, 15266.9134, 15502.8624, 15741.4944, 15980.7956, 16223.8916, 16468.6316, 16715.733, 16965.5726, 17217.204, 17470.666, 17727.8516, 17986.7886, 18247.6902, 18510.9632, 18775.304, 19044.7486, 19314.4408, 19587.202, 19862.2576, 20135.924, 20417.0324, 20697.9788, 20979.6112, 21265.0274, 21550.723, 21841.6906, 22132.162, 22428.1406, 22722.127, 23020.5606, 23319.7394, 23620.4014, 23925.2728, 24226.9224, 24535.581, 24845.505, 25155.9618, 25470.3828, 25785.9702, 26103.7764, 26420.4132, 26742.0186, 27062.8852, 27388.415, 27714.6024, 28042.296, 28365.4494, 28701.1526, 29031.8008, 29364.2156, 29704.497, 30037.1458, 30380.111, 30723.8168, 31059.5114, 31404.9498, 31751.6752, 32095.2686, 32444.7792, 32794.767, 33145.204, 33498.4226, 33847.6502, 34209.006, 34560.849, 34919.4838, 35274.9778, 35635.1322, 35996.3266, 36359.1394, 36722.8266, 37082.8516, 37447.7354, 37815.9606, 38191.0692, 38559.4106, 38924.8112, 39294.6726, 39663.973, 40042.261, 40416.2036, 40779.2036, 41161.6436, 41540.9014, 41921.1998, 42294.7698, 42678.5264, 43061.3464, 43432.375, 43818.432, 44198.6598, 44583.0138, 44970.4794, 45353.924, 45729.858, 46118.2224, 46511.5724, 46900.7386, 47280.6964, 47668.1472, 48055.6796, 48446.9436, 48838.7146, 49217.7296, 49613.7796, 50010.7508, 50410.0208, 50793.7886, 51190.2456, 51583.1882, 51971.0796, 52376.5338, 52763.319, 53165.5534, 53556.5594, 53948.2702, 54346.352, 54748.7914, 55138.577, 55543.4824, 55941.1748, 56333.7746, 56745.1552, 57142.7944, 57545.2236, 57935.9956, 58348.5268, 58737.5474, 59158.5962, 59542.6896, 59958.8004, 60349.3788, 60755.0212, 61147.6144, 61548.194, 61946.0696, 62348.6042, 62763.603, 63162.781, 63560.635, 63974.3482, 64366.4908, 64771.5876, 65176.7346, 65597.3916, 65995.915, 66394.0384, 66822.9396, 67203.6336, 67612.2032, 68019.0078, 68420.0388, 68821.22, 69235.8388, 69640.0724, 70055.155, 70466.357, 70863.4266, 71276.2482, 71677.0306, 72080.2006, 72493.0214, 72893.5952, 73314.5856, 73714.9852, 74125.3022, 74521.2122, 74933.6814, 75341.5904, 75743.0244, 76166.0278, 76572.1322, 76973.1028, 77381.6284, 77800.6092, 78189.328, 78607.0962, 79012.2508, 79407.8358, 79825.725, 80238.701, 80646.891, 81035.6436, 81460.0448, 81876.3884, }, + // precision 15 + (double[]) { 23635.0036, 24030.8034, 24431.4744, 24837.1524, 25246.7928, 25661.326, 26081.3532, 26505.2806, 26933.9892, 27367.7098, 27805.318, 28248.799, 28696.4382, 29148.8244, 29605.5138, 30066.8668, 30534.2344, 31006.32, 31480.778, 31962.2418, 32447.3324, 32938.0232, 33432.731, 33930.728, 34433.9896, 34944.1402, 35457.5588, 35974.5958, 36497.3296, 37021.9096, 37554.326, 38088.0826, 38628.8816, 39171.3192, 39723.2326, 40274.5554, 40832.3142, 41390.613, 41959.5908, 42532.5466, 43102.0344, 43683.5072, 44266.694, 44851.2822, 45440.7862, 46038.0586, 46640.3164, 47241.064, 47846.155, 48454.7396, 49076.9168, 49692.542, 50317.4778, 50939.65, 51572.5596, 52210.2906, 52843.7396, 53481.3996, 54127.236, 54770.406, 55422.6598, 56078.7958, 56736.7174, 57397.6784, 58064.5784, 58730.308, 59404.9784, 60077.0864, 60751.9158, 61444.1386, 62115.817, 62808.7742, 63501.4774, 64187.5454, 64883.6622, 65582.7468, 66274.5318, 66976.9276, 67688.7764, 68402.138, 69109.6274, 69822.9706, 70543.6108, 71265.5202, 71983.3848, 72708.4656, 73433.384, 74158.4664, 74896.4868, 75620.9564, 76362.1434, 77098.3204, 77835.7662, 78582.6114, 79323.9902, 80067.8658, 80814.9246, 81567.0136, 82310.8536, 83061.9952, 83821.4096, 84580.8608, 85335.547, 86092.5802, 86851.6506, 87612.311, 88381.2016, 89146.3296, 89907.8974, 90676.846, 91451.4152, 92224.5518, 92995.8686, 93763.5066, 94551.2796, 95315.1944, 96096.1806, 96881.0918, 97665.679, 98442.68, 99229.3002, 100011.0994, 100790.6386, 101580.1564, 102377.7484, 103152.1392, 103944.2712, 104730.216, 105528.6336, 106324.9398, 107117.6706, 107890.3988, 108695.2266, 109485.238, 110294.7876, 111075.0958, 111878.0496, 112695.2864, 113464.5486, 114270.0474, 115068.608, 115884.3626, 116673.2588, 117483.3716, 118275.097, 119085.4092, 119879.2808, 120687.5868, 121499.9944, 122284.916, 123095.9254, 123912.5038, 124709.0454, 125503.7182, 126323.259, 127138.9412, 127943.8294, 128755.646, 129556.5354, 130375.3298, 131161.4734, 131971.1962, 132787.5458, 133588.1056, 134431.351, 135220.2906, 136023.398, 136846.6558, 137667.0004, 138463.663, 139283.7154, 140074.6146, 140901.3072, 141721.8548, 142543.2322, 143356.1096, 144173.7412, 144973.0948, 145794.3162, 146609.5714, 147420.003, 148237.9784, 149050.5696, 149854.761, 150663.1966, 151494.0754, 152313.1416, 153112.6902, 153935.7206, 154746.9262, 155559.547, 156401.9746, 157228.7036, 158008.7254, 158820.75, 159646.9184, 160470.4458, 161279.5348, 162093.3114, 162918.542, 163729.2842, }, + // precision 16 + (double[]) { 47271, 48062.3584, 48862.7074, 49673.152, 50492.8416, 51322.9514, 52161.03, 53009.407, 53867.6348, 54734.206, 55610.5144, 56496.2096, 57390.795, 58297.268, 59210.6448, 60134.665, 61068.0248, 62010.4472, 62962.5204, 63923.5742, 64895.0194, 65876.4182, 66862.6136, 67862.6968, 68868.8908, 69882.8544, 70911.271, 71944.0924, 72990.0326, 74040.692, 75100.6336, 76174.7826, 77252.5998, 78340.2974, 79438.2572, 80545.4976, 81657.2796, 82784.6336, 83915.515, 85059.7362, 86205.9368, 87364.4424, 88530.3358, 89707.3744, 90885.9638, 92080.197, 93275.5738, 94479.391, 95695.918, 96919.2236, 98148.4602, 99382.3474, 100625.6974, 101878.0284, 103141.6278, 104409.4588, 105686.2882, 106967.5402, 108261.6032, 109548.1578, 110852.0728, 112162.231, 113479.0072, 114806.2626, 116137.9072, 117469.5048, 118813.5186, 120165.4876, 121516.2556, 122875.766, 124250.5444, 125621.2222, 127003.2352, 128387.848, 129775.2644, 131181.7776, 132577.3086, 133979.9458, 135394.1132, 136800.9078, 138233.217, 139668.5308, 141085.212, 142535.2122, 143969.0684, 145420.2872, 146878.1542, 148332.7572, 149800.3202, 151269.66, 152743.6104, 154213.0948, 155690.288, 157169.4246, 158672.1756, 160160.059, 161650.6854, 163145.7772, 164645.6726, 166159.1952, 167682.1578, 169177.3328, 170700.0118, 172228.8964, 173732.6664, 175265.5556, 176787.799, 178317.111, 179856.6914, 181400.865, 182943.4612, 184486.742, 186033.4698, 187583.7886, 189148.1868, 190688.4526, 192250.1926, 193810.9042, 195354.2972, 196938.7682, 198493.5898, 200079.2824, 201618.912, 203205.5492, 204765.5798, 206356.1124, 207929.3064, 209498.7196, 211086.229, 212675.1324, 214256.7892, 215826.2392, 217412.8474, 218995.6724, 220618.6038, 222207.1166, 223781.0364, 225387.4332, 227005.7928, 228590.4336, 230217.8738, 231805.1054, 233408.9, 234995.3432, 236601.4956, 238190.7904, 239817.2548, 241411.2832, 243002.4066, 244640.1884, 246255.3128, 247849.3508, 249479.9734, 251106.8822, 252705.027, 254332.9242, 255935.129, 257526.9014, 259154.772, 260777.625, 262390.253, 264004.4906, 265643.59, 267255.4076, 268873.426, 270470.7252, 272106.4804, 273722.4456, 275337.794, 276945.7038, 278592.9154, 280204.3726, 281841.1606, 283489.171, 285130.1716, 286735.3362, 288364.7164, 289961.1814, 291595.5524, 293285.683, 294899.6668, 296499.3434, 298128.0462, 299761.8946, 301394.2424, 302997.6748, 304615.1478, 306269.7724, 307886.114, 309543.1028, 311153.2862, 312782.8546, 314421.2008, 316033.2438, 317692.9636, 319305.2648, 320948.7406, 322566.3364, 324228.4224, 325847.1542, }, + // precision 17 + (double[]) { 94542, 96125.811, 97728.019, 99348.558, 100987.9705, 102646.7565, 104324.5125, 106021.7435, 107736.7865, 109469.272, 111223.9465, 112995.219, 114787.432, 116593.152, 118422.71, 120267.2345, 122134.6765, 124020.937, 125927.2705, 127851.255, 129788.9485, 131751.016, 133726.8225, 135722.592, 137736.789, 139770.568, 141821.518, 143891.343, 145982.1415, 148095.387, 150207.526, 152355.649, 154515.6415, 156696.05, 158887.7575, 161098.159, 163329.852, 165569.053, 167837.4005, 170121.6165, 172420.4595, 174732.6265, 177062.77, 179412.502, 181774.035, 184151.939, 186551.6895, 188965.691, 191402.8095, 193857.949, 196305.0775, 198774.6715, 201271.2585, 203764.78, 206299.3695, 208818.1365, 211373.115, 213946.7465, 216532.076, 219105.541, 221714.5375, 224337.5135, 226977.5125, 229613.0655, 232270.2685, 234952.2065, 237645.3555, 240331.1925, 243034.517, 245756.0725, 248517.6865, 251232.737, 254011.3955, 256785.995, 259556.44, 262368.335, 265156.911, 267965.266, 270785.583, 273616.0495, 276487.4835, 279346.639, 282202.509, 285074.3885, 287942.2855, 290856.018, 293774.0345, 296678.5145, 299603.6355, 302552.6575, 305492.9785, 308466.8605, 311392.581, 314347.538, 317319.4295, 320285.9785, 323301.7325, 326298.3235, 329301.3105, 332301.987, 335309.791, 338370.762, 341382.923, 344431.1265, 347464.1545, 350507.28, 353619.2345, 356631.2005, 359685.203, 362776.7845, 365886.488, 368958.2255, 372060.6825, 375165.4335, 378237.935, 381328.311, 384430.5225, 387576.425, 390683.242, 393839.648, 396977.8425, 400101.9805, 403271.296, 406409.8425, 409529.5485, 412678.7, 415847.423, 419020.8035, 422157.081, 425337.749, 428479.6165, 431700.902, 434893.1915, 438049.582, 441210.5415, 444379.2545, 447577.356, 450741.931, 453959.548, 457137.0935, 460329.846, 463537.4815, 466732.3345, 469960.5615, 473164.681, 476347.6345, 479496.173, 482813.1645, 486025.6995, 489249.4885, 492460.1945, 495675.8805, 498908.0075, 502131.802, 505374.3855, 508550.9915, 511806.7305, 515026.776, 518217.0005, 521523.9855, 524705.9855, 527950.997, 531210.0265, 534472.497, 537750.7315, 540926.922, 544207.094, 547429.4345, 550666.3745, 553975.3475, 557150.7185, 560399.6165, 563662.697, 566916.7395, 570146.1215, 573447.425, 576689.6245, 579874.5745, 583202.337, 586503.0255, 589715.635, 592910.161, 596214.3885, 599488.035, 602740.92, 605983.0685, 609248.67, 612491.3605, 615787.912, 619107.5245, 622307.9555, 625577.333, 628840.4385, 632085.2155, 635317.6135, 638691.7195, 641887.467, 645139.9405, 648441.546, 651666.252, 654941.845, }, + // precision 18 + (double[]) { 189084, 192250.913, 195456.774, 198696.946, 201977.762, 205294.444, 208651.754, 212042.099, 215472.269, 218941.91, 222443.912, 225996.845, 229568.199, 233193.568, 236844.457, 240543.233, 244279.475, 248044.27, 251854.588, 255693.2, 259583.619, 263494.621, 267445.385, 271454.061, 275468.769, 279549.456, 283646.446, 287788.198, 291966.099, 296181.164, 300431.469, 304718.618, 309024.004, 313393.508, 317760.803, 322209.731, 326675.061, 331160.627, 335654.47, 340241.442, 344841.833, 349467.132, 354130.629, 358819.432, 363574.626, 368296.587, 373118.482, 377914.93, 382782.301, 387680.669, 392601.981, 397544.323, 402529.115, 407546.018, 412593.658, 417638.657, 422762.865, 427886.169, 433017.167, 438213.273, 443441.254, 448692.421, 453937.533, 459239.049, 464529.569, 469910.083, 475274.03, 480684.473, 486070.26, 491515.237, 496995.651, 502476.617, 507973.609, 513497.19, 519083.233, 524726.509, 530305.505, 535945.728, 541584.404, 547274.055, 552967.236, 558667.862, 564360.216, 570128.148, 575965.08, 581701.952, 587532.523, 593361.144, 599246.128, 605033.418, 610958.779, 616837.117, 622772.818, 628672.04, 634675.369, 640574.831, 646585.739, 652574.547, 658611.217, 664642.684, 670713.914, 676737.681, 682797.313, 688837.897, 694917.874, 701009.882, 707173.648, 713257.254, 719415.392, 725636.761, 731710.697, 737906.209, 744103.074, 750313.39, 756504.185, 762712.579, 768876.985, 775167.859, 781359, 787615.959, 793863.597, 800245.477, 806464.582, 812785.294, 819005.925, 825403.057, 831676.197, 837936.284, 844266.968, 850642.711, 856959.756, 863322.774, 869699.931, 876102.478, 882355.787, 888694.463, 895159.952, 901536.143, 907872.631, 914293.672, 920615.14, 927130.974, 933409.404, 939922.178, 946331.47, 952745.93, 959209.264, 965590.224, 972077.284, 978501.961, 984953.19, 991413.271, 997817.479, 1004222.658, 1010725.676, 1017177.138, 1023612.529, 1030098.236, 1036493.719, 1043112.207, 1049537.036, 1056008.096, 1062476.184, 1068942.337, 1075524.95, 1081932.864, 1088426.025, 1094776.005, 1101327.448, 1107901.673, 1114423.639, 1120884.602, 1127324.923, 1133794.24, 1140328.886, 1146849.376, 1153346.682, 1159836.502, 1166478.703, 1172953.304, 1179391.502, 1185950.982, 1192544.052, 1198913.41, 1205430.994, 1212015.525, 1218674.042, 1225121.683, 1231551.101, 1238126.379, 1244673.795, 1251260.649, 1257697.86, 1264320.983, 1270736.319, 1277274.694, 1283804.95, 1290211.514, 1296858.568, 1303455.691, } +}; + +static const double *g_biasData[] = { + // precision 4 + (double[]) { 10, 9.717, 9.207, 8.7896, 8.2882, 7.8204, 7.3772, 6.9342, 6.5202, 6.161, 5.7722, 5.4636, 5.0396, 4.6766, 4.3566, 4.0454, 3.7936, 3.4856, 3.2666, 2.9946, 2.766, 2.4692, 2.3638, 2.0764, 1.7864, 1.7602, 1.4814, 1.433, 1.2926, 1.0664, 0.999600000000001, 0.7956, 0.5366, 0.589399999999998, 0.573799999999999, 0.269799999999996, 0.368200000000002, 0.0544000000000011, 0.234200000000001, 0.0108000000000033, -0.203400000000002, -0.0701999999999998, -0.129600000000003, -0.364199999999997, -0.480600000000003, -0.226999999999997, -0.322800000000001, -0.382599999999996, -0.511200000000002, -0.669600000000003, -0.749400000000001, -0.500399999999999, -0.617600000000003, -0.6922, -0.601599999999998, -0.416200000000003, -0.338200000000001, -0.782600000000002, -0.648600000000002, -0.919800000000002, -0.851799999999997, -0.962400000000002, -0.6402, -1.1922, -1.0256, -1.086, -1.21899999999999, -0.819400000000002, -0.940600000000003, -1.1554, -1.2072, -1.1752, -1.16759999999999, -1.14019999999999, -1.3754, -1.29859999999999, -1.607, -1.3292, -1.7606, }, + // precision 5 + (double[]) { 22, 21.1194, 20.8208, 20.2318, 19.77, 19.2436, 18.7774, 18.2848, 17.8224, 17.3742, 16.9336, 16.503, 16.0494, 15.6292, 15.2124, 14.798, 14.367, 13.9728, 13.5944, 13.217, 12.8438, 12.3696, 12.0956, 11.7044, 11.324, 11.0668, 10.6698, 10.3644, 10.049, 9.6918, 9.4146, 9.082, 8.687, 8.5398, 8.2462, 7.857, 7.6606, 7.4168, 7.1248, 6.9222, 6.6804, 6.447, 6.3454, 5.9594, 5.7636, 5.5776, 5.331, 5.19, 4.9676, 4.7564, 4.5314, 4.4442, 4.3708, 3.9774, 3.9624, 3.8796, 3.755, 3.472, 3.2076, 3.1024, 2.8908, 2.7338, 2.7728, 2.629, 2.413, 2.3266, 2.1524, 2.2642, 2.1806, 2.0566, 1.9192, 1.7598, 1.3516, 1.5802, 1.43859999999999, 1.49160000000001, 1.1524, 1.1892, 0.841399999999993, 0.879800000000003, 0.837599999999995, 0.469800000000006, 0.765600000000006, 0.331000000000003, 0.591399999999993, 0.601200000000006, 0.701599999999999, 0.558199999999999, 0.339399999999998, 0.354399999999998, 0.491200000000006, 0.308000000000007, 0.355199999999996, -0.0254000000000048, 0.205200000000005, -0.272999999999996, 0.132199999999997, 0.394400000000005, -0.241200000000006, 0.242000000000004, 0.191400000000002, 0.253799999999998, -0.122399999999999, -0.370800000000003, 0.193200000000004, -0.0848000000000013, 0.0867999999999967, -0.327200000000005, -0.285600000000002, 0.311400000000006, -0.128399999999999, -0.754999999999995, -0.209199999999996, -0.293599999999998, -0.364000000000004, -0.253600000000006, -0.821200000000005, -0.253600000000006, -0.510400000000004, -0.383399999999995, -0.491799999999998, -0.220200000000006, -0.0972000000000008, -0.557400000000001, -0.114599999999996, -0.295000000000002, -0.534800000000004, 0.346399999999988, -0.65379999999999, 0.0398000000000138, 0.0341999999999985, -0.995800000000003, -0.523400000000009, -0.489000000000004, -0.274799999999999, -0.574999999999989, -0.482799999999997, 0.0571999999999946, -0.330600000000004, -0.628800000000012, -0.140199999999993, -0.540600000000012, -0.445999999999998, -0.599400000000003, -0.262599999999992, 0.163399999999996, -0.100599999999986, -0.39500000000001, -1.06960000000001, -0.836399999999998, -0.753199999999993, -0.412399999999991, -0.790400000000005, -0.29679999999999, -0.28540000000001, -0.193000000000012, -0.0772000000000048, -0.962799999999987, -0.414800000000014, }, + // precision 6 + (double[]) { 45, 44.1902, 43.271, 42.8358, 41.8142, 41.2854, 40.317, 39.354, 38.8924, 37.9436, 37.4596, 36.5262, 35.6248, 35.1574, 34.2822, 33.837, 32.9636, 32.074, 31.7042, 30.7976, 30.4772, 29.6564, 28.7942, 28.5004, 27.686, 27.291, 26.5672, 25.8556, 25.4982, 24.8204, 24.4252, 23.7744, 23.0786, 22.8344, 22.0294, 21.8098, 21.0794, 20.5732, 20.1878, 19.5648, 19.2902, 18.6784, 18.3352, 17.8946, 17.3712, 17.0852, 16.499, 16.2686, 15.6844, 15.2234, 14.9732, 14.3356, 14.2286, 13.7262, 13.3284, 13.1048, 12.5962, 12.3562, 12.1272, 11.4184, 11.4974, 11.0822, 10.856, 10.48, 10.2834, 10.0208, 9.637, 9.51739999999999, 9.05759999999999, 8.74760000000001, 8.42700000000001, 8.1326, 8.2372, 8.2788, 7.6776, 7.79259999999999, 7.1952, 6.9564, 6.6454, 6.87, 6.5428, 6.19999999999999, 6.02940000000001, 5.62780000000001, 5.6782, 5.792, 5.35159999999999, 5.28319999999999, 5.0394, 5.07480000000001, 4.49119999999999, 4.84899999999999, 4.696, 4.54040000000001, 4.07300000000001, 4.37139999999999, 3.7216, 3.7328, 3.42080000000001, 3.41839999999999, 3.94239999999999, 3.27719999999999, 3.411, 3.13079999999999, 2.76900000000001, 2.92580000000001, 2.68279999999999, 2.75020000000001, 2.70599999999999, 2.3886, 3.01859999999999, 2.45179999999999, 2.92699999999999, 2.41720000000001, 2.41139999999999, 2.03299999999999, 2.51240000000001, 2.5564, 2.60079999999999, 2.41720000000001, 1.80439999999999, 1.99700000000001, 2.45480000000001, 1.8948, 2.2346, 2.30860000000001, 2.15479999999999, 1.88419999999999, 1.6508, 0.677199999999999, 1.72540000000001, 1.4752, 1.72280000000001, 1.66139999999999, 1.16759999999999, 1.79300000000001, 1.00059999999999, 0.905200000000008, 0.659999999999997, 1.55879999999999, 1.1636, 0.688199999999995, 0.712600000000009, 0.450199999999995, 1.1978, 0.975599999999986, 0.165400000000005, 1.727, 1.19739999999999, -0.252600000000001, 1.13460000000001, 1.3048, 1.19479999999999, 0.313400000000001, 0.878999999999991, 1.12039999999999, 0.853000000000009, 1.67920000000001, 0.856999999999999, 0.448599999999999, 1.2362, 0.953399999999988, 1.02859999999998, 0.563199999999995, 0.663000000000011, 0.723000000000013, 0.756599999999992, 0.256599999999992, -0.837600000000009, 0.620000000000005, 0.821599999999989, 0.216600000000028, 0.205600000000004, 0.220199999999977, 0.372599999999977, 0.334400000000016, 0.928400000000011, 0.972800000000007, 0.192400000000021, 0.487199999999973, -0.413000000000011, 0.807000000000016, 0.120600000000024, 0.769000000000005, 0.870799999999974, 0.66500000000002, 0.118200000000002, 0.401200000000017, 0.635199999999998, 0.135400000000004, 0.175599999999974, 1.16059999999999, 0.34620000000001, 0.521400000000028, -0.586599999999976, -1.16480000000001, 0.968399999999974, 0.836999999999989, 0.779600000000016, 0.985799999999983, }, + // precision 7 + (double[]) { 91, 89.4934, 87.9758, 86.4574, 84.9718, 83.4954, 81.5302, 80.0756, 78.6374, 77.1782, 75.7888, 73.9522, 72.592, 71.2532, 69.9086, 68.5938, 66.9474, 65.6796, 64.4394, 63.2176, 61.9768, 60.4214, 59.2528, 58.0102, 56.8658, 55.7278, 54.3044, 53.1316, 52.093, 51.0032, 49.9092, 48.6306, 47.5294, 46.5756, 45.6508, 44.662, 43.552, 42.3724, 41.617, 40.5754, 39.7872, 38.8444, 37.7988, 36.8606, 36.2118, 35.3566, 34.4476, 33.5882, 32.6816, 32.0824, 31.0258, 30.6048, 29.4436, 28.7274, 27.957, 27.147, 26.4364, 25.7592, 25.3386, 24.781, 23.8028, 23.656, 22.6544, 21.996, 21.4718, 21.1544, 20.6098, 19.5956, 19.0616, 18.5758, 18.4878, 17.5244, 17.2146, 16.724, 15.8722, 15.5198, 15.0414, 14.941, 14.9048, 13.87, 13.4304, 13.028, 12.4708, 12.37, 12.0624, 11.4668, 11.5532, 11.4352, 11.2564, 10.2744, 10.2118, 9.74720000000002, 10.1456, 9.2928, 8.75040000000001, 8.55279999999999, 8.97899999999998, 8.21019999999999, 8.18340000000001, 7.3494, 7.32499999999999, 7.66140000000001, 6.90300000000002, 7.25439999999998, 6.9042, 7.21499999999997, 6.28640000000001, 6.08139999999997, 6.6764, 6.30099999999999, 5.13900000000001, 5.65800000000002, 5.17320000000001, 4.59019999999998, 4.9538, 5.08280000000002, 4.92200000000003, 4.99020000000002, 4.7328, 5.4538, 4.11360000000002, 4.22340000000003, 4.08780000000002, 3.70800000000003, 4.15559999999999, 4.18520000000001, 3.63720000000001, 3.68220000000002, 3.77960000000002, 3.6078, 2.49160000000001, 3.13099999999997, 2.5376, 3.19880000000001, 3.21100000000001, 2.4502, 3.52820000000003, 2.91199999999998, 3.04480000000001, 2.7432, 2.85239999999999, 2.79880000000003, 2.78579999999999, 1.88679999999999, 2.98860000000002, 2.50639999999999, 1.91239999999999, 2.66160000000002, 2.46820000000002, 1.58199999999999, 1.30399999999997, 2.27379999999999, 2.68939999999998, 1.32900000000001, 3.10599999999999, 1.69080000000002, 2.13740000000001, 2.53219999999999, 1.88479999999998, 1.33240000000001, 1.45119999999997, 1.17899999999997, 2.44119999999998, 1.60659999999996, 2.16700000000003, 0.77940000000001, 2.37900000000002, 2.06700000000001, 1.46000000000004, 2.91160000000002, 1.69200000000001, 0.954600000000028, 2.49300000000005, 2.2722, 1.33500000000004, 2.44899999999996, 1.20140000000004, 3.07380000000001, 2.09739999999999, 2.85640000000001, 2.29960000000005, 2.40899999999999, 1.97040000000004, 0.809799999999996, 1.65279999999996, 2.59979999999996, 0.95799999999997, 2.06799999999998, 2.32780000000002, 4.20159999999998, 1.96320000000003, 1.86400000000003, 1.42999999999995, 3.77940000000001, 1.27200000000005, 1.86440000000005, 2.20600000000002, 3.21900000000005, 1.5154, 2.61019999999996, }, + // precision 8 + (double[]) { 183.2152, 180.2454, 177.2096, 173.6652, 170.6312, 167.6822, 164.249, 161.3296, 158.0038, 155.2074, 152.4612, 149.27, 146.5178, 143.4412, 140.8032, 138.1634, 135.1688, 132.6074, 129.6946, 127.2664, 124.8228, 122.0432, 119.6824, 116.9464, 114.6268, 112.2626, 109.8376, 107.4034, 104.8956, 102.8522, 100.7638, 98.3552, 96.3556, 93.7526, 91.9292, 89.8954, 87.8198, 85.7668, 83.298, 81.6688, 79.9466, 77.9746, 76.1672, 74.3474, 72.3028, 70.8912, 69.114, 67.4646, 65.9744, 64.4092, 62.6022, 60.843, 59.5684, 58.1652, 56.5426, 55.4152, 53.5388, 52.3592, 51.1366, 49.486, 48.3918, 46.5076, 45.509, 44.3834, 43.3498, 42.0668, 40.7346, 40.1228, 38.4528, 37.7, 36.644, 36.0518, 34.5774, 33.9068, 32.432, 32.1666, 30.434, 29.6644, 28.4894, 27.6312, 26.3804, 26.292, 25.5496000000001, 25.0234, 24.8206, 22.6146, 22.4188, 22.117, 20.6762, 20.6576, 19.7864, 19.509, 18.5334, 17.9204, 17.772, 16.2924, 16.8654, 15.1836, 15.745, 15.1316, 15.0386, 14.0136, 13.6342, 12.6196, 12.1866, 12.4281999999999, 11.3324, 10.4794000000001, 11.5038, 10.129, 9.52800000000002, 10.3203999999999, 9.46299999999997, 9.79280000000006, 9.12300000000005, 8.74180000000001, 9.2192, 7.51020000000005, 7.60659999999996, 7.01840000000004, 7.22239999999999, 7.40139999999997, 6.76179999999999, 7.14359999999999, 5.65060000000005, 5.63779999999997, 5.76599999999996, 6.75139999999999, 5.57759999999996, 3.73220000000003, 5.8048, 5.63019999999995, 4.93359999999996, 3.47979999999995, 4.33879999999999, 3.98940000000005, 3.81960000000004, 3.31359999999995, 3.23080000000004, 3.4588, 3.08159999999998, 3.4076, 3.00639999999999, 2.38779999999997, 2.61900000000003, 1.99800000000005, 3.34820000000002, 2.95060000000001, 0.990999999999985, 2.11440000000005, 2.20299999999997, 2.82219999999995, 2.73239999999998, 2.7826, 3.76660000000004, 2.26480000000004, 2.31280000000004, 2.40819999999997, 2.75360000000001, 3.33759999999995, 2.71559999999999, 1.7478000000001, 1.42920000000004, 2.39300000000003, 2.22779999999989, 2.34339999999997, 0.87259999999992, 3.88400000000001, 1.80600000000004, 1.91759999999999, 1.16779999999994, 1.50320000000011, 2.52500000000009, 0.226400000000012, 2.31500000000005, 0.930000000000064, 1.25199999999995, 2.14959999999996, 0.0407999999999902, 2.5447999999999, 1.32960000000003, 0.197400000000016, 2.52620000000002, 3.33279999999991, -1.34300000000007, 0.422199999999975, 0.917200000000093, 1.12920000000008, 1.46060000000011, 1.45779999999991, 2.8728000000001, 3.33359999999993, -1.34079999999994, 1.57680000000005, 0.363000000000056, 1.40740000000005, 0.656600000000026, 0.801400000000058, -0.454600000000028, 1.51919999999996, }, + // precision 9 + (double[]) { 368, 361.8294, 355.2452, 348.6698, 342.1464, 336.2024, 329.8782, 323.6598, 317.462, 311.2826, 305.7102, 299.7416, 293.9366, 288.1046, 282.285, 277.0668, 271.306, 265.8448, 260.301, 254.9886, 250.2422, 244.8138, 239.7074, 234.7428, 229.8402, 225.1664, 220.3534, 215.594, 210.6886, 205.7876, 201.65, 197.228, 192.8036, 188.1666, 184.0818, 180.0824, 176.2574, 172.302, 168.1644, 164.0056, 160.3802, 156.7192, 152.5234, 149.2084, 145.831, 142.485, 139.1112, 135.4764, 131.76, 129.3368, 126.5538, 122.5058, 119.2646, 116.5902, 113.3818, 110.8998, 107.9532, 105.2062, 102.2798, 99.4728, 96.9582, 94.3292, 92.171, 89.7809999999999, 87.5716, 84.7048, 82.5322, 79.875, 78.3972, 75.3464, 73.7274, 71.2834, 70.1444, 68.4263999999999, 66.0166, 64.018, 62.0437999999999, 60.3399999999999, 58.6856, 57.9836, 55.0311999999999, 54.6769999999999, 52.3188, 51.4846, 49.4423999999999, 47.739, 46.1487999999999, 44.9202, 43.4059999999999, 42.5342000000001, 41.2834, 38.8954000000001, 38.3286000000001, 36.2146, 36.6684, 35.9946, 33.123, 33.4338, 31.7378000000001, 29.076, 28.9692, 27.4964, 27.0998, 25.9864, 26.7754, 24.3208, 23.4838, 22.7388000000001, 24.0758000000001, 21.9097999999999, 20.9728, 19.9228000000001, 19.9292, 16.617, 17.05, 18.2996000000001, 15.6128000000001, 15.7392, 14.5174, 13.6322, 12.2583999999999, 13.3766000000001, 11.423, 13.1232, 9.51639999999998, 10.5938000000001, 9.59719999999993, 8.12220000000002, 9.76739999999995, 7.50440000000003, 7.56999999999994, 6.70440000000008, 6.41419999999994, 6.71019999999999, 5.60940000000005, 4.65219999999999, 6.84099999999989, 3.4072000000001, 3.97859999999991, 3.32760000000007, 5.52160000000003, 3.31860000000006, 2.06940000000009, 4.35400000000004, 1.57500000000005, 0.280799999999999, 2.12879999999996, -0.214799999999968, -0.0378000000000611, -0.658200000000079, 0.654800000000023, -0.0697999999999865, 0.858400000000074, -2.52700000000004, -2.1751999999999, -3.35539999999992, -1.04019999999991, -0.651000000000067, -2.14439999999991, -1.96659999999997, -3.97939999999994, -0.604400000000169, -3.08260000000018, -3.39159999999993, -5.29640000000018, -5.38920000000007, -5.08759999999984, -4.69900000000007, -5.23720000000003, -3.15779999999995, -4.97879999999986, -4.89899999999989, -7.48880000000008, -5.94799999999987, -5.68060000000014, -6.67180000000008, -4.70499999999993, -7.27779999999984, -4.6579999999999, -4.4362000000001, -4.32139999999981, -5.18859999999995, -6.66879999999992, -6.48399999999992, -5.1260000000002, -4.4032000000002, -6.13500000000022, -5.80819999999994, -4.16719999999987, -4.15039999999999, -7.45600000000013, -7.24080000000004, -9.83179999999993, -5.80420000000004, -8.6561999999999, -6.99940000000015, -10.5473999999999, -7.34139999999979, -6.80999999999995, -6.29719999999998, -6.23199999999997, }, + // precision 10 + (double[]) { 737.1256, 724.4234, 711.1064, 698.4732, 685.4636, 673.0644, 660.488, 647.9654, 636.0832, 623.7864, 612.1992, 600.2176, 588.5228, 577.1716, 565.7752, 554.899, 543.6126, 532.6492, 521.9474, 511.5214, 501.1064, 490.6364, 480.2468, 470.4588, 460.3832, 451.0584, 440.8606, 431.3868, 422.5062, 413.1862, 404.463, 395.339, 386.1936, 378.1292, 369.1854, 361.2908, 353.3324, 344.8518, 337.5204, 329.4854, 321.9318, 314.552, 306.4658, 299.4256, 292.849, 286.152, 278.8956, 271.8792, 265.118, 258.62, 252.5132, 245.9322, 239.7726, 233.6086, 227.5332, 222.5918, 216.4294, 210.7662, 205.4106, 199.7338, 194.9012, 188.4486, 183.1556, 178.6338, 173.7312, 169.6264, 163.9526, 159.8742, 155.8326, 151.1966, 147.5594, 143.07, 140.037, 134.1804, 131.071, 127.4884, 124.0848, 120.2944, 117.333, 112.9626, 110.2902, 107.0814, 103.0334, 99.4832000000001, 96.3899999999999, 93.7202000000002, 90.1714000000002, 87.2357999999999, 85.9346, 82.8910000000001, 80.0264000000002, 78.3834000000002, 75.1543999999999, 73.8683999999998, 70.9895999999999, 69.4367999999999, 64.8701999999998, 65.0408000000002, 61.6738, 59.5207999999998, 57.0158000000001, 54.2302, 53.0962, 50.4985999999999, 52.2588000000001, 47.3914, 45.6244000000002, 42.8377999999998, 43.0072, 40.6516000000001, 40.2453999999998, 35.2136, 36.4546, 33.7849999999999, 33.2294000000002, 32.4679999999998, 30.8670000000002, 28.6507999999999, 28.9099999999999, 27.5983999999999, 26.1619999999998, 24.5563999999999, 23.2328000000002, 21.9484000000002, 21.5902000000001, 21.3346000000001, 17.7031999999999, 20.6111999999998, 19.5545999999999, 15.7375999999999, 17.0720000000001, 16.9517999999998, 15.326, 13.1817999999998, 14.6925999999999, 13.0859999999998, 13.2754, 10.8697999999999, 11.248, 7.3768, 4.72339999999986, 7.97899999999981, 8.7503999999999, 7.68119999999999, 9.7199999999998, 7.73919999999998, 5.6224000000002, 7.44560000000001, 6.6601999999998, 5.9058, 4.00199999999995, 4.51699999999983, 4.68240000000014, 3.86220000000003, 5.13639999999987, 5.98500000000013, 2.47719999999981, 2.61999999999989, 1.62800000000016, 4.65000000000009, 0.225599999999758, 0.831000000000131, -0.359400000000278, 1.27599999999984, -2.92559999999958, -0.0303999999996449, 2.37079999999969, -2.0033999999996, 0.804600000000391, 0.30199999999968, 1.1247999999996, -2.6880000000001, 0.0321999999996478, -1.18099999999959, -3.9402, -1.47940000000017, -0.188400000000001, -2.10720000000038, -2.04159999999956, -3.12880000000041, -4.16160000000036, -0.612799999999879, -3.48719999999958, -8.17900000000009, -5.37780000000021, -4.01379999999972, -5.58259999999973, -5.73719999999958, -7.66799999999967, -5.69520000000011, -1.1247999999996, -5.58520000000044, -8.04560000000038, -4.64840000000004, -11.6468000000004, -7.97519999999986, -5.78300000000036, -7.67420000000038, -10.6328000000003, -9.81720000000041, }, + // precision 11 + (double[]) { 1476, 1449.6014, 1423.5802, 1397.7942, 1372.3042, 1347.2062, 1321.8402, 1297.2292, 1272.9462, 1248.9926, 1225.3026, 1201.4252, 1178.0578, 1155.6092, 1132.626, 1110.5568, 1088.527, 1066.5154, 1045.1874, 1024.3878, 1003.37, 982.1972, 962.5728, 942.1012, 922.9668, 903.292, 884.0772, 864.8578, 846.6562, 828.041, 809.714, 792.3112, 775.1806, 757.9854, 740.656, 724.346, 707.5154, 691.8378, 675.7448, 659.6722, 645.5722, 630.1462, 614.4124, 600.8728, 585.898, 572.408, 558.4926, 544.4938, 531.6776, 517.282, 505.7704, 493.1012, 480.7388, 467.6876, 456.1872, 445.5048, 433.0214, 420.806, 411.409, 400.4144, 389.4294, 379.2286, 369.651, 360.6156, 350.337, 342.083, 332.1538, 322.5094, 315.01, 305.6686, 298.1678, 287.8116, 280.9978, 271.9204, 265.3286, 257.5706, 249.6014, 242.544, 235.5976, 229.583, 220.9438, 214.672, 208.2786, 201.8628, 195.1834, 191.505, 186.1816, 178.5188, 172.2294, 167.8908, 161.0194, 158.052, 151.4588, 148.1596, 143.4344, 138.5238, 133.13, 127.6374, 124.8162, 118.7894, 117.3984, 114.6078, 109.0858, 105.1036, 103.6258, 98.6018000000004, 95.7618000000002, 93.5821999999998, 88.5900000000001, 86.9992000000002, 82.8800000000001, 80.4539999999997, 74.6981999999998, 74.3644000000004, 73.2914000000001, 65.5709999999999, 66.9232000000002, 65.1913999999997, 62.5882000000001, 61.5702000000001, 55.7035999999998, 56.1764000000003, 52.7596000000003, 53.0302000000001, 49.0609999999997, 48.4694, 44.933, 46.0474000000004, 44.7165999999997, 41.9416000000001, 39.9207999999999, 35.6328000000003, 35.5276000000003, 33.1934000000001, 33.2371999999996, 33.3864000000003, 33.9228000000003, 30.2371999999996, 29.1373999999996, 25.2272000000003, 24.2942000000003, 19.8338000000003, 18.9005999999999, 23.0907999999999, 21.8544000000002, 19.5176000000001, 15.4147999999996, 16.9314000000004, 18.6737999999996, 12.9877999999999, 14.3688000000002, 12.0447999999997, 15.5219999999999, 12.5299999999997, 14.5940000000001, 14.3131999999996, 9.45499999999993, 12.9441999999999, 3.91139999999996, 13.1373999999996, 5.44720000000052, 9.82779999999912, 7.87279999999919, 3.67760000000089, 5.46980000000076, 5.55099999999948, 5.65979999999945, 3.89439999999922, 3.1275999999998, 5.65140000000065, 6.3062000000009, 3.90799999999945, 1.87060000000019, 5.17020000000048, 2.46680000000015, 0.770000000000437, -3.72340000000077, 1.16400000000067, 8.05340000000069, 0.135399999999208, 2.15940000000046, 0.766999999999825, 1.0594000000001, 3.15500000000065, -0.287399999999252, 2.37219999999979, -2.86620000000039, -1.63199999999961, -2.22979999999916, -0.15519999999924, -1.46039999999994, -0.262199999999211, -2.34460000000036, -2.8078000000005, -3.22179999999935, -5.60159999999996, -8.42200000000048, -9.43740000000071, 0.161799999999857, -10.4755999999998, -10.0823999999993, }, + // precision 12 + (double[]) { 2953, 2900.4782, 2848.3568, 2796.3666, 2745.324, 2694.9598, 2644.648, 2595.539, 2546.1474, 2498.2576, 2450.8376, 2403.6076, 2357.451, 2311.38, 2266.4104, 2221.5638, 2176.9676, 2134.193, 2090.838, 2048.8548, 2007.018, 1966.1742, 1925.4482, 1885.1294, 1846.4776, 1807.4044, 1768.8724, 1731.3732, 1693.4304, 1657.5326, 1621.949, 1586.5532, 1551.7256, 1517.6182, 1483.5186, 1450.4528, 1417.865, 1385.7164, 1352.6828, 1322.6708, 1291.8312, 1260.9036, 1231.476, 1201.8652, 1173.6718, 1145.757, 1119.2072, 1092.2828, 1065.0434, 1038.6264, 1014.3192, 988.5746, 965.0816, 940.1176, 917.9796, 894.5576, 871.1858, 849.9144, 827.1142, 805.0818, 783.9664, 763.9096, 742.0816, 724.3962, 706.3454, 688.018, 667.4214, 650.3106, 633.0686, 613.8094, 597.818, 581.4248, 563.834, 547.363, 531.5066, 520.455400000001, 505.583199999999, 488.366, 476.480799999999, 459.7682, 450.0522, 434.328799999999, 423.952799999999, 408.727000000001, 399.079400000001, 387.252200000001, 373.987999999999, 360.852000000001, 351.6394, 339.642, 330.902400000001, 322.661599999999, 311.662200000001, 301.3254, 291.7484, 279.939200000001, 276.7508, 263.215200000001, 254.811400000001, 245.5494, 242.306399999999, 234.8734, 223.787200000001, 217.7156, 212.0196, 200.793, 195.9748, 189.0702, 182.449199999999, 177.2772, 170.2336, 164.741, 158.613600000001, 155.311, 147.5964, 142.837, 137.3724, 132.0162, 130.0424, 121.9804, 120.451800000001, 114.8968, 111.585999999999, 105.933199999999, 101.705, 98.5141999999996, 95.0488000000005, 89.7880000000005, 91.4750000000004, 83.7764000000006, 80.9698000000008, 72.8574000000008, 73.1615999999995, 67.5838000000003, 62.6263999999992, 63.2638000000006, 66.0977999999996, 52.0843999999997, 58.9956000000002, 47.0912000000008, 46.4956000000002, 48.4383999999991, 47.1082000000006, 43.2392, 37.2759999999998, 40.0283999999992, 35.1864000000005, 35.8595999999998, 32.0998, 28.027, 23.6694000000007, 33.8266000000003, 26.3736000000008, 27.2008000000005, 21.3245999999999, 26.4115999999995, 23.4521999999997, 19.5013999999992, 19.8513999999996, 10.7492000000002, 18.6424000000006, 13.1265999999996, 18.2436000000016, 6.71860000000015, 3.39459999999963, 6.33759999999893, 7.76719999999841, 0.813999999998487, 3.82819999999992, 0.826199999999517, 8.07440000000133, -1.59080000000176, 5.01780000000144, 0.455399999998917, -0.24199999999837, 0.174800000000687, -9.07640000000174, -4.20160000000033, -3.77520000000004, -4.75179999999818, -5.3724000000002, -8.90680000000066, -6.10239999999976, -5.74120000000039, -9.95339999999851, -3.86339999999836, -13.7304000000004, -16.2710000000006, -7.51359999999841, -3.30679999999847, -13.1339999999982, -10.0551999999989, -6.72019999999975, -8.59660000000076, -10.9307999999983, -1.8775999999998, -4.82259999999951, -13.7788, -21.6470000000008, -10.6735999999983, -15.7799999999988, }, + // precision 13 + (double[]) { 5907.5052, 5802.2672, 5697.347, 5593.5794, 5491.2622, 5390.5514, 5290.3376, 5191.6952, 5093.5988, 4997.3552, 4902.5972, 4808.3082, 4715.5646, 4624.109, 4533.8216, 4444.4344, 4356.3802, 4269.2962, 4183.3784, 4098.292, 4014.79, 3932.4574, 3850.6036, 3771.2712, 3691.7708, 3615.099, 3538.1858, 3463.4746, 3388.8496, 3315.6794, 3244.5448, 3173.7516, 3103.3106, 3033.6094, 2966.5642, 2900.794, 2833.7256, 2769.81, 2707.3196, 2644.0778, 2583.9916, 2523.4662, 2464.124, 2406.073, 2347.0362, 2292.1006, 2238.1716, 2182.7514, 2128.4884, 2077.1314, 2025.037, 1975.3756, 1928.933, 1879.311, 1831.0006, 1783.2144, 1738.3096, 1694.5144, 1649.024, 1606.847, 1564.7528, 1525.3168, 1482.5372, 1443.9668, 1406.5074, 1365.867, 1329.2186, 1295.4186, 1257.9716, 1225.339, 1193.2972, 1156.3578, 1125.8686, 1091.187, 1061.4094, 1029.4188, 1000.9126, 972.3272, 944.004199999999, 915.7592, 889.965, 862.834200000001, 840.4254, 812.598399999999, 785.924200000001, 763.050999999999, 741.793799999999, 721.466, 699.040799999999, 677.997200000002, 649.866999999998, 634.911800000002, 609.8694, 591.981599999999, 570.2922, 557.129199999999, 538.3858, 521.872599999999, 502.951400000002, 495.776399999999, 475.171399999999, 459.751, 439.995200000001, 426.708999999999, 413.7016, 402.3868, 387.262599999998, 372.0524, 357.050999999999, 342.5098, 334.849200000001, 322.529399999999, 311.613799999999, 295.848000000002, 289.273000000001, 274.093000000001, 263.329600000001, 251.389599999999, 245.7392, 231.9614, 229.7952, 217.155200000001, 208.9588, 199.016599999999, 190.839199999999, 180.6976, 176.272799999999, 166.976999999999, 162.5252, 151.196400000001, 149.386999999999, 133.981199999998, 130.0586, 130.164000000001, 122.053400000001, 110.7428, 108.1276, 106.232400000001, 100.381600000001, 98.7668000000012, 86.6440000000002, 79.9768000000004, 82.4722000000002, 68.7026000000005, 70.1186000000016, 71.9948000000004, 58.998599999999, 59.0492000000013, 56.9818000000014, 47.5338000000011, 42.9928, 51.1591999999982, 37.2740000000013, 42.7220000000016, 31.3734000000004, 26.8090000000011, 25.8934000000008, 26.5286000000015, 29.5442000000003, 19.3503999999994, 26.0760000000009, 17.9527999999991, 14.8419999999969, 10.4683999999979, 8.65899999999965, 9.86720000000059, 4.34139999999752, -0.907800000000861, -3.32080000000133, -0.936199999996461, -11.9916000000012, -8.87000000000262, -6.33099999999831, -11.3366000000024, -15.9207999999999, -9.34659999999712, -15.5034000000014, -19.2097999999969, -15.357799999998, -28.2235999999975, -30.6898000000001, -19.3271999999997, -25.6083999999973, -24.409599999999, -13.6385999999984, -33.4473999999973, -32.6949999999997, -28.9063999999998, -31.7483999999968, -32.2935999999972, -35.8329999999987, -47.620600000002, -39.0855999999985, -33.1434000000008, -46.1371999999974, -37.5892000000022, -46.8164000000033, -47.3142000000007, -60.2914000000019, -37.7575999999972, }, + // precision 14 + (double[]) { 11816.475, 11605.0046, 11395.3792, 11188.7504, 10984.1814, 10782.0086, 10582.0072, 10384.503, 10189.178, 9996.2738, 9806.0344, 9617.9798, 9431.394, 9248.7784, 9067.6894, 8889.6824, 8712.9134, 8538.8624, 8368.4944, 8197.7956, 8031.8916, 7866.6316, 7703.733, 7544.5726, 7386.204, 7230.666, 7077.8516, 6926.7886, 6778.6902, 6631.9632, 6487.304, 6346.7486, 6206.4408, 6070.202, 5935.2576, 5799.924, 5671.0324, 5541.9788, 5414.6112, 5290.0274, 5166.723, 5047.6906, 4929.162, 4815.1406, 4699.127, 4588.5606, 4477.7394, 4369.4014, 4264.2728, 4155.9224, 4055.581, 3955.505, 3856.9618, 3761.3828, 3666.9702, 3575.7764, 3482.4132, 3395.0186, 3305.8852, 3221.415, 3138.6024, 3056.296, 2970.4494, 2896.1526, 2816.8008, 2740.2156, 2670.497, 2594.1458, 2527.111, 2460.8168, 2387.5114, 2322.9498, 2260.6752, 2194.2686, 2133.7792, 2074.767, 2015.204, 1959.4226, 1898.6502, 1850.006, 1792.849, 1741.4838, 1687.9778, 1638.1322, 1589.3266, 1543.1394, 1496.8266, 1447.8516, 1402.7354, 1361.9606, 1327.0692, 1285.4106, 1241.8112, 1201.6726, 1161.973, 1130.261, 1094.2036, 1048.2036, 1020.6436, 990.901400000002, 961.199800000002, 924.769800000002, 899.526400000002, 872.346400000002, 834.375, 810.432000000001, 780.659800000001, 756.013800000001, 733.479399999997, 707.923999999999, 673.858, 652.222399999999, 636.572399999997, 615.738599999997, 586.696400000001, 564.147199999999, 541.679600000003, 523.943599999999, 505.714599999999, 475.729599999999, 461.779600000002, 449.750800000002, 439.020799999998, 412.7886, 400.245600000002, 383.188199999997, 362.079599999997, 357.533799999997, 334.319000000003, 327.553399999997, 308.559399999998, 291.270199999999, 279.351999999999, 271.791400000002, 252.576999999997, 247.482400000001, 236.174800000001, 218.774599999997, 220.155200000001, 208.794399999999, 201.223599999998, 182.995600000002, 185.5268, 164.547400000003, 176.5962, 150.689599999998, 157.8004, 138.378799999999, 134.021200000003, 117.614399999999, 108.194000000003, 97.0696000000025, 89.6042000000016, 95.6030000000028, 84.7810000000027, 72.635000000002, 77.3482000000004, 59.4907999999996, 55.5875999999989, 50.7346000000034, 61.3916000000027, 50.9149999999936, 39.0384000000049, 58.9395999999979, 29.633600000001, 28.2032000000036, 26.0078000000067, 17.0387999999948, 9.22000000000116, 13.8387999999977, 8.07240000000456, 14.1549999999988, 15.3570000000036, 3.42660000000615, 6.24820000000182, -2.96940000000177, -8.79940000000352, -5.97860000000219, -14.4048000000039, -3.4143999999942, -13.0148000000045, -11.6977999999945, -25.7878000000055, -22.3185999999987, -24.409599999999, -31.9756000000052, -18.9722000000038, -22.8678000000073, -30.8972000000067, -32.3715999999986, -22.3907999999938, -43.6720000000059, -35.9038, -39.7492000000057, -54.1641999999993, -45.2749999999942, -42.2989999999991, -44.1089999999967, -64.3564000000042, -49.9551999999967, -42.6116000000038, }, + // precision 15 + (double[]) { 23634.0036, 23210.8034, 22792.4744, 22379.1524, 21969.7928, 21565.326, 21165.3532, 20770.2806, 20379.9892, 19994.7098, 19613.318, 19236.799, 18865.4382, 18498.8244, 18136.5138, 17778.8668, 17426.2344, 17079.32, 16734.778, 16397.2418, 16063.3324, 15734.0232, 15409.731, 15088.728, 14772.9896, 14464.1402, 14157.5588, 13855.5958, 13559.3296, 13264.9096, 12978.326, 12692.0826, 12413.8816, 12137.3192, 11870.2326, 11602.5554, 11340.3142, 11079.613, 10829.5908, 10583.5466, 10334.0344, 10095.5072, 9859.694, 9625.2822, 9395.7862, 9174.0586, 8957.3164, 8738.064, 8524.155, 8313.7396, 8116.9168, 7913.542, 7718.4778, 7521.65, 7335.5596, 7154.2906, 6968.7396, 6786.3996, 6613.236, 6437.406, 6270.6598, 6107.7958, 5945.7174, 5787.6784, 5635.5784, 5482.308, 5337.9784, 5190.0864, 5045.9158, 4919.1386, 4771.817, 4645.7742, 4518.4774, 4385.5454, 4262.6622, 4142.74679999999, 4015.5318, 3897.9276, 3790.7764, 3685.13800000001, 3573.6274, 3467.9706, 3368.61079999999, 3271.5202, 3170.3848, 3076.4656, 2982.38400000001, 2888.4664, 2806.4868, 2711.9564, 2634.1434, 2551.3204, 2469.7662, 2396.61139999999, 2318.9902, 2243.8658, 2171.9246, 2105.01360000001, 2028.8536, 1960.9952, 1901.4096, 1841.86079999999, 1777.54700000001, 1714.5802, 1654.65059999999, 1596.311, 1546.2016, 1492.3296, 1433.8974, 1383.84600000001, 1339.4152, 1293.5518, 1245.8686, 1193.50659999999, 1162.27959999999, 1107.19439999999, 1069.18060000001, 1035.09179999999, 999.679000000004, 957.679999999993, 925.300199999998, 888.099400000006, 848.638600000006, 818.156400000007, 796.748399999997, 752.139200000005, 725.271200000003, 692.216, 671.633600000001, 647.939799999993, 621.670599999998, 575.398799999995, 561.226599999995, 532.237999999998, 521.787599999996, 483.095799999996, 467.049599999998, 465.286399999997, 415.548599999995, 401.047399999996, 380.607999999993, 377.362599999993, 347.258799999996, 338.371599999999, 310.096999999994, 301.409199999995, 276.280799999993, 265.586800000005, 258.994399999996, 223.915999999997, 215.925399999993, 213.503800000006, 191.045400000003, 166.718200000003, 166.259000000005, 162.941200000001, 148.829400000002, 141.645999999993, 123.535399999993, 122.329800000007, 89.473399999988, 80.1962000000058, 77.5457999999926, 59.1056000000099, 83.3509999999951, 52.2906000000075, 36.3979999999865, 40.6558000000077, 42.0003999999899, 19.6630000000005, 19.7153999999864, -8.38539999999921, -0.692799999989802, 0.854800000000978, 3.23219999999856, -3.89040000000386, -5.25880000001052, -24.9052000000083, -22.6837999999989, -26.4286000000138, -34.997000000003, -37.0216000000073, -43.430400000012, -58.2390000000014, -68.8034000000043, -56.9245999999985, -57.8583999999973, -77.3097999999882, -73.2793999999994, -81.0738000000129, -87.4530000000086, -65.0254000000132, -57.296399999992, -96.2746000000043, -103.25, -96.081600000005, -91.5542000000132, -102.465200000006, -107.688599999994, -101.458000000013, -109.715800000005, }, + // precision 16 + (double[]) { 47270, 46423.3584, 45585.7074, 44757.152, 43938.8416, 43130.9514, 42330.03, 41540.407, 40759.6348, 39988.206, 39226.5144, 38473.2096, 37729.795, 36997.268, 36272.6448, 35558.665, 34853.0248, 34157.4472, 33470.5204, 32793.5742, 32127.0194, 31469.4182, 30817.6136, 30178.6968, 29546.8908, 28922.8544, 28312.271, 27707.0924, 27114.0326, 26526.692, 25948.6336, 25383.7826, 24823.5998, 24272.2974, 23732.2572, 23201.4976, 22674.2796, 22163.6336, 21656.515, 21161.7362, 20669.9368, 20189.4424, 19717.3358, 19256.3744, 18795.9638, 18352.197, 17908.5738, 17474.391, 17052.918, 16637.2236, 16228.4602, 15823.3474, 15428.6974, 15043.0284, 14667.6278, 14297.4588, 13935.2882, 13578.5402, 13234.6032, 12882.1578, 12548.0728, 12219.231, 11898.0072, 11587.2626, 11279.9072, 10973.5048, 10678.5186, 10392.4876, 10105.2556, 9825.766, 9562.5444, 9294.2222, 9038.2352, 8784.848, 8533.2644, 8301.7776, 8058.30859999999, 7822.94579999999, 7599.11319999999, 7366.90779999999, 7161.217, 6957.53080000001, 6736.212, 6548.21220000001, 6343.06839999999, 6156.28719999999, 5975.15419999999, 5791.75719999999, 5621.32019999999, 5451.66, 5287.61040000001, 5118.09479999999, 4957.288, 4798.4246, 4662.17559999999, 4512.05900000001, 4364.68539999999, 4220.77720000001, 4082.67259999999, 3957.19519999999, 3842.15779999999, 3699.3328, 3583.01180000001, 3473.8964, 3338.66639999999, 3233.55559999999, 3117.799, 3008.111, 2909.69140000001, 2814.86499999999, 2719.46119999999, 2624.742, 2532.46979999999, 2444.7886, 2370.1868, 2272.45259999999, 2196.19260000001, 2117.90419999999, 2023.2972, 1969.76819999999, 1885.58979999999, 1833.2824, 1733.91200000001, 1682.54920000001, 1604.57980000001, 1556.11240000001, 1491.3064, 1421.71960000001, 1371.22899999999, 1322.1324, 1264.7892, 1196.23920000001, 1143.8474, 1088.67240000001, 1073.60380000001, 1023.11660000001, 959.036400000012, 927.433199999999, 906.792799999996, 853.433599999989, 841.873800000001, 791.1054, 756.899999999994, 704.343200000003, 672.495599999995, 622.790399999998, 611.254799999995, 567.283200000005, 519.406599999988, 519.188400000014, 495.312800000014, 451.350799999986, 443.973399999988, 431.882199999993, 392.027000000002, 380.924200000009, 345.128999999986, 298.901400000002, 287.771999999997, 272.625, 247.253000000026, 222.490600000019, 223.590000000026, 196.407599999977, 176.425999999978, 134.725199999986, 132.4804, 110.445599999977, 86.7939999999944, 56.7038000000175, 64.915399999998, 38.3726000000024, 37.1606000000029, 46.170999999973, 49.1716000000015, 15.3362000000197, 6.71639999997569, -34.8185999999987, -39.4476000000141, 12.6830000000191, -12.3331999999937, -50.6565999999875, -59.9538000000175, -65.1054000000004, -70.7576000000117, -106.325200000021, -126.852200000023, -110.227599999984, -132.885999999999, -113.897200000007, -142.713800000027, -151.145399999979, -150.799200000009, -177.756200000003, -156.036399999983, -182.735199999996, -177.259399999981, -198.663600000029, -174.577600000019, -193.84580000001, }, + // precision 17 + (double[]) { 94541, 92848.811, 91174.019, 89517.558, 87879.9705, 86262.7565, 84663.5125, 83083.7435, 81521.7865, 79977.272, 78455.9465, 76950.219, 75465.432, 73994.152, 72546.71, 71115.2345, 69705.6765, 68314.937, 66944.2705, 65591.255, 64252.9485, 62938.016, 61636.8225, 60355.592, 59092.789, 57850.568, 56624.518, 55417.343, 54231.1415, 53067.387, 51903.526, 50774.649, 49657.6415, 48561.05, 47475.7575, 46410.159, 45364.852, 44327.053, 43318.4005, 42325.6165, 41348.4595, 40383.6265, 39436.77, 38509.502, 37594.035, 36695.939, 35818.6895, 34955.691, 34115.8095, 33293.949, 32465.0775, 31657.6715, 30877.2585, 30093.78, 29351.3695, 28594.1365, 27872.115, 27168.7465, 26477.076, 25774.541, 25106.5375, 24452.5135, 23815.5125, 23174.0655, 22555.2685, 21960.2065, 21376.3555, 20785.1925, 20211.517, 19657.0725, 19141.6865, 18579.737, 18081.3955, 17578.995, 17073.44, 16608.335, 16119.911, 15651.266, 15194.583, 14749.0495, 14343.4835, 13925.639, 13504.509, 13099.3885, 12691.2855, 12328.018, 11969.0345, 11596.5145, 11245.6355, 10917.6575, 10580.9785, 10277.8605, 9926.58100000001, 9605.538, 9300.42950000003, 8989.97850000003, 8728.73249999998, 8448.3235, 8175.31050000002, 7898.98700000002, 7629.79100000003, 7413.76199999999, 7149.92300000001, 6921.12650000001, 6677.1545, 6443.28000000003, 6278.23450000002, 6014.20049999998, 5791.20299999998, 5605.78450000001, 5438.48800000001, 5234.2255, 5059.6825, 4887.43349999998, 4682.935, 4496.31099999999, 4322.52250000002, 4191.42499999999, 4021.24200000003, 3900.64799999999, 3762.84250000003, 3609.98050000001, 3502.29599999997, 3363.84250000003, 3206.54849999998, 3079.70000000001, 2971.42300000001, 2867.80349999998, 2727.08100000001, 2630.74900000001, 2496.6165, 2440.902, 2356.19150000002, 2235.58199999999, 2120.54149999999, 2012.25449999998, 1933.35600000003, 1820.93099999998, 1761.54800000001, 1663.09350000002, 1578.84600000002, 1509.48149999999, 1427.3345, 1379.56150000001, 1306.68099999998, 1212.63449999999, 1084.17300000001, 1124.16450000001, 1060.69949999999, 1007.48849999998, 941.194499999983, 879.880500000028, 836.007500000007, 782.802000000025, 748.385499999975, 647.991500000004, 626.730500000005, 570.776000000013, 484.000500000024, 513.98550000001, 418.985499999952, 386.996999999974, 370.026500000036, 355.496999999974, 356.731499999994, 255.92200000002, 259.094000000041, 205.434499999974, 165.374500000034, 197.347500000033, 95.718499999959, 67.6165000000037, 54.6970000000438, 31.7395000000251, -15.8784999999916, 8.42500000004657, -26.3754999999655, -118.425500000012, -66.6629999999423, -42.9745000000112, -107.364999999991, -189.839000000036, -162.611499999999, -164.964999999967, -189.079999999958, -223.931499999948, -235.329999999958, -269.639500000048, -249.087999999989, -206.475499999942, -283.04449999996, -290.667000000016, -304.561499999953, -336.784499999951, -380.386500000022, -283.280499999993, -364.533000000054, -389.059499999974, -364.454000000027, -415.748000000021, -417.155000000028, }, + // precision 18 + (double[]) { 189083, 185696.913, 182348.774, 179035.946, 175762.762, 172526.444, 169329.754, 166166.099, 163043.269, 159958.91, 156907.912, 153906.845, 150924.199, 147996.568, 145093.457, 142239.233, 139421.475, 136632.27, 133889.588, 131174.2, 128511.619, 125868.621, 123265.385, 120721.061, 118181.769, 115709.456, 113252.446, 110840.198, 108465.099, 106126.164, 103823.469, 101556.618, 99308.004, 97124.508, 94937.803, 92833.731, 90745.061, 88677.627, 86617.47, 84650.442, 82697.833, 80769.132, 78879.629, 77014.432, 75215.626, 73384.587, 71652.482, 69895.93, 68209.301, 66553.669, 64921.981, 63310.323, 61742.115, 60205.018, 58698.658, 57190.657, 55760.865, 54331.169, 52908.167, 51550.273, 50225.254, 48922.421, 47614.533, 46362.049, 45098.569, 43926.083, 42736.03, 41593.473, 40425.26, 39316.237, 38243.651, 37170.617, 36114.609, 35084.19, 34117.233, 33206.509, 32231.505, 31318.728, 30403.404, 29540.0550000001, 28679.236, 27825.862, 26965.216, 26179.148, 25462.08, 24645.952, 23922.523, 23198.144, 22529.128, 21762.4179999999, 21134.779, 20459.117, 19840.818, 19187.04, 18636.3689999999, 17982.831, 17439.7389999999, 16874.547, 16358.2169999999, 15835.684, 15352.914, 14823.681, 14329.313, 13816.897, 13342.874, 12880.882, 12491.648, 12021.254, 11625.392, 11293.7610000001, 10813.697, 10456.209, 10099.074, 9755.39000000001, 9393.18500000006, 9047.57900000003, 8657.98499999999, 8395.85900000005, 8033, 7736.95900000003, 7430.59699999995, 7258.47699999996, 6924.58200000005, 6691.29399999999, 6357.92500000005, 6202.05700000003, 5921.19700000004, 5628.28399999999, 5404.96799999999, 5226.71100000001, 4990.75600000005, 4799.77399999998, 4622.93099999998, 4472.478, 4171.78700000001, 3957.46299999999, 3868.95200000005, 3691.14300000004, 3474.63100000005, 3341.67200000002, 3109.14000000001, 3071.97400000005, 2796.40399999998, 2756.17799999996, 2611.46999999997, 2471.93000000005, 2382.26399999997, 2209.22400000005, 2142.28399999999, 2013.96100000001, 1911.18999999994, 1818.27099999995, 1668.47900000005, 1519.65800000005, 1469.67599999998, 1367.13800000004, 1248.52899999998, 1181.23600000003, 1022.71900000004, 1088.20700000005, 959.03600000008, 876.095999999903, 791.183999999892, 703.337000000058, 731.949999999953, 586.86400000006, 526.024999999907, 323.004999999888, 320.448000000091, 340.672999999952, 309.638999999966, 216.601999999955, 102.922999999952, 19.2399999999907, -0.114000000059605, -32.6240000000689, -89.3179999999702, -153.497999999905, -64.2970000000205, -143.695999999996, -259.497999999905, -253.017999999924, -213.948000000091, -397.590000000084, -434.006000000052, -403.475000000093, -297.958000000101, -404.317000000039, -528.898999999976, -506.621000000043, -513.205000000075, -479.351000000024, -596.139999999898, -527.016999999993, -664.681000000099, -680.306000000099, -704.050000000047, -850.486000000034, -757.43200000003, -713.308999999892, } +}; +/* + * Returns the bias correctors from the + * hyperloglog paper + */ +static double alpha(unsigned char precision) { + switch (precision) { + case 4: + return 0.673; + case 5: + return 0.697; + case 6: + return 0.709; + default: + return 0.7213 / (1 + 1.079 / NUM_REG(precision)); + } +} + +// Estimates cardinality using a linear counting. Used when some registers still have a zero value. +static double linear_count(int num_reg, int num_zero) +{ + double est = num_reg * log((double)num_reg / (double)num_zero); + return est; +} +/** + * Binary searches for the nearest matching index + * @return The matching index, or closest match + */ +static int binary_search(double val, int num, const double *array) { + int low=0, mid, high=num-1; + while (low < high) { + mid = (low + high) / 2; + if (val > array[mid]) { + low = mid + 1; + } else if (val == array[mid]) { + return mid; + } else { + high = mid - 1; + } + } + return low; +} +/** + * Interpolates the bias estimate using the + * empircal data collected by Google, from the + * paper mentioned above. + */ +static double bias_estimate(int precision, double raw_est) { + // Determine the samples available + int samples; + switch (precision) { + case 4: + samples = 80; + break; + case 5: + samples = 160; + break; + default: + samples = 200; + break; + } + + // Get the proper arrays based on precision + const double *estimates = *(g_rawEstimateData+(precision-4)); + const double *biases = *(g_biasData+(precision-4)); + + // Get the matching biases + int idx = binary_search(raw_est, samples, estimates); + if (idx == 0) + return biases[0]; + else if (idx == samples) + return biases[samples-1]; + else + return (biases[idx] + biases[idx-1]) / 2; +} + +// Computes the raw cardinality estimate +static double hll_raw_estimate(const uint32_t *registers, unsigned char precision, long long reset_idx, long long time_window_ms, int *num_zero) +{ + int m = NUM_REG(precision); + + double Mi=0, Wi=0;//Wi as the time window span of the i-th register Mi. + double lambda=0; + double harmonic_mean=0; + *num_zero=0; + int effective_reg=0; + for (int i=0; i < m; i++) + { + Wi=(i>=reset_idx)?(m+reset_idx-i):(reset_idx-i)+1; + Mi = get_register(registers, i); + if(!Mi) + *num_zero += 1; + //STHLL++ neglects the 1/8 of the lowest registers to reduce the variance in the final evaluation. + if(Wi < m/8 && time_window_ms) + { + continue; + } + effective_reg++; + lambda=pow(2.0, Mi-1)*m*m/Wi; + harmonic_mean += 1/lambda; + } + harmonic_mean = effective_reg/harmonic_mean; + return harmonic_mean; +} +double hll_count(const uint32_t *registers, unsigned char precision, long long reset_idx, long long time_window_ms) +{ + int num_zero=0; + double raw_est=hll_raw_estimate(registers, precision, reset_idx, time_window_ms, &num_zero); + raw_est*=alpha(precision); + double est=0; + double num_reg=NUM_REG(precision); + if (raw_est <= 5 * num_reg) { + raw_est -= bias_estimate(precision, raw_est); + } + if(raw_est<=5*num_reg/2) + { + if(num_zero) + { + est=linear_count(num_reg, num_zero); + assert(est>=0); + return est; + } + } + if(raw_est>INT32_MAX/30) + { + return INT32_MIN*log(1-raw_est/INT32_MAX); + } + assert(raw_est>=0); + return raw_est; +} +void hll_reset_registers(uint32_t *registers, unsigned char precision, long long offset, long long count) +{ + int num_reg=NUM_REG(precision); + if(count>=num_reg) + { + clear_register(registers, precision); + return; + } + for(int i=0; i<count; i++) + { + reset_register(registers, (offset+i)%num_reg); + } + return; +} +void hll_advance_reset_index(long long *reset_idx, long long reset_reg_count, unsigned char precision) +{ + *reset_idx=(*reset_idx+reset_reg_count)%NUM_REG(precision); + return; +} +long long hll_get_reset_register_count(unsigned char precision, long long time_window_ms, struct timeval now, struct timeval *reset_time) +{ + long long reset_time_slot_us=RESET_TIME_SLOT_US(time_window_ms, precision); + long long delta_us=timeval_delta_us((*reset_time), now); + if(delta_us < reset_time_slot_us) + return 0; + + //We cannot use 'now' as reset_time, but rounded to the nearest time slot. + long long reset_bit_count=0; + reset_bit_count=delta_us/reset_time_slot_us; + struct timeval elapse; + elapse.tv_sec=reset_time_slot_us*reset_bit_count/1000/1000; + elapse.tv_usec=reset_time_slot_us*reset_bit_count%(1000*1000); + timeradd(reset_time, &elapse, reset_time); + return reset_bit_count; +} +void hll_merge(uint32_t *dst_registers, const uint32_t *src_registers, unsigned char precision) +{ + int n_register=NUM_REG(precision); + int s_reg=0, d_reg=0; + for(int i=0; i<n_register; i++) + { + + s_reg=get_register(src_registers, i); + d_reg=get_register(dst_registers, i); + set_register(dst_registers, i, MAX(s_reg, d_reg)); + } +} +double hll_error(unsigned char precision) +{ + /* + * Error of HLL is 1.04 / sqrt(m) + * m is given by 2^p + */ + return 1.04/sqrt(NUM_REG(precision)); +} +size_t hll_size(unsigned char precision) +{ + // Determine how many registers are needed + int num_reg = NUM_REG(precision); + + // Get the full words required + int words = INT_CEIL(num_reg, REG_PER_WORD); + return sizeof(uint32_t)*words; +} +int hll_should_slide(unsigned char precision, long long time_window_ms, struct timeval now, struct timeval reset_time) +{ + assert(time_window_ms>0); + long long reset_time_slot_us=RESET_TIME_SLOT_US(time_window_ms, precision); + long long delta_us=timeval_delta_us(reset_time, now); + if(delta_us >= reset_time_slot_us) + return 1; + return 0; +} + +void hll_encode_into_base64(const uint32_t *registers, unsigned char precision, char **blob, size_t *blob_sz) +{ + size_t sz=0, offset=0; + size_t num_reg = NUM_REG(precision); + size_t words = INT_CEIL(num_reg, REG_PER_WORD); + + sz = hll_size(precision) + 2; // [version][precision][data..., + 2 for version and precision + unsigned char *buffer = ALLOC(unsigned char, sz); + + const unsigned char version = 1; + memcpy(buffer+offset, &version, 1); + offset += 1; + + memcpy(buffer+offset, &precision, 1); + offset += 1; + + for (int i = 0; i < words; i++) { + uint32_t word = registers[i]; + buffer[offset++] = word >> 24; + buffer[offset++] = word >> 16; + buffer[offset++] = word >> 8; + buffer[offset++] = word; + } + + char *enc = b64_encode(buffer, sz); + free(buffer); + *blob_sz = strlen(enc); + *blob = enc; + return; +}
\ No newline at end of file diff --git a/src/cells/hll_common.h b/src/cells/hll_common.h new file mode 100644 index 0000000..b62530a --- /dev/null +++ b/src/cells/hll_common.h @@ -0,0 +1,28 @@ +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <stdint.h> +#include <sys/time.h>//gettimeofday +#include <stddef.h> + +uint32_t *hll_create_register(int precision); +void hll_free_register(uint32_t *registers); +uint32_t *hll_duplicate(const uint32_t *registers, unsigned char precision); +int hll_add_hash(uint32_t *registers, unsigned char precision, uint64_t hash); +double hll_count(const uint32_t *registers, unsigned char precision, long long reset_idx, long long time_window_ms); +size_t hll_size(unsigned char precision); +double hll_error(unsigned char precision); +int hll_should_slide(unsigned char precision, long long time_window_ms, struct timeval now, struct timeval reset_time); +void hll_reset_registers(uint32_t *registers, unsigned char precision, long long offset, long long count); +long long hll_get_reset_register_count(unsigned char precision, long long time_window_ms, struct timeval now, struct timeval *reset_time); +void hll_advance_reset_index(long long *reset_idx, long long reset_reg_count, unsigned char precision); +void hll_merge(uint32_t *dst_registers, const uint32_t *src_registers, unsigned char precision); +void hll_encode_into_base64(const uint32_t *registers, unsigned char precision, char **blob, size_t *blob_sz); + +#ifdef __cplusplus +} +#endif
\ No newline at end of file diff --git a/src/cells/spread_sketch.c b/src/cells/spread_sketch.c new file mode 100644 index 0000000..85f123b --- /dev/null +++ b/src/cells/spread_sketch.c @@ -0,0 +1,719 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <assert.h> + +#include "xxhash/xxhash.h" +#include "uthash.h" + +#include "spread_sketch.h" +#include "hll_common.h" +#include "exdata.h" + +struct entry { + int ref_count; + void *exdata; + bool dying; + char *key; + size_t key_len; + UT_hash_handle hh; +}; + +struct spread_sketch_scheme { + exdata_new_cb new_fn; + exdata_free_cb free_fn; + exdata_merge_cb merge_fn; + exdata_reset_cb reset_fn; + exdata_copy_cb copy_fn; +}; + +struct entry_table { + struct entry *entry; + + struct spread_sketch_scheme scheme; +}; + +struct bucket { + struct entry *content; + uint32_t level; + long long last_update_ms; // linux timestamp since Jan 1st 1970 + uint32_t *sthll_register; +}; + +struct spread_sketch { + int depth; + int width; + long long time_window_ms; + unsigned char precision; + + // shared states of all sthlls + long long reset_idx; + struct timeval reset_time; + + struct spread_sketch_scheme scheme; + + struct bucket *buckets; + struct entry_table *table; + + int level0_cnt; // used to filter out dummy adding +}; + +static void *default_new_fn(void *arg) { + return NULL; +} +static void default_free_fn(void *exdata) { + return; +} +static void default_merge_fn(void *dest, void *src) { + return; +} +static void default_reset_fn(void *exdata) { + return; +} +static void *default_copy_fn(void *exdata) { + return exdata; +} + +struct spread_sketch_scheme DEFAULT_SCHEME = { + .new_fn = default_new_fn, + .free_fn = default_free_fn, + .merge_fn = default_merge_fn, + .reset_fn = default_reset_fn, + .copy_fn = default_copy_fn +}; + +uint32_t cal_true_level(const struct spread_sketch *ss, int bucket_idx, long long t) { + /* + return f(t), the actual level of bucket, which satisfy: + 1. d 2^f(t)/dt is constants + 2. f(t0 + 2T) = 0 + 3. f((t0) = L ) + */ + struct bucket *bucket = &ss->buckets[bucket_idx]; + if (ss->time_window_ms == 0) { + return bucket->level; + } + + unsigned L = bucket->level; + long long T = ss->time_window_ms; + long long t0 = bucket->last_update_ms; + + assert(t >= t0); + if (t - t0 >= 2 * T) { + return 0; + } + if (L <= 1) { + return t - t0 >= T ? 0 : L; + } + + long long tmp_exp = 1 << L; + double a = ((double)(1 - tmp_exp)) / (2.0 * T); + double b = (double)(tmp_exp); + + return (uint32_t)(log2(a * ((double)(t-t0)) + b) + 0.5); +} + +static inline bool key_equal(const char *key1, size_t key1_len, const char *key2, size_t key2_len) { + if (key1_len != key2_len) { + return false; + } + return memcmp(key1, key2, key1_len) == 0; +} +static inline char *key_dup(const char *key, size_t key_len) { + char *ret = malloc(key_len+1); + memcpy(ret, key, key_len); + ret[key_len] = '\0'; + return ret; +} + +struct entry *smart_ptr_table_find(struct entry_table *table, const char *key, size_t key_len) { + struct entry *ret; + HASH_FIND(hh, table->entry, key, key_len, ret); + if (ret == NULL || ret->dying) { + return NULL; + } + return ret; +} + +struct entry *smart_ptr_table_get(struct entry_table *table, const char *key, size_t key_len, void *arg) { + struct entry *ret; + HASH_FIND(hh, table->entry, key, key_len, ret); + + if (ret != NULL) { + ret->dying = false; + ret->ref_count++; + } else { + ret = malloc(sizeof(struct entry)); + ret->dying = false; + ret->ref_count = 1; + ret->key = key_dup(key, key_len); + ret->key_len = key_len; + if (arg == NULL) { + ret->exdata = NULL; + } else { + ret->exdata = table->scheme.new_fn(arg); + } + HASH_ADD_KEYPTR(hh, table->entry, ret->key, ret->key_len, ret); + } + + return ret; +} + +int smart_ptr_table_release(struct entry_table *table, const char *key, size_t key_len) { + struct entry *ret; + HASH_FIND(hh, table->entry, key, key_len, ret); + if (ret == NULL) { + return -1; + } + + ret->ref_count--; + if (ret->ref_count == 0) { + // printf("release %s\n", key); + HASH_DEL(table->entry, ret); + table->scheme.free_fn(ret->exdata); + free(ret->key); + free(ret); + } + + return 0; +} + +void smart_ptr_table_free(struct entry_table *table) { + struct entry *current, *tmp; + HASH_ITER(hh, table->entry, current, tmp) { + HASH_DEL(table->entry, current); + table->scheme.free_fn(current->exdata); + free(current->key); + free(current); + } + free(table); +} + +struct entry_table *smart_ptr_table_new() { + struct entry_table *table = malloc(sizeof(struct entry_table)); + table->entry = NULL; + + table->scheme = DEFAULT_SCHEME; + + return table; +} + +struct spread_sketch *spread_sketch_new(int depth, int width, unsigned char precision, int time_window_ms, struct timeval now) { + struct spread_sketch *pthis = malloc(sizeof(struct spread_sketch)); + + pthis->depth = depth; + pthis->width = width; + pthis->time_window_ms = time_window_ms; + pthis->precision = precision; + + pthis->reset_idx = 0; + pthis->reset_time = now; + + pthis->buckets = calloc(depth * width, sizeof(struct bucket)); + pthis->scheme = DEFAULT_SCHEME; + pthis->table = smart_ptr_table_new(); + pthis->table->scheme = pthis->scheme; + + for (int i = 0; i < depth * width; i++) { + pthis->buckets[i].sthll_register = hll_create_register(precision); + } + + pthis->level0_cnt = pthis->depth * pthis->width; + + return pthis; +} + +void move_registers_forward(struct spread_sketch *ss, const struct timeval *now) { + if (ss->time_window_ms == 0) { + return; + } + + long long reset_reg_count = hll_get_reset_register_count(ss->precision, ss->time_window_ms, *now, &ss->reset_time); + if (reset_reg_count > 0) { + for (int i = 0; i < ss->depth * ss->width; i++) { + hll_reset_registers(ss->buckets[i].sthll_register, ss->precision, ss->reset_idx, reset_reg_count); + } + hll_advance_reset_index(&ss->reset_idx, reset_reg_count, ss->precision); + } +} + +// return 0 if not added, return 1 if added +int spread_sketch_add_hash(struct spread_sketch *ss, const char *key, size_t key_length, uint64_t item_hash, void *arg, struct timeval now) { + uint32_t level = (uint32_t)__builtin_clzll(item_hash) + 1; + long long now_ms = now.tv_sec * 1000 + now.tv_usec / 1000; + + if (item_hash == DUMMY_ITEM_HASH) { + if (ss->level0_cnt == 0) { + return 0; + } + assert(ss->level0_cnt>0); + } + + // https://www.eecs.harvard.edu/~michaelm/postscripts/tr-02-05.pdf + // A technique from the hashing literature is to use two hash functions h1(x) and h2(x) to simulate additional hash functions of the form gi(x) = h1(x) + ih2(x) + // Assuming that the 128-bit xxhash function is perfect, we can view it as a combination of two 64-bit hash functions. + uint64_t hash_x_tmp = XXH3_64bits_withSeed(key, key_length, 171); + uint32_t hash_x1 = (uint32_t) (hash_x_tmp >> 32); + uint32_t hash_x2 = (uint32_t) hash_x_tmp; + + bool in_sketch = false; + move_registers_forward(ss, &now); + for (int i = 0; i < ss->depth; i++) { + uint32_t hash_x = hash_x1 + i * hash_x2; + int bucket_idx = (hash_x % ss->width) + i * ss->width; + struct bucket *bucket = &ss->buckets[bucket_idx]; + + if (bucket->content != NULL && key_equal(bucket->content->key, bucket->content->key_len, key, key_length)) { + bucket->content->dying = false; + bucket->last_update_ms = now_ms; + + if (bucket->level < level) { + if (bucket->level == 0) { + ss->level0_cnt--; + } + bucket->level = level; + } + in_sketch = true; + } else { + uint32_t true_level = bucket->content == NULL ? 0: cal_true_level(ss, bucket_idx, now_ms); + + if (level > true_level) { + if (bucket->level == 0) { + ss->level0_cnt--; + } + + // printf("update key %s to %s, and level %u to %u, in bucket (r,w)=(%d,%u)\n", bucket->content == NULL ? "NULL": bucket->content->key, key, true_level, level, i, hash_x % ss->width); + const struct entry *content_old = bucket->content; + if (content_old != NULL) { + smart_ptr_table_release(ss->table, content_old->key, content_old->key_len); + } + struct entry *content_new = smart_ptr_table_get(ss->table, key, key_length, arg); + bucket->content = content_new; + + bucket->last_update_ms = now_ms; + bucket->level = level; + + in_sketch = true; + } + } + hll_add_hash(bucket->sthll_register, ss->precision, item_hash); + } + + return in_sketch ? 1 : 0; +} + +int spread_sketch_add(struct spread_sketch *ss, const char *key, size_t key_length, const char* item, size_t item_len, void *arg, struct timeval now) { + uint64_t hash = XXH3_64bits(item, item_len); + return spread_sketch_add_hash(ss, key, key_length, hash, arg, now); +} + +double spread_sketch_point_query(const struct spread_sketch *ss, const char *key, size_t key_length) { + uint64_t hash_x_tmp = XXH3_64bits_withSeed(key, key_length, 171); + uint32_t hash_x1 = (uint32_t) (hash_x_tmp >> 32); + uint32_t hash_x2 = (uint32_t) hash_x_tmp; + + double count_min = (double)INT32_MAX; + for (int i = 0; i < ss->depth; i++) { + uint32_t hash_x = hash_x1 + i * hash_x2; + int bucket_idx = (hash_x % ss->width) + i * ss->width; + + double est = hll_count(ss->buckets[bucket_idx].sthll_register, ss->precision, ss->reset_idx, ss->time_window_ms); + if (est < count_min) { + count_min = est; + } + } + return count_min; +} + +struct spread_sketch *duplicate_and_step(const struct spread_sketch *ss, const struct timeval *now) { + struct spread_sketch *duplicate = malloc(sizeof(struct spread_sketch)); + duplicate->depth = ss->depth; + duplicate->width = ss->width; + duplicate->precision = ss->precision; + duplicate->reset_idx = ss->reset_idx; + duplicate->reset_time = ss->reset_time; + duplicate->time_window_ms = ss->time_window_ms; + duplicate->buckets = calloc(ss->depth * ss->width, sizeof(struct bucket)); + for (int i = 0; i < ss->depth * ss->width; i++) { + duplicate->buckets[i].sthll_register = hll_duplicate(ss->buckets[i].sthll_register, ss->precision); + } + + move_registers_forward(duplicate, now); + return duplicate; +} + +double spread_sketch_query(const struct spread_sketch *ss, const char *key, size_t key_length, struct timeval now) { + if (ss->time_window_ms!=0 && hll_should_slide(ss->precision, ss->time_window_ms, now, ss->reset_time)) { + struct spread_sketch *duplicate = duplicate_and_step(ss, &now); + double ret = spread_sketch_point_query(duplicate, key, key_length); + spread_sketch_free(duplicate); + return ret; + } else { + return spread_sketch_point_query(ss, key, key_length); + } +} + +void spread_sketch_free(struct spread_sketch *ss) { + if (ss == NULL) { + return; + } + smart_ptr_table_free(ss->table); + for (int i = 0; i < ss->depth * ss->width; i++) { + hll_free_register(ss->buckets[i].sthll_register); + } + free(ss->buckets); + free(ss); +} + +void spread_sketch_merge(struct spread_sketch *dst, const struct spread_sketch *src) +{ + assert(dst->depth == src->depth && dst->width == src->width); + assert(dst->time_window_ms == src->time_window_ms); + assert(dst->precision == src->precision); + + for (int i = 0; i < dst->depth * dst->width; i++) { + const struct bucket *bucket_src = &src->buckets[i]; + struct bucket *bucket_dst = &dst->buckets[i]; + + if (bucket_src->content == NULL || bucket_src->content->dying) { + continue; + } + + hll_merge(bucket_dst->sthll_register, src->buckets[i].sthll_register, dst->precision); + if (bucket_dst->level == 0 && bucket_src->level > 0) { + dst->level0_cnt--; + } + + if (bucket_dst->content == NULL) { + bucket_dst->content = smart_ptr_table_get(dst->table, bucket_src->content->key, bucket_src->content->key_len, NULL); + bucket_dst->level = bucket_src->level; + bucket_dst->last_update_ms = bucket_src->last_update_ms; + + continue; + } + bucket_dst->content->dying = false; + + if (key_equal(bucket_src->content->key, bucket_src->content->key_len, bucket_dst->content->key, bucket_dst->content->key_len)) { + if (bucket_src->level > bucket_dst->level) { + bucket_dst->level = bucket_src->level; + } + if (bucket_src->last_update_ms > bucket_dst->last_update_ms) { + bucket_dst->last_update_ms = bucket_src->last_update_ms; + } + } else { + uint32_t true_level_src = cal_true_level(src, i, bucket_src->last_update_ms); + uint32_t true_level_dst = cal_true_level(dst, i, bucket_dst->last_update_ms); + + if (true_level_src > true_level_dst) { + smart_ptr_table_release(dst->table, bucket_dst->content->key, bucket_dst->content->key_len); + bucket_dst->content = smart_ptr_table_get(dst->table, bucket_src->content->key, bucket_src->content->key_len, NULL); + bucket_dst->last_update_ms = bucket_src->last_update_ms; + } + } + } + + // for exdata + const struct spread_sketch_scheme *scheme = &dst->table->scheme; + + struct entry *content_dest, *content_src, *tmp; + HASH_ITER(hh, dst->table->entry, content_dest, tmp) { + HASH_FIND(hh, src->table->entry, content_dest->key, content_dest->key_len, content_src); + if (content_src == NULL || content_src->dying) { + continue; + } + + if (content_dest->exdata == NULL) { + content_dest->exdata = scheme->copy_fn(content_src->exdata); + } else { + scheme->merge_fn(content_dest->exdata, content_src->exdata); + } + } +} + +void *spread_sketch_get0_exdata(const struct spread_sketch *ss, const char *key, size_t key_len) { + const struct entry *content = smart_ptr_table_find(ss->table, key, key_len); + if (content == NULL) { + return NULL; + } + return content->exdata; +} + +void spread_sketch_reset(struct spread_sketch *ss) { + for (int i = 0; i < ss->depth * ss->width; i++) { + struct bucket *bucket = &ss->buckets[i]; + bucket->level = 0; + hll_reset_registers(bucket->sthll_register, ss->precision, ss->reset_idx, 100000); // count is big enough + } + + struct entry *content, *tmp; + HASH_ITER(hh, ss->table->entry, content, tmp) { + ss->scheme.reset_fn(content->exdata); + content->dying = true; + } + + ss->level0_cnt = ss->depth * ss->width; +} + +void spread_sketch_set_exdata_schema(struct spread_sketch *ss, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn) { + ss->scheme.new_fn = new_fn; + ss->scheme.free_fn = free_fn; + ss->scheme.merge_fn = merge_fn; + ss->scheme.reset_fn = reset_fn; + ss->scheme.copy_fn = copy_fn; + + ss->table->scheme = ss->scheme; +} + +int spread_sketch_get_count(const struct spread_sketch *ss) { + int cnt = 0; + struct entry *content, *tmp; + HASH_ITER(hh, ss->table->entry, content, tmp) { + if (!content->dying) { + cnt++; + } + } + + return cnt; +} + +size_t spread_sketch_list(const struct spread_sketch *ss, void **exdatas, size_t n_exdatas) { + size_t count = 0; + struct entry *content, *tmp; + HASH_ITER(hh, ss->table->entry, content, tmp) { + if (content->dying) { + continue; + } + if (count >= n_exdatas) { + break; + } + exdatas[count] = content->exdata; + count++; + } + return count; +} + +void spread_sketch_list_keys(const struct spread_sketch *ss, char ***keys, size_t **key_lens, size_t *n_keys) { + size_t count_max = HASH_COUNT(ss->table->entry); + size_t count = 0; + + *keys = malloc(count_max * sizeof(char *)); + *key_lens = malloc(count_max * sizeof(size_t)); + + struct entry *content, *tmp; + HASH_ITER(hh, ss->table->entry, content, tmp) { + if (content->dying) { + continue; + } + + (*keys)[count] = content->key; + (*key_lens)[count] = content->key_len; + count++; + } + + *n_keys = count; +} + +double spread_sketch_get_cardinality(const struct spread_sketch *ss, const char *key, size_t key_len) { + if (smart_ptr_table_find(ss->table, key, key_len) == NULL) { + return -1; + } + + double est = spread_sketch_point_query(ss, key, key_len); + return est; +} + +char *spread_sketch_get_hll_base64_serialization(const struct spread_sketch *ss, const char *key, size_t key_len) { + uint64_t hash_x_tmp = XXH3_64bits_withSeed(key, key_len, 171); + uint32_t hash_x1 = (uint32_t) (hash_x_tmp >> 32); + uint32_t hash_x2 = (uint32_t) hash_x_tmp; + uint32_t *register_ret = NULL; + double min_cardinality = (double)INT32_MAX; + + for (int i = 0; i < ss->depth; i++) { + uint32_t hash_x = hash_x1 + i * hash_x2; + int bucket_idx = (hash_x % ss->width) + i * ss->width; + + double est = hll_count(ss->buckets[bucket_idx].sthll_register, ss->precision, ss->reset_idx, ss->time_window_ms); + if (est < min_cardinality) { + min_cardinality = est; + register_ret = ss->buckets[bucket_idx].sthll_register; + } + } + + char *enc; + size_t enc_len; + hll_encode_into_base64(register_ret, ss->precision, &enc, &enc_len); + return enc; +} + +struct spread_sketch *spread_sketch_copy(const struct spread_sketch *src) { + struct spread_sketch *dst = malloc(sizeof(struct spread_sketch)); + memcpy(dst, src, sizeof(struct spread_sketch)); + + dst->buckets = calloc(dst->depth * dst->width, sizeof(struct bucket)); + dst->table = smart_ptr_table_new(); + spread_sketch_set_exdata_schema(dst, src->scheme.new_fn, src->scheme.free_fn, src->scheme.merge_fn, src->scheme.reset_fn, src->scheme.copy_fn); + for (int i = 0; i < dst->depth * dst->width; i++) { + dst->buckets[i].sthll_register = hll_duplicate(src->buckets[i].sthll_register, src->precision); + } + + for (int i = 0; i < dst->depth * dst->width; i++) { + if (src->buckets[i].content == NULL || src->buckets[i].content->dying) { + continue; + } + dst->buckets[i].content = smart_ptr_table_get(dst->table, src->buckets[i].content->key, src->buckets[i].content->key_len, NULL); + dst->buckets[i].level = src->buckets[i].level; + if (dst->buckets[i].content->exdata == NULL) { + dst->buckets[i].content->exdata = src->scheme.copy_fn(src->buckets[i].content->exdata); + } + } + return dst; +} + +void spread_sketch_get_parameter_recommendation(int expected_super_spreader_number, int *depth_out, int *width_out, unsigned char *precision_out) +{ + int logk = expected_super_spreader_number >= 3200 ? 4 : 3; // lg3200 = 3.51,round up to 4 + *depth_out = logk; + + int w; + if (expected_super_spreader_number <= 100) { + w = expected_super_spreader_number * 3 /2; // * 1.5, when the number is small, we need more width + } else { + w = expected_super_spreader_number + 50; // + 50: 100*1.5-100 = 50, make w=f(k) continuous + } + if (w < 40) { + w = 40; + } + *width_out = w; + + *precision_out = 6; +} + +void spread_sketch_get_parameter(const struct spread_sketch *ss, int *depth_out, int *width_out, unsigned char *precision_out, int *time_window_ms_out) +{ + *depth_out = ss->depth; + *width_out = ss->width; + *precision_out = ss->precision; + *time_window_ms_out = ss->time_window_ms; +} + +void spread_sketch_change_precision(struct spread_sketch *ss, unsigned char precision) { + for (int i = 0; i < ss->depth * ss->width; i++) { + hll_free_register(ss->buckets[i].sthll_register); + ss->buckets[i].sthll_register = hll_create_register(precision); + } + ss->precision = precision; +} + +void spread_sketch_serialize(const struct spread_sketch *ss, char **blob, size_t *blob_sz) +{ + /* + format: + struct spread_sketch(including useless pointers) + struct bucket * depth * width + int64_t * depth * width for keylen + key(close-knit, key_len, key, key_len, key, ..., in order of bucket index) + */ + // get serialize size + + size_t sz = 0; + sz += sizeof(struct spread_sketch); + sz += ss->depth * ss->width * (sizeof(struct bucket) + hll_size(ss->precision) + sizeof(int64_t)); + for (int i = 0; i < ss->depth * ss->width; i++) { + if (ss->buckets[i].content != NULL) { + sz += ss->buckets[i].content->key_len; + } + } + + char *buffer = malloc(sz); + *blob = buffer; + *blob_sz = sz; + + memcpy(buffer, ss, sizeof(struct spread_sketch)); + buffer += sizeof(struct spread_sketch); + for (int i = 0; i < ss->depth * ss->width; i++) { + const struct bucket *bucket = &ss->buckets[i]; + memcpy(buffer, bucket, sizeof(struct bucket)); + buffer += sizeof(struct bucket); + memcpy(buffer, bucket->sthll_register, hll_size(ss->precision)); + buffer += hll_size(ss->precision); + } + for (int i = 0; i < ss->depth * ss->width; i++) { + int64_t key_len; + if (ss->buckets[i].content != NULL) { + key_len = ss->buckets[i].content->key_len; + } else { + key_len = 0; + } + memcpy(buffer, &key_len, sizeof(int64_t)); + buffer += sizeof(int64_t); + + if (key_len > 0) { + memcpy(buffer, ss->buckets[i].content->key, key_len); + buffer += key_len; + } + } +} + +struct spread_sketch *spread_sketch_deserialize(const char *blob, size_t blob_sz) +{ + struct spread_sketch *ss = malloc(sizeof(struct spread_sketch)); + memcpy(ss, blob, sizeof(struct spread_sketch)); + blob += sizeof(struct spread_sketch); + ss->table = smart_ptr_table_new(); + ss->buckets = calloc(ss->depth * ss->width, sizeof(struct bucket)); + ss->scheme = DEFAULT_SCHEME; + + for (int i = 0; i < ss->depth * ss->width; i++) { + struct bucket *bucket = &ss->buckets[i]; + memcpy(bucket, blob, sizeof(struct bucket)); + blob += sizeof(struct bucket); + + bucket->sthll_register = hll_create_register(ss->precision); + memcpy(bucket->sthll_register, blob, hll_size(ss->precision)); + blob += hll_size(ss->precision); + } + + for (int i = 0; i < ss->depth * ss->width; i++) { + int64_t key_len; + memcpy(&key_len, blob, sizeof(int64_t)); + blob += sizeof(int64_t); + if (key_len == 0) { + continue; + } + const char *key = blob; + blob += key_len; + + struct entry *content = smart_ptr_table_get(ss->table, key, key_len, NULL); + ss->buckets[i].content = content; + } + + return ss; +} + +void spread_sketch_merge_blob(struct spread_sketch *dst, const char *blob, size_t blob_sz) +{ + struct spread_sketch *src = spread_sketch_deserialize(blob, blob_sz); + spread_sketch_merge(dst, src); + spread_sketch_free(src); +} + +size_t spread_sketch_calculate_memory_usage(const struct spread_sketch *ss) +{ + size_t ret = 0; + ret += sizeof(struct spread_sketch); + + size_t bucket_size = sizeof(struct bucket) + hll_size(ss->precision); + printf("every bucket size: %zu\n", bucket_size); + ret += ss->depth * ss->width * bucket_size; + + printf("the number of content: %u\n", HASH_COUNT(ss->table->entry)); + struct entry *content, *tmp; + HASH_ITER(hh, ss->table->entry, content, tmp) { + ret += sizeof(struct entry); + ret += content->key_len; + // assume the exdata is NULL + } + return ret; +}
\ No newline at end of file diff --git a/src/cells/spread_sketch.h b/src/cells/spread_sketch.h new file mode 100644 index 0000000..c15ad81 --- /dev/null +++ b/src/cells/spread_sketch.h @@ -0,0 +1,55 @@ +#pragma once + + + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "exdata.h" +#include <stdint.h> //uint64_t +#include <sys/time.h> // struct timeval +#include <stddef.h> + +#define DUMMY_ITEM_HASH (1ULL<<63) // level(left most zeros) = 0 + +struct spread_sketch; + +// set time_window_ms to zero, the spread sketch will not slide and decay, in which case, `now` can be any value +struct spread_sketch *spread_sketch_new(int depth, int width, unsigned char precision, int time_window_ms, struct timeval now); +void spread_sketch_free(struct spread_sketch *ss); +void spread_sketch_set_exdata_schema(struct spread_sketch *ss, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn); + +int spread_sketch_add_hash(struct spread_sketch *ss, const char *key, size_t key_length, uint64_t item_hash, void *arg, struct timeval now); +int spread_sketch_add(struct spread_sketch *ss, const char *key, size_t key_length, const char* item, size_t item_len, void *arg, struct timeval now); + +// get the number of keys stored in spread sketch +int spread_sketch_get_count(const struct spread_sketch *ss); +// list all the keys in spread sketch. User should free the arrays, but do not free the elements of strings in the array(because they are references to the internal data structure) +// Example: char **key; size_t *key_len; size_t n_keys; spread_sketch_list_keys(&key, &key_len, &n_keys); free(key); free(key_len); +void spread_sketch_list_keys(const struct spread_sketch *ss, char ***keys, size_t **key_lens, size_t *n_keys); +// query the cardinality(or fanout) of a key in spread sketch. +// Even thought spread sketch algorithm does not requires keys to exist innately, when querying a key that is not present in the spread sketch, `spread_sketch_get_cardinality` will return -1. +double spread_sketch_get_cardinality(const struct spread_sketch *ss, const char *key, size_t key_len); +// query a hyperloglog 's base64 serialization. The serialization format is [1,precision,register...] and then encoded by base64 +char *spread_sketch_get_hll_base64_serialization(const struct spread_sketch *ss, const char *key, size_t key_len); +void *spread_sketch_get0_exdata(const struct spread_sketch *ss, const char *key, size_t key_len); +// in most cases, it has the same output as `spread_sketch_get_cardinality`, but it will perform more like an ordinary spread sketch query. +// Will always return a value, even if the key is not present in the spread sketch. Must pass a `now` value required by Stagger hll query. +double spread_sketch_query(const struct spread_sketch *ss, const char *key, size_t key_length, struct timeval now); + +void spread_sketch_merge(struct spread_sketch *dest, const struct spread_sketch *src); +struct spread_sketch *spread_sketch_copy(const struct spread_sketch *src); +void spread_sketch_serialize(const struct spread_sketch *ss, char **blob, size_t *blob_sz); +struct spread_sketch *spread_sketch_deserialize(const char *blob, size_t blob_sz); +void spread_sketch_merge_blob(struct spread_sketch *dst, const char *blob, size_t blob_sz); +void spread_sketch_reset(struct spread_sketch *ss); + +void spread_sketch_get_parameter(const struct spread_sketch *ss, int *depth_out, int *width_out, unsigned char *precision_out, int *time_window_ms_out); +// spread sketch alway store values more than expected_query_num,expected_query_num is a hint to set spread sketch parameters properly +void spread_sketch_get_parameter_recommendation(int expected_super_spreader_number, int *depth_out, int *width_out, unsigned char *precision_out); +size_t spread_sketch_calculate_memory_usage(const struct spread_sketch *ss); + +#ifdef __cplusplus +} +#endif
\ No newline at end of file |
