1 /*
2 Copyright (c) 1994 - 2010, Lawrence Livermore National Security, LLC.
3 LLNL-CODE-425250.
4 All rights reserved.
5
6 This file is part of Silo. For details, see silo.llnl.gov.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 * Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the disclaimer below.
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the disclaimer (as noted
16 below) in the documentation and/or other materials provided with
17 the distribution.
18 * Neither the name of the LLNS/LLNL nor the names of its
19 contributors may be used to endorse or promote products derived
20 from this software without specific prior written permission.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LAWRENCE
26 LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35 This work was produced at Lawrence Livermore National Laboratory under
36 Contract No. DE-AC52-07NA27344 with the DOE.
37
38 Neither the United States Government nor Lawrence Livermore National
39 Security, LLC nor any of their employees, makes any warranty, express
40 or implied, or assumes any liability or responsibility for the
41 accuracy, completeness, or usefulness of any information, apparatus,
42 product, or process disclosed, or represents that its use would not
43 infringe privately-owned rights.
44
45 Any reference herein to any specific commercial products, process, or
46 services by trade name, trademark, manufacturer or otherwise does not
47 necessarily constitute or imply its endorsement, recommendation, or
48 favoring by the United States Government or Lawrence Livermore
49 National Security, LLC. The views and opinions of authors expressed
50 herein do not necessarily state or reflect those of the United States
51 Government or Lawrence Livermore National Security, LLC, and shall not
52 be used for advertising or product endorsement purposes.
53 */
54 /*-------------------------------------------------------------------------
55 *
56 * Created: num.c
57 * Dec 4 1996
58 * Robb Matzke <matzke@viper.llnl.gov>
59 *
60 * Purpose: Number functions.
61 *
62 * Modifications:
63 *
64 *-------------------------------------------------------------------------
65 */
66 #include <assert.h>
67 #include <browser.h>
68 #include <ctype.h>
69 #include <math.h>
70
71 #define MYCLASS(X) ((obj_num_t*)(X))
72
73 typedef struct obj_num_t {
74 obj_pub_t pub;
75 int fp;
76 union {
77 int i;
78 double d;
79 } u;
80 } obj_num_t;
81
82 class_t C_NUM;
83 static obj_t num_new (va_list);
84 static void num_print (obj_t, out_t*);
85 static int num_diff (obj_t, obj_t);
86
87
88 /*-------------------------------------------------------------------------
89 * Function: num_class
90 *
91 * Purpose: Initializes the number class.
92 *
93 * Return: Success: Ptr to the num class.
94 *
95 * Failure: NULL
96 *
97 * Programmer: Robb Matzke
98 * matzke@viper.llnl.gov
99 * Dec 4 1996
100 *
101 * Modifications:
102 *
103 * Lisa J. Roberts, Mon Nov 22 17:27:53 PST 1999
104 * I changed strdup to safe_strdup.
105 *
106 *-------------------------------------------------------------------------
107 */
108 class_t
num_class(void)109 num_class (void) {
110
111 class_t cls = (class_t)calloc (1, sizeof(*cls));
112
113 cls->name = safe_strdup ("NUM");
114 cls->newobj = num_new;
115 cls->dest = NULL;
116 cls->copy = NULL;
117 cls->print = num_print;
118 cls->diff = num_diff;
119 return cls;
120 }
121
122
123 /*-------------------------------------------------------------------------
124 * Function: num_new
125 *
126 * Purpose: Creates a new number object from a string. The string can
127 * have leading and trailing space. Strings that start with
128 * `0x' are hexadecimal and strings starting with `0' are
129 * octal.
130 *
131 * Return: Success: Ptr to new number object.
132 *
133 * Failure: NIL
134 *
135 * Programmer: Robb Matzke
136 * matzke@viper.llnl.gov
137 * Dec 4 1996
138 *
139 * Modifications:
140 *
141 *-------------------------------------------------------------------------
142 */
143 static obj_t
num_new(va_list ap)144 num_new (va_list ap) {
145
146 obj_num_t *self = (obj_num_t *)calloc (1, sizeof(obj_num_t));
147 char *lexeme;
148
149 lexeme = va_arg (ap, char*);
150 if (strchr(lexeme, '.') ||
151 strchr(lexeme, 'e') ||
152 strchr(lexeme, 'E')) {
153 self->fp = true;
154 self->u.d = strtod (lexeme, NULL);
155 } else {
156 self->fp = false;
157 self->u.i = strtol (lexeme, NULL, 0);
158 }
159 return (obj_t)self;
160 }
161
162
163 /*-------------------------------------------------------------------------
164 * Function: num_print
165 *
166 * Purpose: Prints a number.
167 *
168 * Return: void
169 *
170 * Programmer: Robb Matzke
171 * matzke@viper.llnl.gov
172 * Dec 4 1996
173 *
174 * Modifications:
175 * Robb Matzke, 2000-06-28
176 * Uses the $fmt_int or $fmt_double format.
177 *
178 * Robb Matzke, 2000-10-23
179 * Looks at $obase.
180 *-------------------------------------------------------------------------
181 */
182 static void
num_print(obj_t _self,out_t * f)183 num_print(obj_t _self, out_t *f)
184 {
185 obj_num_t *self=MYCLASS(_self);
186 int obase=sym_bi_true("obase");
187 unsigned char *mem=NULL;
188 int i, j;
189 char buf[512];
190 unsigned u, mask, nbits;
191
192 if (self->fp) {
193 mem = (unsigned char*)&(self->u.d);
194 if (16==obase) {
195 for (i=0; i<sizeof(double); i++) {
196 sprintf(buf+2*i, "%02x", *(mem+i));
197 }
198 out_puts(f, buf);
199 } else if (8==obase) {
200 prim_octal(buf, mem, sizeof(double));
201 out_puts(f, buf);
202 } else if (2==obase) {
203 for (i=0; i<sizeof(double); i++) {
204 u = *((unsigned char*)mem+i);
205 for (j=0, mask=0x80; j<8; j++, mask>>=1) {
206 sprintf(buf+i*8+j, "%c", u&mask?'1':'0');
207 }
208 }
209 out_puts(f, buf);
210 } else {
211 char *fmt = sym_bi_gets("fmt_double");
212 if (!fmt || !*fmt) fmt = "%g";
213 out_printf(f, fmt, self->u.d);
214 }
215 } else {
216
217 mem = (unsigned char*)&(self->u.i);
218 u = *((unsigned*)mem);
219 nbits = 8*sizeof(self->u.i);
220
221 if (16==obase) {
222 out_printf(f, "%0*x", 2*sizeof(int), (unsigned)(self->u.i));
223 } else if (8==obase) {
224 out_printf(f, "%0*o", (nbits+2)/3, (unsigned)(self->u.i));
225 } else if (2==obase) {
226 for (i=0; i<sizeof(self->u.i); i++) {
227 u = *((unsigned char*)mem+i);
228 for (j=0, mask=0x80; j<8; j++, mask>>=1) {
229 sprintf(buf+i*8+j, "%c", u&mask?'1':'0');
230 }
231 }
232 out_puts(f, buf);
233 } else {
234 char *fmt = sym_bi_gets("fmt_int");
235 if (!fmt || !*fmt) fmt = "%d";
236 out_printf (f, fmt, self->u.i);
237 }
238 }
239 }
240
241
242 /*-------------------------------------------------------------------------
243 * Function: num_diff
244 *
245 * Purpose: Determines if two numbers are the same or different.
246 *
247 * Return: Success:
248 * 0: Numbers are the same (or close enough)
249 * 1: Numbers are different and the difference was printed.
250 * 2: Numbers are sufficiently different.
251 *
252 * Failure:
253 * -1: Some type of failure.
254 *
255 * Programmer: Robb Matzke
256 * robb@maya.nuance.mdn.com
257 * Jan 21 1997
258 *
259 * Modifications:
260 * Robb Matzke, 7 Feb 1997
261 * If both numbers are integers then we use the integer differencing
262 * tolerances.
263 *
264 * Robb Matzke, 2000-06-28
265 * Honors the DiffOpt settings. Supports two-column output.
266 *
267 * Mark C. Miller, Wed Nov 11 22:18:17 PST 2009
268 * Added suppot for alternate relative diff option using epsilon param.
269 *-------------------------------------------------------------------------
270 */
271 static int
num_diff(obj_t _a,obj_t _b)272 num_diff (obj_t _a, obj_t _b) {
273
274 obj_num_t *a = MYCLASS(_a);
275 obj_num_t *b = MYCLASS(_b);
276 double ad, bd, abs, rel, eps;
277 int status;
278 out_t *f = OUT_STDOUT;
279
280 if (a->fp || b->fp) {
281 ad = a->fp ? a->u.d : (double)(a->u.i);
282 bd = b->fp ? b->u.d : (double)(b->u.i);
283 abs = DiffOpt.d_abs;
284 rel = DiffOpt.d_rel;
285 eps = DiffOpt.d_eps;
286 } else {
287 ad = a->u.i;
288 bd = b->u.i;
289 abs = DiffOpt.i_abs;
290 rel = DiffOpt.i_rel;
291 eps = DiffOpt.i_eps;
292 }
293
294 status = different (ad, bd, abs, rel, eps) ? 2 : 0;
295 if (status>0 && DIFF_REP_ALL==DiffOpt.report && DiffOpt.two_column) {
296 obj_print(_a, f);
297 out_column(f, OUT_COL2, DIFF_SEPARATOR);
298 obj_print(_b, f);
299 out_nl(f);
300 status = 1;
301 }
302 return status;
303 }
304
305
306 /*-------------------------------------------------------------------------
307 * Function: num_int
308 *
309 * Purpose: Returns the integer value of SELF
310 *
311 * Return: Success: An integer value.
312 *
313 * Failure: Floating point values are truncated.
314 * If SELF is not a number then -1 is returned.
315 *
316 * Programmer: Robb Matzke
317 * matzke@viper.llnl.gov
318 * Dec 4 1996
319 *
320 * Modifications:
321 *
322 * Robb Matzke, 3 Feb 1997
323 * It is safe to call this function for any type of object.
324 *
325 *-------------------------------------------------------------------------
326 */
327 int
num_int(obj_t _self)328 num_int (obj_t _self) {
329
330 int retval;
331 obj_num_t *self = MYCLASS(_self);
332
333 if (!self || C_NUM!=self->pub.cls) return -1;
334 if (self->fp) retval = (int)(self->u.d);
335 else retval = self->u.i;
336 return retval;
337 }
338
339
340 /*-------------------------------------------------------------------------
341 * Function: num_isint
342 *
343 * Purpose: Returns true iff the object is an integer.
344 *
345 * Return: Success: true or false.
346 *
347 * Failure: never fails
348 *
349 * Programmer: Robb Matzke
350 * robb@maya.nuance.mdn.com
351 * Jan 3 1997
352 *
353 * Modifications:
354 *
355 *-------------------------------------------------------------------------
356 */
357 int
num_isint(obj_t _self)358 num_isint (obj_t _self) {
359
360 obj_num_t *self = MYCLASS(_self);
361
362 return (self && C_NUM==self->pub.cls && !self->fp);
363 }
364
365
366 /*-------------------------------------------------------------------------
367 * Function: num_fp
368 *
369 * Purpose: Returns the floating point value of SELF
370 *
371 * Return: Success: A double value.
372 *
373 * Failure: Never fails
374 *
375 * Programmer: Robb Matzke
376 * matzke@viper.llnl.gov
377 * Dec 4 1996
378 *
379 * Modifications:
380 *
381 *-------------------------------------------------------------------------
382 */
383 double
num_fp(obj_t _self)384 num_fp (obj_t _self) {
385
386 obj_num_t *self = MYCLASS(_self);
387
388 return self->fp ? self->u.d : (double)(self->u.i);
389 }
390
391
392 /*-------------------------------------------------------------------------
393 * Function: num_isfp
394 *
395 * Purpose: Returns true iff the object is an integer or floating
396 * point value.
397 *
398 * Return: Success: true or false.
399 *
400 * Failure: never fails
401 *
402 * Programmer: Robb Matzke
403 * robb@maya.nuance.mdn.com
404 * Jan 3 1997
405 *
406 * Modifications:
407 *
408 *-------------------------------------------------------------------------
409 */
410 int
num_isfp(obj_t _self)411 num_isfp (obj_t _self) {
412
413 obj_num_t *self = MYCLASS(_self);
414
415 return (self && C_NUM==self->pub.cls);
416 }
417