mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 21:35:49 +00:00
Discussion of these changes can be found on the Mercury developers
mailing list archives from June 2018.
COPYING.LIB:
Add a special linking exception to the LGPL.
*:
Update references to COPYING.LIB.
Clean up some minor errors that have accumulated in copyright
messages.
247 lines
9.4 KiB
C
247 lines
9.4 KiB
C
// vim: ts=4 sw=4 expandtab ft=c
|
|
|
|
// Copyright (C) 1995-1997, 1999-2002, 2007, 2011 The University of Melbourne.
|
|
// Copyright (C) 2013-2014, 2016, 2018 The Mercury team.
|
|
// This file is distributed under the terms specified in COPYING.LIB.
|
|
|
|
// mercury_float.h - floating point handling
|
|
|
|
#ifndef MERCURY_FLOAT_H
|
|
#define MERCURY_FLOAT_H
|
|
|
|
#include "mercury_conf.h" // for MR_BOXED_FLOAT, MR_CONSERVATIVE_GC
|
|
#include "mercury_types.h" // for `MR_Word'
|
|
#include "mercury_std.h" // for `MR_bool'
|
|
|
|
#ifdef MR_USE_SINGLE_PREC_FLOAT
|
|
typedef float MR_Float;
|
|
#define MR_FLT_MIN_PRECISION 7
|
|
#define MR_FLT_FMT "%f"
|
|
// We assume that sizeof(float) <= sizeof(MR_Word).
|
|
#undef MR_BOXED_FLOAT
|
|
#else
|
|
typedef double MR_Float;
|
|
#define MR_FLT_MIN_PRECISION 15
|
|
#define MR_FLT_FMT "%lf"
|
|
#endif
|
|
#define MR_FLT_MAX_PRECISION (MR_FLT_MIN_PRECISION + 2)
|
|
|
|
#define MR_FLOAT_WORDS ((sizeof(MR_Float) + sizeof(MR_Word) - 1) \
|
|
/ sizeof(MR_Word))
|
|
|
|
// MR_Float_Aligned and #pragma pack are used convince the C compiler to lay
|
|
// out structures containing MR_Float members as expected by the Mercury
|
|
// compiler, without additional padding or packing.
|
|
//
|
|
// For MSVC, __declspec(align) only increases alignment, e.g. for single
|
|
// precision floats on 64-bit platforms. #pragma pack is required to
|
|
// reduce packing size, e.g. double precision floats on 32-bit platform.
|
|
//
|
|
// Any changes here will probably also need to be made for int64s/uint64s
|
|
// in mercury_int.h.
|
|
|
|
#if defined(MR_GNUC) || defined(MR_CLANG)
|
|
typedef MR_Float MR_Float_Aligned __attribute__((aligned(sizeof(MR_Word))));
|
|
#elif defined(MR_MSVC)
|
|
typedef __declspec(align(MR_BYTES_PER_WORD)) MR_Float MR_Float_Aligned;
|
|
#else
|
|
typedef MR_Float MR_Float_Aligned;
|
|
#endif
|
|
|
|
#ifdef MR_BOXED_FLOAT
|
|
|
|
#define MR_word_to_float(w) (* (MR_Float *) (w))
|
|
|
|
#ifdef MR_CONSERVATIVE_GC
|
|
#define MR_make_hp_float_aligned() ((void) 0)
|
|
|
|
#define MR_float_to_word(f) \
|
|
( \
|
|
MR_hp_alloc_atomic_msg(MR_FLOAT_WORDS, \
|
|
(MR_AllocSiteInfoPtr) MR_ALLOC_SITE_FLOAT, NULL), \
|
|
* (MR_Float *) (void *) (MR_hp - MR_FLOAT_WORDS) = (f), \
|
|
/* return */ (MR_Word) (MR_hp - MR_FLOAT_WORDS) \
|
|
)
|
|
#else // ! defined(MR_CONSERVATIVE_GC)
|
|
// We need to ensure that what we allocated on the heap is properly
|
|
// aligned for a floating-point value, by rounding MR_hp up to the
|
|
// nearest float-aligned boundary.
|
|
// XXX This code assumes that sizeof(MR_Float) is a power of two,
|
|
// and not greater than 2 * sizeof(MR_Word).
|
|
#define MR_make_hp_float_aligned() \
|
|
( ((MR_Word) MR_hp & (sizeof(MR_Float) - 1)) ? \
|
|
MR_hp_alloc_atomic_msg(1, MR_ALLOC_SITE_FLOAT, NULL) \
|
|
: \
|
|
(void) 0 \
|
|
)
|
|
|
|
#define MR_float_to_word(f) \
|
|
( \
|
|
MR_make_hp_float_aligned(), \
|
|
MR_hp_alloc_atomic_msg(MR_FLOAT_WORDS, MR_ALLOC_SITE_FLOAT, NULL), \
|
|
* (MR_Float *) (void *) (MR_hp - MR_FLOAT_WORDS) = (f), \
|
|
/* return */ (MR_Word) (MR_hp - MR_FLOAT_WORDS) \
|
|
)
|
|
#endif // MR_CONSERVATIVE_GC
|
|
|
|
#ifdef MR_GNUC
|
|
#define MR_float_const(f) ({ static const MR_Float d = f; (MR_Word) &d; })
|
|
#else
|
|
#define MR_float_const(f) MR_float_to_word(f) // inefficient
|
|
#endif
|
|
|
|
// MR_BOXED_FLOAT is never defined if using single-precision floats,
|
|
// so MR_Float must be the C type "double".
|
|
|
|
union MR_Float_Dword {
|
|
MR_Float f;
|
|
MR_Word w[2];
|
|
};
|
|
|
|
#if defined(MR_GNUC) || defined(MR_CLANG)
|
|
#define MR_float_word_bits(f, n) \
|
|
(((union MR_Float_Dword) (MR_Float) (f)).w[(n)])
|
|
#define MR_dword_float_get_word0(f) \
|
|
(((union MR_Float_Dword) (MR_Float) (f)).w[0])
|
|
#define MR_dword_float_get_word1(f) \
|
|
(((union MR_Float_Dword) (MR_Float) (f)).w[1])
|
|
#else // ! (defined(MR_GNUC) || defined(MR_CLANG))
|
|
MR_EXTERN_INLINE MR_Word MR_float_word_bits(MR_Float f, MR_Integer n);
|
|
MR_EXTERN_INLINE MR_Word MR_dword_float_get_word0(MR_Float f);
|
|
MR_EXTERN_INLINE MR_Word MR_dword_float_get_word1(MR_Float f);
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_float_word_bits(MR_Float f, MR_Integer n)
|
|
{
|
|
union MR_Float_Dword __ffdw;
|
|
__ffdw.f = f;
|
|
return __ffdw.w[n];
|
|
}
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_dword_float_get_word0(MR_Float f)
|
|
{
|
|
union MR_Float_Dword __ffdw;
|
|
__ffdw.f = f;
|
|
return __ffdw.w[0];
|
|
}
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_dword_float_get_word1(MR_Float f)
|
|
{
|
|
union MR_Float_Dword __ffdw;
|
|
__ffdw.f = f;
|
|
return __ffdw.w[1];
|
|
}
|
|
#endif // defined(MR_GNUC) || defined(MR_CLANG)
|
|
|
|
#define MR_float_from_dword_ptr(ptr) \
|
|
(((union MR_Float_Dword *) (ptr))->f)
|
|
|
|
#if defined(MR_GNUC) || defined(MR_CLANG)
|
|
#define MR_float_from_dword(w0, w1) \
|
|
({ \
|
|
union MR_Float_Dword __ffdw; \
|
|
__ffdw.w[0] = (MR_Word) (w0); \
|
|
__ffdw.w[1] = (MR_Word) (w1); \
|
|
__ffdw.f; \
|
|
})
|
|
#else // ! (defined(MR_GNUC) || defined(MR_CLANG))
|
|
#define MR_float_from_dword(w0, w1) \
|
|
MR_float_from_dword_func((MR_Word) (w0), (MR_Word) (w1))
|
|
|
|
MR_EXTERN_INLINE MR_Float
|
|
MR_float_from_dword_func(MR_Word w0, MR_Word w1);
|
|
|
|
MR_EXTERN_INLINE MR_Float
|
|
MR_float_from_dword_func(MR_Word w0, MR_Word w1)
|
|
{
|
|
union MR_Float_Dword __ffdw;
|
|
__ffdw.w[0] = (MR_Word) (w0);
|
|
__ffdw.w[1] = (MR_Word) (w1);
|
|
return __ffdw.f;
|
|
}
|
|
#endif // defined(MR_GNUC) || defined(MR_CLANG)
|
|
|
|
#else // ! MR_BOXED_FLOAT
|
|
|
|
// Unboxed float means we can assume sizeof(MR_Float) <= sizeof(MR_Word).
|
|
|
|
#define MR_make_hp_float_aligned() ((void) 0)
|
|
|
|
union MR_Float_Word {
|
|
MR_Float f;
|
|
MR_Word w;
|
|
};
|
|
|
|
#define MR_float_const(f) MR_float_to_word(f)
|
|
|
|
#if defined(MR_GNUC) || defined(MR_CLANG)
|
|
// GNU C and clang both allow you to cast to a union type.
|
|
#define MR_float_to_word(f) \
|
|
(__extension__ ((union MR_Float_Word) (MR_Float) (f)).w)
|
|
#define MR_word_to_float(w) \
|
|
(__extension__ ((union MR_Float_Word) (MR_Word) (w)).f)
|
|
#else // ! (defined(MR_GNUC) || defined(MR_CLANG))
|
|
static MR_Word MR_float_to_word(MR_Float f)
|
|
{ union MR_Float_Word tmp; tmp.f = f; return tmp.w; }
|
|
static MR_Float MR_word_to_float(MR_Word w)
|
|
{ union MR_Float_Word tmp; tmp.w = w; return tmp.f; }
|
|
#endif // defined(MR_GNUC) || defined(MR_CLANG)
|
|
|
|
#endif // not MR_BOXED_FLOAT
|
|
|
|
// The size of the buffer to pass to MR_sprintf_float.
|
|
//
|
|
// Longest possible string for %#.*g format is `-n.nnnnnnE-mmmm', which
|
|
// has size PRECISION + MAX_EXPONENT_DIGITS + 5 (for the `-', `.', `E',
|
|
// '-', and '\\0'). PRECISION is at most 20, and MAX_EXPONENT_DIGITS is
|
|
// at most 5, so we need at most 30 chars. 80 is way more than enough.
|
|
|
|
#define MR_SPRINTF_FLOAT_BUF_SIZE 80
|
|
|
|
#define MR_float_to_string(Float, String, alloc_id) \
|
|
do { \
|
|
char buf[MR_SPRINTF_FLOAT_BUF_SIZE]; \
|
|
MR_sprintf_float(buf, Float); \
|
|
MR_make_aligned_string_copy_msg(String, buf, (alloc_id)); \
|
|
} while (0)
|
|
|
|
extern void MR_sprintf_float(char *buf, MR_Float f);
|
|
|
|
extern MR_Integer MR_hash_float(MR_Float);
|
|
|
|
// We define MR_is_{nan,infinite,finite} as macros if we support C99
|
|
// since the resulting code is faster.
|
|
// MSVC also supports these macros (from VS2013 onwards) but it does not
|
|
// set __STDC_VERSION__ appropriately.
|
|
// (1800 is the internal MSVC version number for VS2013.)
|
|
|
|
#if __STDC_VERSION__ >= 199901 || MR_MSVC >= 1800
|
|
#define MR_is_nan(f) isnan((f))
|
|
#else
|
|
#define MR_is_nan(f) MR_is_nan_func((f))
|
|
#endif
|
|
|
|
// See comments for function MR_is_infinite_func in mercury_float.c for the
|
|
// handling of Solaris here.
|
|
|
|
#if (__STDC_VERSION__ >= 199901 && !defined(MR_SOLARIS)) || MR_MSVC >= 1800
|
|
#define MR_is_infinite(f) isinf((f))
|
|
#else
|
|
#define MR_is_infinite(f) MR_is_infinite_func((f))
|
|
#endif
|
|
|
|
// XXX I don't know whether isfinite works on Solaris or not.
|
|
|
|
#if (__STDC_VERSION__ >= 199901 && !defined(MR_SOLARIS)) || MR_MSVC >= 1800
|
|
#define MR_is_finite(f) isfinite((f))
|
|
#else
|
|
#define MR_is_finite(f) (!MR_is_infinite((f)) && !MR_is_nan((f)))
|
|
#endif
|
|
|
|
extern MR_bool MR_is_nan_func(MR_Float);
|
|
extern MR_bool MR_is_infinite_func(MR_Float);
|
|
|
|
#endif // not MERCURY_FLOAT_H
|