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