source: branches/alilink/CORE/arb_misc.cxx

Last change on this file was 16768, checked in by westram, 7 years ago
File size: 9.6 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : arb_misc.cxx                                      //
4//   Purpose   : misc that doesnt fit elsewhere                    //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in October 2012   //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include "arb_misc.h"
13#include "arb_msg.h"
14#include "arb_file.h"
15#include "arb_string.h"
16
17#include <cmath>
18
19// AISC_MKPT_PROMOTE:#ifndef _GLIBCXX_CSTDLIB
20// AISC_MKPT_PROMOTE:#include <cstdlib>
21// AISC_MKPT_PROMOTE:#endif
22
23const char *GBS_readable_size(unsigned long long size, const char *unit_suffix) {
24    // return human readable size information
25    // returned string is maximal 6+strlen(unit_suffix) characters long
26    // (using "b" as 'unit_suffix' produces '### b', '### Mb' etc)
27
28    if (size<1000) return GBS_global_string("%llu %s", size, unit_suffix);
29
30    const char *units = "kMGTPEZY"; // kilo, Mega, Giga, Tera, ... should be enough forever
31    int i;
32
33    for (i = 0; units[i]; ++i) {
34        char unit = units[i];
35        if (size<1000*1024) {
36            double amount = size/(double)1024;
37            if (amount<10.0)  return GBS_global_string("%4.2f %c%s", amount+0.005, unit, unit_suffix);
38            if (amount<100.0) return GBS_global_string("%4.1f %c%s", amount+0.05, unit, unit_suffix);
39            return GBS_global_string("%i %c%s", (int)(amount+0.5), unit, unit_suffix);
40        }
41        size /= 1024; // next unit
42    }
43    return GBS_global_string("MUCH %s", unit_suffix);
44}
45
46const char *GBS_readable_timediff(size_t seconds) {
47    size_t mins  = seconds/60; seconds -= mins  * 60;
48    size_t hours = mins/60;    mins    -= hours * 60;
49    size_t days  = hours/24;   hours   -= days  * 24;
50
51    const int   MAXPRINT = 40;
52    int         printed  = 0;
53    static char buffer[MAXPRINT+1];
54
55    if (days>0)               printed += sprintf(buffer+printed, "%zud", days);
56    if (printed || hours>0)   printed += sprintf(buffer+printed, "%zuh", hours);
57    if (printed || mins>0)    printed += sprintf(buffer+printed, "%zum", mins);
58
59    printed += sprintf(buffer+printed, "%zus", seconds);
60
61    arb_assert(printed>0 && printed<MAXPRINT);
62
63    return buffer;
64}
65
66const char *ARB_float_2_ascii(const float f) {
67    /*! calculate the "best" ascii representation for float 'f'
68     *  - smaller conversion error is better
69     *  - shorter representation is better (for equal conversion errors)
70     */
71
72    const int   MAXSIZE = 50;
73    static char result[MAXSIZE];
74    char        buffer[MAXSIZE];
75
76    int   printed_e = snprintf(result, MAXSIZE, "%e", f); arb_assert(printed_e<MAXSIZE);
77    float back_e    = strtof(result, NULp);
78    float diff_e    = fabsf(f-back_e);
79
80    int   printed_g = snprintf(buffer, MAXSIZE, "%g", f); arb_assert(printed_g<MAXSIZE);
81    float back_g    = strtof(buffer, NULp);
82    float diff_g    = fabsf(f-back_g);
83
84    if (diff_g<diff_e || (diff_g == diff_e && printed_g<printed_e)) {
85        printed_e = printed_g;
86        back_e    = back_g;
87        diff_e    = diff_g;
88        memcpy(result, buffer, printed_g+1);
89    }
90
91    int   printed_f = snprintf(buffer, MAXSIZE, "%f", f); arb_assert(printed_f<MAXSIZE);
92    float back_f    = strtof(buffer, NULp);
93    float diff_f    = fabsf(f-back_f);
94
95    if (diff_f<diff_e || (diff_f == diff_e && printed_f<printed_e)) {
96        memcpy(result, buffer, printed_f+1);
97    }
98
99    return result;
100}
101
102const char *ARB_getenv_ignore_empty(const char *envvar) {
103    const char *result = getenv(envvar);
104    return (result && result[0]) ? result : NULp;
105}
106
107char *ARB_executable(const char *exe_name, const char *path) {
108    char       *buffer = ARB_alloc<char>(strlen(path)+1+strlen(exe_name)+1);
109    const char *start  = path;
110    int         found  = 0;
111
112    while (!found && start) {
113        const char *colon = strchr(start, ':');
114        int         len   = colon ? (colon-start) : (int)strlen(start);
115
116        memcpy(buffer, start, len);
117        buffer[len] = '/';
118        strcpy(buffer+len+1, exe_name);
119
120        found = GB_is_executablefile(buffer);
121        start = colon ? colon+1 : NULp;
122    }
123
124    char *executable = found ? ARB_strdup(buffer) : NULp;
125    free(buffer);
126    return executable;
127}
128
129// --------------------------------------------------------------------------------
130
131#ifdef UNIT_TESTS
132#ifndef TEST_UNIT_H
133#include <test_unit.h>
134#endif
135
136#if 0
137// simple test
138#define TEST_EXPECT_FLOAT_2_ASCII(f,a) TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a)
139#else
140// also test back-conversion (ascii->float->ascii) is stable
141#define TEST_EXPECT_FLOAT_2_ASCII(f,a) do{                          \
142        TEST_EXPECT_EQUAL(ARB_float_2_ascii(f), a);                 \
143        TEST_EXPECT_EQUAL(ARB_float_2_ascii(strtof(a, NULp)), a);   \
144    }while(0)
145#endif
146
147__ATTR__REDUCED_OPTIMIZE void TEST_float_2_ascii() {
148    TEST_EXPECT_FLOAT_2_ASCII(3.141592e+00, "3.141592");
149    TEST_EXPECT_FLOAT_2_ASCII(3.141592,     "3.141592");
150    TEST_EXPECT_FLOAT_2_ASCII(3.14159,      "3.14159");
151
152    TEST_EXPECT_FLOAT_2_ASCII(0.1,           "0.1");
153    TEST_EXPECT_FLOAT_2_ASCII(0.01,          "0.01");
154    TEST_EXPECT_FLOAT_2_ASCII(0.001,         "0.001");
155    TEST_EXPECT_FLOAT_2_ASCII(0.0001,        "0.0001");
156    TEST_EXPECT_FLOAT_2_ASCII(0.00001,       "1e-05");
157    TEST_EXPECT_FLOAT_2_ASCII(0.000001,      "1e-06");
158    TEST_EXPECT_FLOAT_2_ASCII(0.0000001,     "1e-07");
159    TEST_EXPECT_FLOAT_2_ASCII(0.00000001,    "1e-08");
160    TEST_EXPECT_FLOAT_2_ASCII(0.000000001,   "1e-09");
161    TEST_EXPECT_FLOAT_2_ASCII(0.0000000001,  "1e-10");
162    TEST_EXPECT_FLOAT_2_ASCII(0.00000000001, "1e-11");
163
164    TEST_EXPECT_FLOAT_2_ASCII(10,         "10");
165    TEST_EXPECT_FLOAT_2_ASCII(100,        "100");
166    TEST_EXPECT_FLOAT_2_ASCII(1000,       "1000");
167    TEST_EXPECT_FLOAT_2_ASCII(10000,      "10000");
168    TEST_EXPECT_FLOAT_2_ASCII(100000,     "100000");
169    TEST_EXPECT_FLOAT_2_ASCII(1000000,    "1e+06");
170    TEST_EXPECT_FLOAT_2_ASCII(10000000,   "1e+07");
171    TEST_EXPECT_FLOAT_2_ASCII(100000000,  "1e+08");
172    TEST_EXPECT_FLOAT_2_ASCII(1000000000, "1e+09");
173
174    TEST_EXPECT_FLOAT_2_ASCII(3141592,      "3.141592e+06");
175    TEST_EXPECT_FLOAT_2_ASCII(314159.2,     "3.141592e+05");
176    TEST_EXPECT_FLOAT_2_ASCII(31415.92,     "3.141592e+04");
177    TEST_EXPECT_FLOAT_2_ASCII(3141.592,     "3141.592041");
178    TEST_EXPECT_FLOAT_2_ASCII(3141.592041,  "3141.592041");
179    TEST_EXPECT_FLOAT_2_ASCII(314.1592,     "314.159210");
180    TEST_EXPECT_FLOAT_2_ASCII(314.159210,   "314.159210");
181    TEST_EXPECT_FLOAT_2_ASCII(31.41592,     "31.415920");
182    TEST_EXPECT_FLOAT_2_ASCII(3.141592,     "3.141592");
183    TEST_EXPECT_FLOAT_2_ASCII(.3141592,     "3.141592e-01");
184    TEST_EXPECT_FLOAT_2_ASCII(.03141592,    "3.141592e-02");
185    TEST_EXPECT_FLOAT_2_ASCII(.003141592,   "3.141592e-03");
186    TEST_EXPECT_FLOAT_2_ASCII(.0003141592,  "3.141592e-04");
187    TEST_EXPECT_FLOAT_2_ASCII(.00003141592, "3.141592e-05");
188    TEST_EXPECT_FLOAT_2_ASCII(M_PI,         "3.141593");
189
190    TEST_EXPECT_FLOAT_2_ASCII(1/2.0, "0.5");
191    TEST_EXPECT_FLOAT_2_ASCII(1/3.0, "3.333333e-01");
192    TEST_EXPECT_FLOAT_2_ASCII(1/4.0, "0.25");
193    TEST_EXPECT_FLOAT_2_ASCII(1/5.0, "0.2");
194    TEST_EXPECT_FLOAT_2_ASCII(1/6.0, "1.666667e-01");
195
196    TEST_EXPECT_FLOAT_2_ASCII(37550000.0,  "3.755e+07");
197    TEST_EXPECT_FLOAT_2_ASCII(3755000.0,   "3.755e+06");
198    TEST_EXPECT_FLOAT_2_ASCII(375500.0,    "375500");
199    TEST_EXPECT_FLOAT_2_ASCII(37550.0,     "37550");
200    TEST_EXPECT_FLOAT_2_ASCII(3755.0,      "3755");
201    TEST_EXPECT_FLOAT_2_ASCII(375.5,       "375.5");
202    TEST_EXPECT_FLOAT_2_ASCII(37.55,       "37.55");
203    TEST_EXPECT_FLOAT_2_ASCII(3.755,       "3.755");
204    TEST_EXPECT_FLOAT_2_ASCII(0.3755,      "0.3755");
205    TEST_EXPECT_FLOAT_2_ASCII(0.03755,     "0.03755");
206    TEST_EXPECT_FLOAT_2_ASCII(0.003755,    "0.003755");
207    TEST_EXPECT_FLOAT_2_ASCII(0.0003755,   "0.0003755");
208    TEST_EXPECT_FLOAT_2_ASCII(0.00003755,  "3.755e-05");
209    TEST_EXPECT_FLOAT_2_ASCII(0.000003755, "3.755e-06");
210
211    TEST_EXPECT_FLOAT_2_ASCII(1000.0*1000.0*1000.0,    "1e+09");
212    TEST_EXPECT_FLOAT_2_ASCII(25000.0*25000.0*25000.0, "1.5625e+13");
213}
214
215// ------------------------------------------------------------
216// test to ensure sanitizers work as expected
217
218#if 0
219void TEST_fail_address_sanitizer() {
220    static int array[5];
221    array[2] = 1;
222    array[5] = 1; // <- fails with AddressSanitizer
223
224    printf("array[5]=%i\n", array[5]);
225}
226#endif
227
228#if 0
229void TEST_fail_undef_sanitizer() {
230    // error below are not reported if AddressSanitizer bails out (TEST_fail_address_sanitizer)
231    int x  = 7;
232    int y1 = -1;
233
234    int s = x<<y1; // runtime error with ubsan: shift exponent -1 is negative (does not terminate)
235    printf("s=%i\n", s);
236
237    int o = INT_MAX;
238    int u = INT_MIN;
239    o++; // runtime error: signed integer overflow
240    u--; // runtime error: signed integer overflow
241    printf("o=%i u=%i\n", o, u);
242
243#if 0
244    int y2 = 0;
245    int z1 = x/y1;
246    int z2 = x/y2; // runtime error with ubsan: division by zero (terminates with SEGV; also w/o sanitizers)
247    printf("z1=%i z2=%i\n", z1, z2);
248#endif
249}
250#endif
251
252#if 0
253void TEST_fail_leak_sanitizer() {
254    int *p = new int[5]; // <- fails with LeakSanitizer (only reported if AddressSanitizer does not bail out (TEST_fail_address_sanitizer))
255    printf("p[3]=%i\n", p[3]);
256}
257#endif
258
259// ------------------------------------------------------------
260
261#endif // UNIT_TESTS
262
263// --------------------------------------------------------------------------------
264
Note: See TracBrowser for help on using the repository browser.