00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "logmath.h"
00039 #include "err.h"
00040 #include "ckd_alloc.h"
00041 #include "mmio.h"
00042 #include "bio.h"
00043 #include "strfuncs.h"
00044
00045 #include <math.h>
00046 #include <string.h>
00047 #include <assert.h>
00048
00049 struct logmath_s {
00050 logadd_t t;
00051 int refcount;
00052 mmio_file_t *filemap;
00053 float64 base;
00054 float64 log_of_base;
00055 float64 log10_of_base;
00056 float64 inv_log_of_base;
00057 float64 inv_log10_of_base;
00058 int32 zero;
00059 };
00060
00061 logmath_t *
00062 logmath_init(float64 base, int shift, int use_table)
00063 {
00064 logmath_t *lmath;
00065 uint32 maxyx, i;
00066 float64 byx;
00067 int width;
00068
00069
00070 if (base <= 1.0) {
00071 E_ERROR("Base must be greater than 1.0\n");
00072 return NULL;
00073 }
00074
00075
00076 lmath = ckd_calloc(1, sizeof(*lmath));
00077 lmath->refcount = 1;
00078 lmath->base = base;
00079 lmath->log_of_base = log(base);
00080 lmath->log10_of_base = log10(base);
00081 lmath->inv_log_of_base = 1.0/lmath->log_of_base;
00082 lmath->inv_log10_of_base = 1.0/lmath->log10_of_base;
00083 lmath->t.shift = shift;
00084 lmath->zero = logmath_log(lmath, 1e-300);
00085
00086 if (!use_table)
00087 return lmath;
00088
00089
00090 maxyx = (uint32) (log(2.0) / log(base) + 0.5) >> shift;
00091
00092 if (maxyx < 256) width = 1;
00093 else if (maxyx < 65536) width = 2;
00094 else width = 4;
00095
00096 lmath->t.width = width;
00097
00098 byx = 1.0;
00099 for (i = 0;; ++i) {
00100 float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base;
00101 int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift;
00102
00103
00104 if (k <= 0)
00105 break;
00106
00107
00108
00109
00110 byx /= base;
00111 }
00112 i >>= shift;
00113
00114
00115 if (i < 255) i = 255;
00116
00117 lmath->t.table = ckd_calloc(i+1, width);
00118 lmath->t.table_size = i + 1;
00119
00120 byx = 1.0;
00121 for (i = 0;; ++i) {
00122 float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base;
00123 int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift;
00124 uint32 prev = 0;
00125
00126
00127
00128 switch (width) {
00129 case 1:
00130 prev = ((uint8 *)lmath->t.table)[i >> shift];
00131 break;
00132 case 2:
00133 prev = ((uint16 *)lmath->t.table)[i >> shift];
00134 break;
00135 case 4:
00136 prev = ((uint32 *)lmath->t.table)[i >> shift];
00137 break;
00138 }
00139 if (prev == 0) {
00140 switch (width) {
00141 case 1:
00142 ((uint8 *)lmath->t.table)[i >> shift] = (uint8) k;
00143 break;
00144 case 2:
00145 ((uint16 *)lmath->t.table)[i >> shift] = (uint16) k;
00146 break;
00147 case 4:
00148 ((uint32 *)lmath->t.table)[i >> shift] = (uint32) k;
00149 break;
00150 }
00151 }
00152 if (k <= 0)
00153 break;
00154
00155
00156 byx /= base;
00157 }
00158
00159 return lmath;
00160 }
00161
00162 logmath_t *
00163 logmath_read(const char *file_name)
00164 {
00165 logmath_t *lmath;
00166 char **argname, **argval;
00167 int32 byteswap, i;
00168 int chksum_present, do_mmap;
00169 uint32 chksum;
00170 long pos;
00171 FILE *fp;
00172
00173 E_INFO("Reading log table file '%s'\n", file_name);
00174 if ((fp = fopen(file_name, "rb")) == NULL) {
00175 E_ERROR("fopen(%s,rb) failed\n", file_name);
00176 return NULL;
00177 }
00178
00179
00180 if (bio_readhdr(fp, &argname, &argval, &byteswap) < 0) {
00181 E_ERROR("bio_readhdr(%s) failed\n", file_name);
00182 fclose(fp);
00183 return NULL;
00184 }
00185
00186 lmath = ckd_calloc(1, sizeof(*lmath));
00187
00188 lmath->t.shift = 0;
00189 lmath->t.width = 2;
00190 lmath->base = 1.0001;
00191
00192
00193 chksum_present = 0;
00194 for (i = 0; argname[i]; i++) {
00195 if (strcmp(argname[i], "version") == 0) {
00196 }
00197 else if (strcmp(argname[i], "chksum0") == 0) {
00198 if (strcmp(argval[i], "yes") == 0)
00199 chksum_present = 1;
00200 }
00201 else if (strcmp(argname[i], "width") == 0) {
00202 lmath->t.width = atoi(argval[i]);
00203 }
00204 else if (strcmp(argname[i], "shift") == 0) {
00205 lmath->t.shift = atoi(argval[i]);
00206 }
00207 else if (strcmp(argname[i], "logbase") == 0) {
00208 lmath->base = atof_c(argval[i]);
00209 }
00210 }
00211 bio_hdrarg_free(argname, argval);
00212 chksum = 0;
00213
00214
00215 lmath->log_of_base = log(lmath->base);
00216 lmath->log10_of_base = log10(lmath->base);
00217 lmath->inv_log_of_base = 1.0/lmath->log_of_base;
00218 lmath->inv_log10_of_base = 1.0/lmath->log10_of_base;
00219
00220
00221
00222 if (bio_fread(&lmath->t.table_size, sizeof(int32), 1, fp, byteswap, &chksum) != 1) {
00223 E_ERROR("fread(%s) (total #values) failed\n", file_name);
00224 goto error_out;
00225 }
00226
00227
00228 do_mmap = 1;
00229 pos = ftell(fp);
00230 if (pos & ((long)lmath->t.width - 1)) {
00231 E_WARN("%s: Data start %ld is not aligned on %d-byte boundary, will not memory map\n",
00232 file_name, pos, lmath->t.width);
00233 do_mmap = 0;
00234 }
00235
00236 if (byteswap) {
00237 E_WARN("%s: Data is wrong-endian, will not memory map\n", file_name);
00238 do_mmap = 0;
00239 }
00240
00241 if (do_mmap) {
00242 lmath->filemap = mmio_file_read(file_name);
00243 lmath->t.table = (char *)mmio_file_ptr(lmath->filemap) + pos;
00244 }
00245 else {
00246 lmath->t.table = ckd_calloc(lmath->t.table_size, lmath->t.width);
00247 if (bio_fread(lmath->t.table, lmath->t.width, lmath->t.table_size,
00248 fp, byteswap, &chksum) != lmath->t.table_size) {
00249 E_ERROR("fread(%s) (%d x %d bytes) failed\n",
00250 file_name, lmath->t.table_size, lmath->t.width);
00251 goto error_out;
00252 }
00253 if (chksum_present)
00254 bio_verify_chksum(fp, byteswap, chksum);
00255
00256 if (fread(&i, 1, 1, fp) == 1) {
00257 E_ERROR("%s: More data than expected\n", file_name);
00258 goto error_out;
00259 }
00260 }
00261 fclose(fp);
00262
00263 return lmath;
00264 error_out:
00265 logmath_free(lmath);
00266 return NULL;
00267 }
00268
00269 int32
00270 logmath_write(logmath_t *lmath, const char *file_name)
00271 {
00272 FILE *fp;
00273 long pos;
00274 uint32 chksum;
00275
00276 if (lmath->t.table == NULL) {
00277 E_ERROR("No log table to write!\n");
00278 return -1;
00279 }
00280
00281 E_INFO("Writing log table file '%s'\n", file_name);
00282 if ((fp = fopen(file_name, "wb")) == NULL) {
00283 E_ERROR("fopen(%s,wb) failed\n", file_name);
00284 return -1;
00285 }
00286
00287
00288
00289 fprintf(fp, "s3\nversion 1.0\nchksum0 yes\n");
00290 fprintf(fp, "width %d\n", lmath->t.width);
00291 fprintf(fp, "shift %d\n", lmath->t.shift);
00292 fprintf(fp, "logbase %f\n", lmath->base);
00293
00294 pos = ftell(fp) + strlen("endhdr\n");
00295 if (pos & ((long)lmath->t.width - 1)) {
00296 size_t align = lmath->t.width - (pos & ((long)lmath->t.width - 1));
00297 assert(lmath->t.width <= 8);
00298 fwrite(" " , 1, align, fp);
00299 }
00300 fprintf(fp, "endhdr\n");
00301
00302
00303 chksum = (uint32)BYTE_ORDER_MAGIC;
00304 fwrite(&chksum, sizeof(uint32), 1, fp);
00305 chksum = 0;
00306
00307 if (bio_fwrite(&lmath->t.table_size, sizeof(uint32),
00308 1, fp, 0, &chksum) != 1) {
00309 E_ERROR("fwrite(%s) (total #values) failed\n", file_name);
00310 goto error_out;
00311 }
00312
00313 if (bio_fwrite(lmath->t.table, lmath->t.width, lmath->t.table_size,
00314 fp, 0, &chksum) != lmath->t.table_size) {
00315 E_ERROR("fwrite(%s) (%d x %d bytes) failed\n",
00316 file_name, lmath->t.table_size, lmath->t.width);
00317 goto error_out;
00318 }
00319 if (bio_fwrite(&chksum, sizeof(uint32), 1, fp, 0, NULL) != 1) {
00320 E_ERROR("fwrite(%s) checksum failed\n", file_name);
00321 goto error_out;
00322 }
00323
00324 fclose(fp);
00325 return 0;
00326
00327 error_out:
00328 fclose(fp);
00329 return -1;
00330 }
00331
00332 logmath_t *
00333 logmath_retain(logmath_t *lmath)
00334 {
00335 ++lmath->refcount;
00336 return lmath;
00337 }
00338
00339 int
00340 logmath_free(logmath_t *lmath)
00341 {
00342 if (lmath == NULL)
00343 return 0;
00344 if (--lmath->refcount > 0)
00345 return lmath->refcount;
00346 if (lmath->filemap)
00347 mmio_file_unmap(lmath->filemap);
00348 else
00349 ckd_free(lmath->t.table);
00350 ckd_free(lmath);
00351 return 0;
00352 }
00353
00354 int32
00355 logmath_get_table_shape(logmath_t *lmath, uint32 *out_size,
00356 uint32 *out_width, uint32 *out_shift)
00357 {
00358 if (out_size) *out_size = lmath->t.table_size;
00359 if (out_width) *out_width = lmath->t.width;
00360 if (out_shift) *out_shift = lmath->t.shift;
00361
00362 return lmath->t.table_size * lmath->t.width;
00363 }
00364
00365 float64
00366 logmath_get_base(logmath_t *lmath)
00367 {
00368 return lmath->base;
00369 }
00370
00371 int
00372 logmath_get_zero(logmath_t *lmath)
00373 {
00374 return lmath->zero;
00375 }
00376
00377 int
00378 logmath_get_width(logmath_t *lmath)
00379 {
00380 return lmath->t.width;
00381 }
00382
00383 int
00384 logmath_get_shift(logmath_t *lmath)
00385 {
00386 return lmath->t.shift;
00387 }
00388
00389 int
00390 logmath_add(logmath_t *lmath, int logb_x, int logb_y)
00391 {
00392 logadd_t *t = LOGMATH_TABLE(lmath);
00393 int d, r;
00394
00395 if (t->table == NULL) {
00396 return logmath_add_exact(lmath, logb_x, logb_y);
00397 }
00398
00399
00400 if (logb_x > logb_y) {
00401 d = (logb_x - logb_y);
00402 r = logb_x;
00403 }
00404 else {
00405 d = (logb_y - logb_x);
00406 r = logb_y;
00407 }
00408
00409 if (d < 0) {
00410
00411 return r;
00412 }
00413 if ((size_t)d >= t->table_size) {
00414
00415
00416
00417 return r;
00418 }
00419
00420 switch (t->width) {
00421 case 1:
00422 return r + (((uint8 *)t->table)[d]);
00423 case 2:
00424 return r + (((uint16 *)t->table)[d]);
00425 case 4:
00426 return r + (((uint32 *)t->table)[d]);
00427 }
00428 return r;
00429 }
00430
00431 int
00432 logmath_add_exact(logmath_t *lmath, int logb_p, int logb_q)
00433 {
00434 return logmath_log(lmath,
00435 logmath_exp(lmath, logb_p)
00436 + logmath_exp(lmath, logb_q));
00437 }
00438
00439 int
00440 logmath_log(logmath_t *lmath, float64 p)
00441 {
00442 if (p <= 0) {
00443 return lmath->zero;
00444 }
00445 return (int)(log(p) * lmath->inv_log_of_base) >> lmath->t.shift;
00446 }
00447
00448 float64
00449 logmath_exp(logmath_t *lmath, int logb_p)
00450 {
00451 return pow(lmath->base, (float64)(logb_p << lmath->t.shift));
00452 }
00453
00454 int
00455 logmath_ln_to_log(logmath_t *lmath, float64 log_p)
00456 {
00457 return (int)(log_p * lmath->inv_log_of_base) >> lmath->t.shift;
00458 }
00459
00460 float64
00461 logmath_log_to_ln(logmath_t *lmath, int logb_p)
00462 {
00463 return (float64)(logb_p << lmath->t.shift) * lmath->log_of_base;
00464 }
00465
00466 int
00467 logmath_log10_to_log(logmath_t *lmath, float64 log_p)
00468 {
00469 return (int)(log_p * lmath->inv_log10_of_base) >> lmath->t.shift;
00470 }
00471
00472 float64
00473 logmath_log_to_log10(logmath_t *lmath, int logb_p)
00474 {
00475 return (float64)(logb_p << lmath->t.shift) * lmath->log10_of_base;
00476 }