Commit 1aea6983 authored by Lev Walkin's avatar Lev Walkin

fight with signalling NANs and floating point exceptions on alpha64

parent 33700165
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* Redistribution and modifications are permitted subject to BSD license. * Redistribution and modifications are permitted subject to BSD license.
*/ */
#if defined(__alpha) #if defined(__alpha)
#define _ISOC99_SOURCE /* For quiet NAN, indirectly through bits/nan.h */ #define _ISOC99_SOURCE /* For quiet NAN, through bits/nan.h */
#define _BSD_SOURCE /* To reintroduce finite(3) */ #define _BSD_SOURCE /* To reintroduce finite(3) */
#include <sys/resource.h> /* For INFINITY */
#endif #endif
#include <asn_internal.h> #include <asn_internal.h>
#include <stdlib.h> /* for strtod(3) */ #include <stdlib.h> /* for strtod(3) */
...@@ -16,10 +17,15 @@ ...@@ -16,10 +17,15 @@
#undef INT_MAX #undef INT_MAX
#define INT_MAX ((int)(((unsigned int)-1) >> 1)) #define INT_MAX ((int)(((unsigned int)-1) >> 1))
static volatile double real_zero = 0.0; #if !(defined(NAN) || defined(INFINITY))
static volatile double real_zero __attribute__ ((unused)) = 0.0;
#endif
#ifndef NAN #ifndef NAN
#define NAN (real_zero/real_zero) #define NAN (real_zero/real_zero)
#endif #endif
#ifndef INFINITY
#define INFINITY (1.0/real_zero)
#endif
/* /*
* REAL basic type description. * REAL basic type description.
...@@ -54,12 +60,12 @@ typedef enum specialRealValue { ...@@ -54,12 +60,12 @@ typedef enum specialRealValue {
static struct specialRealValue_s { static struct specialRealValue_s {
char *string; char *string;
size_t length; size_t length;
double dv; long dv;
} specialRealValue[] = { } specialRealValue[] = {
#define SRV_SET(foo, val) { foo, sizeof(foo) - 1, val } #define SRV_SET(foo, val) { foo, sizeof(foo) - 1, val }
SRV_SET("<NOT-A-NUMBER/>", 0.0), SRV_SET("<NOT-A-NUMBER/>", 0),
SRV_SET("<MINUS-INFINITY/>", -1.0), SRV_SET("<MINUS-INFINITY/>", -1),
SRV_SET("<PLUS-INFINITY/>", 1.0), SRV_SET("<PLUS-INFINITY/>", 1),
#undef SRV_SET #undef SRV_SET
}; };
...@@ -269,12 +275,25 @@ REAL__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) { ...@@ -269,12 +275,25 @@ REAL__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) {
for(i = 0; i < sizeof(specialRealValue) for(i = 0; i < sizeof(specialRealValue)
/ sizeof(specialRealValue[0]); i++) { / sizeof(specialRealValue[0]); i++) {
struct specialRealValue_s *srv = &specialRealValue[i]; struct specialRealValue_s *srv = &specialRealValue[i];
double dv;
if(srv->length != chunk_size if(srv->length != chunk_size
|| memcmp(srv->string, chunk_buf, chunk_size)) || memcmp(srv->string, chunk_buf, chunk_size))
continue; continue;
if(asn_double2REAL(st, srv->dv / real_zero)) /*
return -1; * It could've been done using
* (double)srv->dv / real_zero,
* but it summons fp exception on some platforms.
*/
switch(srv->dv) {
case -1: dv = - INFINITY; break;
case 0: dv = NAN; break;
case 1: dv = INFINITY; break;
default: return -1;
}
if(asn_double2REAL(st, dv)) return -1;
return chunk_size; return chunk_size;
} }
...@@ -337,10 +356,10 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { ...@@ -337,10 +356,10 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) {
switch(st->buf[0]) { switch(st->buf[0]) {
case 0x40: /* 01000000: PLUS-INFINITY */ case 0x40: /* 01000000: PLUS-INFINITY */
*dbl_value = 1.0/real_zero; *dbl_value = INFINITY;
return 0; return 0;
case 0x41: /* 01000001: MINUS-INFINITY */ case 0x41: /* 01000001: MINUS-INFINITY */
*dbl_value = -1.0/real_zero; *dbl_value = - INFINITY;
return 0; return 0;
/* /*
* The following cases are defined by * The following cases are defined by
......
...@@ -88,8 +88,8 @@ check(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sam ...@@ -88,8 +88,8 @@ check(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sam
printf("%02x", *p); printf("%02x", *p);
printf("] (ilogb %d)\n", ilogb(val)); printf("] (ilogb %d)\n", ilogb(val));
printf("%.12f vs %.12f\n", orig_dbl, val); printf("%.12f vs %.12f\n", val, orig_dbl);
assert(orig_dbl == val || (isnan(orig_dbl) && isnan(val))); assert((isnan(orig_dbl) && isnan(val)) || val == orig_dbl);
printf("OK\n"); printf("OK\n");
check_str_repr(val, sample, canonical_sample); check_str_repr(val, sample, canonical_sample);
...@@ -98,7 +98,7 @@ check(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sam ...@@ -98,7 +98,7 @@ check(REAL_t *rn, double orig_dbl, const char *sample, const char *canonical_sam
uint8_t buf_1_0[] = { 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t buf_1_0[] = { 0x80, 0xcc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t buf_1_1[] = { 0x80, 0xcc, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a }; uint8_t buf_1_1[] = { 0x80, 0xcc, 0x11, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a };
uint8_t buf_3_14[] = { 0x80, 0xcd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f }; uint8_t buf_3_14[] = { 0x80, 0xcd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f };
/* These ones are very interesting! It checks mantissa overflow! */ /* These ones are very interesting! They check mantissa overflow! */
uint8_t buf_mo1[] = { 0xC0, 0xc5, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3}; uint8_t buf_mo1[] = { 0xC0, 0xc5, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3};
uint8_t buf_mo2[] = { 0x80, 0xbd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3,2}; uint8_t buf_mo2[] = { 0x80, 0xbd, 0x19, 0x1e, 0xb8, 0x51, 0xeb, 0x85, 0x1f,3,2};
...@@ -189,11 +189,11 @@ check_xer(int fuzzy, double orig_value) { ...@@ -189,11 +189,11 @@ check_xer(int fuzzy, double orig_value) {
ret = asn_REAL2double(newst1, &value1); ret = asn_REAL2double(newst1, &value1);
assert(ret == 0); assert(ret == 0);
assert(value0 == orig_value assert((isnan(value0) && isnan(orig_value))
|| (isnan(value0) && isnan(orig_value)) || value0 == orig_value
|| fuzzy); || fuzzy);
assert(value1 == orig_value assert((isnan(value1) && isnan(orig_value))
|| (isnan(value1) && isnan(orig_value))); || value1 == orig_value);
assert(newst0->size == st.size || fuzzy); assert(newst0->size == st.size || fuzzy);
assert(newst1->size == st.size); assert(newst1->size == st.size);
...@@ -250,9 +250,18 @@ main() { ...@@ -250,9 +250,18 @@ main() {
check_buf(buf_mo2, sizeof(buf_mo2), 3.14, "3.14", "3.14E0"); check_buf(buf_mo2, sizeof(buf_mo2), 3.14, "3.14", "3.14E0");
#ifdef NAN
check_xer(0, NAN); /* "<NOT-A-NUMBER/>" */
#else
check_xer(0, zero/zero); /* "<NOT-A-NUMBER/>" */ check_xer(0, zero/zero); /* "<NOT-A-NUMBER/>" */
#endif
#ifdef INFINITY
check_xer(0, INFINITY); /* "<PLUS-INFINITY/>" */
check_xer(0, -INFINITY); /* "<MINUS-INFINITY/>" */
#else
check_xer(0, 1.0/zero); /* "<PLUS-INFINITY/>" */ check_xer(0, 1.0/zero); /* "<PLUS-INFINITY/>" */
check_xer(0, -1.0/zero); /* "<MINUS-INFINITY/>" */ check_xer(0, -1.0/zero); /* "<MINUS-INFINITY/>" */
#endif
check_xer(0, 1.0); check_xer(0, 1.0);
check_xer(0, -1.0); check_xer(0, -1.0);
check_xer(0, 1.5); check_xer(0, 1.5);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment