mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-23 05:13:48 +00:00
runtime/*.[ch]:
trace/*.[chyl]:
As above. In some places, improve comments, e.g. by expanding contractions
such as "we've". Add #ifndef guards against double inclusion around
the trace/*.h files that did not already have them.
tools/*:
Make the corresponding changes in shell scripts that generate .[ch] files
in the runtime.
tests/*:
Conform to a slight change in the text of a message.
149 lines
3.9 KiB
C
149 lines
3.9 KiB
C
// vim: ts=4 sw=4 expandtab ft=c
|
|
|
|
// Copyright (C) 1997, 2000, 2002, 2006-2007 The University of Melbourne.
|
|
// This file may only be copied under the terms of the GNU Library General
|
|
// Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
|
|
#include "mercury_imp.h"
|
|
#include <math.h>
|
|
|
|
#if defined(MR_MSVC)
|
|
#include <float.h> // For _FPCLASS_* etc.
|
|
#endif
|
|
|
|
// The function `MR_hash_float()' is used by the library predicate
|
|
// `float__hash' and also for hashing floats for `pragma fact_table' indexing.
|
|
// It computes a non-negative MR_Integer hash value for a MR_Float.
|
|
// The exact hash function used depend on the relative sizes of MR_Float and
|
|
// MR_Integer.
|
|
|
|
union MR_Float_Integer {
|
|
MR_Float f;
|
|
MR_Integer i;
|
|
MR_Integer j[(sizeof(MR_Float)/sizeof(MR_Integer) > 0
|
|
? sizeof(MR_Float)/sizeof(MR_Integer) : 1)];
|
|
char c[sizeof(MR_Float)/sizeof(char)];
|
|
};
|
|
|
|
MR_Integer
|
|
MR_hash_float(MR_Float f)
|
|
{
|
|
union MR_Float_Integer fi;
|
|
size_t i;
|
|
MR_Integer h = 0;
|
|
|
|
fi.i = 0;
|
|
fi.f = f;
|
|
|
|
if (sizeof(MR_Float) <= sizeof(MR_Integer)) {
|
|
h = fi.i;
|
|
} else if (sizeof(MR_Float) % sizeof(MR_Integer) == 0) {
|
|
for (i = 0; i < sizeof(MR_Float)/sizeof(MR_Integer); i++) {
|
|
h ^= fi.j[i];
|
|
}
|
|
} else {
|
|
for (i = 0; i < sizeof(MR_Float)/sizeof(char); i++) {
|
|
h ^= (h << 5);
|
|
h ^= fi.c[i];
|
|
}
|
|
}
|
|
return (h >= 0 ? h : -h);
|
|
}
|
|
|
|
// MR_sprintf_float(buf, f)
|
|
//
|
|
// Fills buf with the string representation of the float, f, such that
|
|
// the string representation has enough precision to represent the
|
|
// float, f.
|
|
//
|
|
// Note that buf must have size at least ML_SPRINTF_FLOAT_BUF_SIZE.
|
|
|
|
void
|
|
MR_sprintf_float(char *buf, MR_Float f)
|
|
{
|
|
MR_Float round_trip = 0.0;
|
|
int i = MR_FLT_MIN_PRECISION;
|
|
|
|
if (MR_is_nan(f)) {
|
|
strcpy(buf, "nan");
|
|
return;
|
|
}
|
|
|
|
if (MR_is_infinite(f)) {
|
|
if (f < 0) {
|
|
strcpy(buf, "-infinity");
|
|
} else {
|
|
strcpy(buf, "infinity");
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Print the float at increasing precisions until the float
|
|
// is round-trippable.
|
|
|
|
do {
|
|
sprintf(buf, "%.*g", i, f);
|
|
if (i >= MR_FLT_MAX_PRECISION) {
|
|
// This should be sufficient precision to round-trip any value.
|
|
// Don't bother checking whether it can actually be round-tripped,
|
|
// since if it can't, this is a bug in the C implementation.
|
|
|
|
break;
|
|
}
|
|
sscanf(buf, MR_FLT_FMT, &round_trip);
|
|
i++;
|
|
} while (round_trip != f);
|
|
|
|
// Append ".0" if there is no "e" or "." in the string.
|
|
|
|
while (1) {
|
|
if (*buf == 'e' || *buf == '.') {
|
|
return;
|
|
}
|
|
if (*buf == '\0') {
|
|
// We only get here if there is no '.' or 'e' in the string.
|
|
strcpy(buf, ".0");
|
|
return;
|
|
}
|
|
buf++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
MR_bool
|
|
MR_is_nan_func(MR_Float Flt)
|
|
{
|
|
#if defined(MR_USE_SINGLE_PREC_FLOAT) && defined(MR_HAVE_ISNANF)
|
|
return isnanf(Flt);
|
|
#elif defined(MR_HAVE_ISNAN)
|
|
return isnan(Flt);
|
|
#elif defined(MR_MSVC)
|
|
return _isnan(Flt);
|
|
#else
|
|
return (Flt != Flt);
|
|
#endif
|
|
}
|
|
|
|
MR_bool
|
|
MR_is_infinite_func(MR_Float Flt)
|
|
{
|
|
// On Solaris, isinf() is detected by configure but we pass -fno-builtin
|
|
// for global registers on x86/x86-64, and that causes an undefined
|
|
// reference to `isinf' when linking. finite() works though.
|
|
|
|
#if defined(MR_USE_SINGLE_PREC_FLOAT) && defined(MR_HAVE_ISINFF) && !defined(MR_SOLARIS)
|
|
return isinff(Flt);
|
|
#elif defined(MR_HAVE_ISINF) && !defined(MR_SOLARIS)
|
|
return isinf(Flt);
|
|
#elif defined(MR_HAVE_FINITE)
|
|
return !finite(Flt) && (Flt == Flt);
|
|
#elif defined(MR_MSVC)
|
|
int sw;
|
|
sw = _fpclass(Flt);
|
|
return (sw == _FPCLASS_NINF) || (sw == _FPCLASS_PINF);
|
|
#else
|
|
return (Flt == Flt / 2.0 && Flt != 0.0);
|
|
#endif
|
|
}
|