/*
* 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)
#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;
-
-//#define CAST_IN(val) ({ long double xxx = *(long double *)(val); printf("CAST to %Lg\n", xxx); xxx; })
+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)
{
- value = strtold("nan", NULL);
+ value = strtoLLD("nan", NULL);
}
void fc_get_inf(void)
{
- value = strtold("inf", NULL);
+ value = strtoLLD("inf", NULL);
}
void fc_calc(const void *a, const void *b, int opcode)
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;