1/*
2 *
3 *  Copyright (C) 2001-2007  Peter Johnson
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29
30#include "libyasm/floatnum.c"
31
32/* constants describing parameters of internal floating point format.
33 *  (these should match those in src/floatnum.c !)
34 */
35#define MANT_BITS       80
36#define MANT_BYTES      10
37
38typedef struct Init_Entry_s {
39    /* input ASCII value */
40    const char *ascii;
41
42    /* correct output from ASCII conversion */
43    unsigned char mantissa[MANT_BYTES];     /* little endian mantissa - first
44                                               byte is not checked for
45                                               correctness. */
46    unsigned short exponent;        /* bias 32767 exponent */
47    unsigned char sign;
48    unsigned char flags;
49
50    /* correct output conversions - these should be *exact* matches */
51    int ret32;
52    unsigned char result32[4];
53    int ret64;
54    unsigned char result64[8];
55    int ret80;
56    unsigned char result80[10];
57} Init_Entry;
58
59/* Values used for normalized tests */
60static Init_Entry normalized_vals[] = {
61    {   "3.141592653589793",
62        {0xc6,0x0d,0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9},0x8000,0,0,
63         0, {0xdb,0x0f,0x49,0x40},
64         0, {0x18,0x2d,0x44,0x54,0xfb,0x21,0x09,0x40},
65         0, {0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9,0x00,0x40}
66    },
67    {   "-3.141592653589793",
68        {0xc6,0x0d,0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9},0x8000,1,0,
69         0, {0xdb,0x0f,0x49,0xc0},
70         0, {0x18,0x2d,0x44,0x54,0xfb,0x21,0x09,0xc0},
71         0, {0xe9,0xbd,0x68,0x21,0xa2,0xda,0x0f,0xc9,0x00,0xc0}
72    },
73    {   "1.e16",
74        {0x00,0x00,0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e},0x8034,0,0,
75         0, {0xca,0x1b,0x0e,0x5a},
76         0, {0x00,0x80,0xe0,0x37,0x79,0xc3,0x41,0x43},
77         0, {0x00,0x00,0x00,0x04,0xbf,0xc9,0x1b,0x8e,0x34,0x40}
78    },
79    {   "1.6e-20",
80        {0xf6,0xd3,0xee,0x7b,0xda,0x74,0x50,0xa0,0x1d,0x97},0x7fbd,0,0,
81         0, {0xa0,0x1d,0x97,0x1e},
82         0, {0x4f,0x9b,0x0e,0x0a,0xb4,0xe3,0xd2,0x3b},
83         0, {0xef,0x7b,0xda,0x74,0x50,0xa0,0x1d,0x97,0xbd,0x3f}
84    },
85    {   "-5876.",
86        {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xb7},0x800b,1,0,
87         0, {0x00,0xa0,0xb7,0xc5},
88         0, {0x00,0x00,0x00,0x00,0x00,0xf4,0xb6,0xc0},
89         0, {0x00,0x00,0x00,0x00,0x00,0x00,0xa0,0xb7,0x0b,0xc0}
90    },
91    /* Edge cases for rounding wrap. */
92    {   "1.00000",
93        {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7ffe,0,0,
94         0, {0x00,0x00,0x80,0x3f},
95         0, {0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f},
96         0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x3f}
97    },
98    {   "1.000000",
99        {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7ffe,0,0,
100         0, {0x00,0x00,0x80,0x3f},
101         0, {0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f},
102         0, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xff,0x3f}
103    },
104};
105
106/* Still normalized values, but edge cases of various sizes, testing underflow/
107 * overflow checks as well.
108 */
109static Init_Entry normalized_edgecase_vals[] = {
110    /* 32-bit edges */
111    {   "1.1754943508222875e-38",
112        {0xd5,0xf2,0x82,0xff,0xff,0xff,0xff,0xff,0xff,0xff},0x7f80,0,0,
113         0, {0x00,0x00,0x80,0x00},
114         0, {0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x38},
115         0, {0x83,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80,0x3f}
116    },
117    {   "3.4028234663852886e+38",
118        {0x21,0x35,0x0a,0x00,0x00,0x00,0x00,0xff,0xff,0xff},0x807e,0,0,
119         0, {0xff,0xff,0x7f,0x7f},
120         0, {0x00,0x00,0x00,0xe0,0xff,0xff,0xef,0x47},
121         0, {0x0a,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x7e,0x40}
122    },
123    /* 64-bit edges */
124    {   "2.2250738585072014E-308",
125        {0x26,0x18,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x80},0x7c01,0,0,
126        -1, {0x00,0x00,0x00,0x00},
127         0, {0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00},
128         0, {0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x3c}
129    },
130    {   "1.7976931348623157E+308",
131        {0x26,0x6b,0xac,0xf7,0xff,0xff,0xff,0xff,0xff,0xff},0x83fe,0,0,
132         1, {0x00,0x00,0x80,0x7f},
133         0, {0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x7f},
134         0, {0xac,0xf7,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0x43}
135    },
136    /* 80-bit edges */
137/*    { "3.3621E-4932",
138        {},,0,0,
139        -1, {0x00,0x00,0x00,0x00},
140        -1, {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
141         0, {}
142    },
143    {   "1.1897E+4932",
144        {},,0,0,
145         1, {0x00,0x00,0x80,0x7f},
146         1, {},
147         0, {}
148    },*/
149    /* internal format edges */
150/*    {
151    },
152    {
153    },*/
154};
155
156static yasm_floatnum *flt;
157
158/* failure messages */
159static char ret_msg[1024], result_msg[1024];
160
161static void
162new_setup(Init_Entry *vals, int i)
163{
164    flt = yasm_floatnum_create(vals[i].ascii);
165    strcpy(result_msg, vals[i].ascii);
166    strcat(result_msg, ": incorrect ");
167}
168
169static int
170new_check_flt(Init_Entry *val)
171{
172    unsigned char *mantissa;
173    int i, result = 0;
174    unsigned int len;
175
176    mantissa = BitVector_Block_Read(flt->mantissa, &len);
177    for (i=1;i<MANT_BYTES;i++)      /* don't compare first byte */
178        if (mantissa[i] != val->mantissa[i])
179            result = 1;
180    free(mantissa);
181    if (result) {
182        strcat(result_msg, "mantissa");
183        return 1;
184    }
185
186    if (flt->exponent != val->exponent) {
187        strcat(result_msg, "exponent");
188        return 1;
189    }
190    if (flt->sign != val->sign) {
191        strcat(result_msg, "sign");
192        return 1;
193    }
194    if (flt->flags != val->flags) {
195        strcat(result_msg, "flags");
196        return 1;
197    }
198    return 0;
199}
200
201static int
202test_new_normalized(void)
203{
204    Init_Entry *vals = normalized_vals;
205    int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
206
207    for (i=0; i<num; i++) {
208        new_setup(vals, i);
209        if (new_check_flt(&vals[i]) != 0)
210            return 1;
211        yasm_floatnum_destroy(flt);
212    }
213    return 0;
214}
215
216static int
217test_new_normalized_edgecase(void)
218{
219    Init_Entry *vals = normalized_edgecase_vals;
220    int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
221
222    for (i=0; i<num; i++) {
223        new_setup(vals, i);
224        if (new_check_flt(&vals[i]) != 0)
225            return 1;
226        yasm_floatnum_destroy(flt);
227    }
228    return 0;
229}
230
231static void
232get_family_setup(void)
233{
234    flt = malloc(sizeof(yasm_floatnum));
235    flt->mantissa = BitVector_Create(MANT_BITS, TRUE);
236}
237
238static void
239get_family_teardown(void)
240{
241    BitVector_Destroy(flt->mantissa);
242    free(flt);
243}
244
245static void
246get_common_setup(Init_Entry *vals, int i)
247{
248    /* set up flt */
249    BitVector_Block_Store(flt->mantissa, vals[i].mantissa, MANT_BYTES);
250    flt->sign = vals[i].sign;
251    flt->exponent = vals[i].exponent;
252    flt->flags = vals[i].flags;
253
254    /* set failure messages */
255    strcpy(ret_msg, vals[i].ascii);
256    strcat(ret_msg, ": incorrect return value");
257    strcpy(result_msg, vals[i].ascii);
258    strcat(result_msg, ": incorrect result generated");
259}
260#if 0
261static void
262append_get_return_value(int val)
263{
264    char str[64];
265    sprintf(str, ": %d", val);
266    strcat(ret_msg, str);
267}
268#endif
269static int
270get_common_check_result(int len, const unsigned char *val,
271                        const unsigned char *correct)
272{
273    char str[64];
274    int i;
275    int result = 0;
276
277    for (i=0;i<len;i++)
278        if (val[i] != correct[i])
279            result = 1;
280
281    if (result) {
282        for (i=0; i<len; i++)
283            sprintf(str+3*i, "%02x ", val[i]);
284        strcat(result_msg, ": ");
285        strcat(result_msg, str);
286    }
287
288    return result;
289}
290
291/*
292 * get_single tests
293 */
294
295static int
296test_get_single_normalized(void)
297{
298    unsigned char outval[4];
299    Init_Entry *vals = normalized_vals;
300    int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
301
302    for (i=0; i<num; i++) {
303        get_common_setup(vals, i);
304        if (yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0) !=
305            vals[i].ret32)
306            return 1;
307        if (get_common_check_result(4, outval, vals[i].result32) != 0)
308            return 1;
309    }
310    return 0;
311}
312
313static int
314test_get_single_normalized_edgecase(void)
315{
316    unsigned char outval[4];
317    Init_Entry *vals = normalized_edgecase_vals;
318    int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
319
320    for (i=0; i<num; i++) {
321        get_common_setup(vals, i);
322        if (yasm_floatnum_get_sized(flt, outval, 4, 32, 0, 0, 0) !=
323            vals[i].ret32)
324            return 1;
325        if (get_common_check_result(4, outval, vals[i].result32) != 0)
326            return 1;
327    }
328    return 0;
329}
330
331/*
332 * get_double tests
333 */
334
335static int
336test_get_double_normalized(void)
337{
338    unsigned char outval[8];
339    Init_Entry *vals = normalized_vals;
340    int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
341
342    for (i=0; i<num; i++) {
343        get_common_setup(vals, i);
344        if (yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0) !=
345            vals[i].ret64)
346            return 1;
347        if (get_common_check_result(8, outval, vals[i].result64) != 0)
348            return 1;
349    }
350    return 0;
351}
352
353static int
354test_get_double_normalized_edgecase(void)
355{
356    unsigned char outval[8];
357    Init_Entry *vals = normalized_edgecase_vals;
358    int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
359
360    for (i=0; i<num; i++) {
361        get_common_setup(vals, i);
362        if (yasm_floatnum_get_sized(flt, outval, 8, 64, 0, 0, 0) !=
363            vals[i].ret64)
364            return 1;
365        if (get_common_check_result(8, outval, vals[i].result64) != 0)
366            return 1;
367    }
368    return 0;
369}
370
371/*
372 * get_extended tests
373 */
374
375static int
376test_get_extended_normalized(void)
377{
378    unsigned char outval[10];
379    Init_Entry *vals = normalized_vals;
380    int i, num = sizeof(normalized_vals)/sizeof(Init_Entry);
381
382    for (i=0; i<num; i++) {
383        get_common_setup(vals, i);
384        if (yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0) !=
385            vals[i].ret80)
386            return 1;
387        if (get_common_check_result(10, outval, vals[i].result80) != 0)
388            return 1;
389    }
390    return 0;
391}
392
393static int
394test_get_extended_normalized_edgecase(void)
395{
396    unsigned char outval[10];
397    Init_Entry *vals = normalized_edgecase_vals;
398    int i, num = sizeof(normalized_edgecase_vals)/sizeof(Init_Entry);
399
400    for (i=0; i<num; i++) {
401        get_common_setup(vals, i);
402        if (yasm_floatnum_get_sized(flt, outval, 10, 80, 0, 0, 0) !=
403            vals[i].ret80)
404            return 1;
405        if (get_common_check_result(10, outval, vals[i].result80) != 0)
406            return 1;
407    }
408    return 0;
409}
410
411char failed[1000];
412
413static int
414runtest_(const char *testname, int (*testfunc)(void), void (*setup)(void),
415         void (*teardown)(void))
416{
417    int nf;
418    if (setup)
419        setup();
420    nf = testfunc();
421    if (teardown)
422        teardown();
423    printf("%c", nf>0 ? 'F':'.');
424    fflush(stdout);
425    if (nf > 0)
426        sprintf(failed, "%s ** F: %s failed: %s!\n", failed, testname,
427                result_msg);
428    return nf;
429}
430#define runtest(x,y,z)  runtest_(#x,test_##x,y,z)
431
432int
433main(void)
434{
435    int nf = 0;
436    if (BitVector_Boot() != ErrCode_Ok)
437        return EXIT_FAILURE;
438    yasm_floatnum_initialize();
439
440    failed[0] = '\0';
441    printf("Test floatnum_test: ");
442    nf += runtest(new_normalized, NULL, NULL);
443    nf += runtest(new_normalized_edgecase, NULL, NULL);
444    nf += runtest(get_single_normalized, get_family_setup, get_family_teardown);
445    nf += runtest(get_single_normalized_edgecase, get_family_setup, get_family_teardown);
446    nf += runtest(get_double_normalized, get_family_setup, get_family_teardown);
447    nf += runtest(get_double_normalized_edgecase, get_family_setup, get_family_teardown);
448    nf += runtest(get_extended_normalized, get_family_setup, get_family_teardown);
449    nf += runtest(get_extended_normalized_edgecase, get_family_setup, get_family_teardown);
450    printf(" +%d-%d/8 %d%%\n%s",
451           8-nf, nf, 100*(8-nf)/8, failed);
452    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
453}
454