/*
* TODO:
*
- * This code uses the C-type long double to respesent floating
+ * This code uses the C-type LLDBL to respesent floating
* point values. This is bad because:
*
* 1.) It depends on IEEE arithmetic on the compilation engine (hardly a problem)
* Replace this code ASAP.
*/
#include "fltcalc.h"
-#include "ieee754.h"
#include <string.h>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
+#ifdef USE_LONG_DOUBLE
+/* have long double type */
+
+/* only defined in C99 mode */
+extern long double strtold(const char *str, char **end);
+
+#define strtoLLD strtold
+
+#else
+/* don't have long double type */
+
+extern double strtod(const char *str, char **end);
+
+#define strtoLLD strtod
+
+#endif
+
/********
* globals
********/
-static long double value;
+static LLDBL value;
-#define CAST_IN(val) (*((long double *)((val))))
+#define CAST_IN(val) (*((LLDBL *)((val))))
#define CAST_OUT(val) ((void *)&(val))
-#define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(long double))
+#define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(LLDBL))
/********
* private functions
********/
const int fc_get_buffer_length(void)
{
- return sizeof(long double);
+ return sizeof(LLDBL);
}
void fc_val_from_str(const char *str, unsigned int len)
{
CLEAR_BUFFER();
- value = strtold(str, NULL);
+ value = strtoLLD(str, NULL);
}
-void fc_val_from_float(long double l)
+void fc_val_from_float(LLDBL l)
{
CLEAR_BUFFER();
value = l;
}
-long double fc_val_to_float(const void *val)
+LLDBL fc_val_to_float(const void *val)
{
return CAST_IN(val);
}
void fc_get_min(unsigned int num_bits)
{
CLEAR_BUFFER();
- switch (num_bits)
- {
+
+ /*
+ * Beware: FLT_MIN is the "Minimum normalised float",
+ * not the smallest number in arithmetic sense
+ */
+ switch (num_bits) {
case 32:
- value = FLT_MIN;
+ value = -FLT_MAX;
break;
case 64:
- value = DBL_MIN;
+ value = -DBL_MAX;
break;
case 80:
default:
- value = LDBL_MIN;
+ value = -LDBL_MAX;
break;
}
}
void fc_get_nan(void)
{
- /* nan: all exponent bit set, non-zero mantissa. not signalling wheni
- * msb of mantissa is set (easily found using this struct */
- union ieee854_long_double ld;
+ value = strtoLLD("nan", NULL);
- CLEAR_BUFFER();
- ld.ieee_nan.negative = 0;
- ld.ieee_nan.exponent = 0x7FFF;
- ld.ieee_nan.quiet_nan = 1;
- ld.ieee_nan.mantissa0 = 42;
-
- value = ld.d;
}
void fc_get_inf(void)
{
- /* +-inf: all exponent bit set, sign is easy, one is strange XXX */
- union ieee854_long_double ld;
-
- CLEAR_BUFFER();
- ld.ieee_nan.negative = 0;
- ld.ieee_nan.exponent = 0x7FFF;
- ld.ieee_nan.quiet_nan = 0;
- ld.ieee_nan.one = 1;
- ld.ieee_nan.mantissa0 = 0;
- ld.ieee_nan.mantissa1 = 0;
-
- value = ld.d;
+ value = strtoLLD("inf", NULL);
}
void fc_calc(const void *a, const void *b, int opcode)
break;
case FC_NEG:
value = -CAST_IN(a);
+ break;
}
}
int fc_comp(const void *a, const void *b)
{
- if (CAST_IN(a) == CAST_IN(b)) return 0;
- else return (CAST_IN(a) > CAST_IN(b))?(1):(-1);
+
+ if (CAST_IN(a) == CAST_IN(b)) {
+ return 0;
+ }
+ else if (CAST_IN(a) > CAST_IN(b)) {
+ return 1;
+ }
+ else {
+ return -1;
+ }
}
char *fc_print_dec(const void *a, char *buf, int buflen)
{
- snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
+ int n;
+
+#ifdef USE_LONG_DOUBLE
+ n = snprintf(buf, buflen, "%1.30Lg", CAST_IN(a));
+#else
+ n = snprintf(buf, buflen, "%1.30g", CAST_IN(a));
+#endif
+
+ if (n > -1 && n < buflen) {
+ /*
+ * for some backends we always want to present 0 as 0.0
+ * as I could not find the best format to express this, add
+ * a .0 explicitely if not found
+ */
+ if (NULL == strrchr(buf, '.'))
+ strncat(buf, ".0", buflen);
+ }
+
return buf;
}
unsigned char fc_sub_bits(const void *value, unsigned num_bits, unsigned byte_ofs)
{
- long double val = CAST_IN(value);
+ LLDBL val = CAST_IN(value);
float f;
double d;