2015-11-13 17:16:49 +11:00
|
|
|
/*
|
2018-08-04 15:14:06 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2015-11-13 17:16:49 +11:00
|
|
|
*
|
|
|
|
* Copyright 2011 Danny Robson <danny@nerdcruft.net>
|
|
|
|
*/
|
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
#include "float.hpp"
|
2019-05-17 12:26:08 +10:00
|
|
|
#include "debug/assert.hpp"
|
2011-05-23 17:18:52 +10:00
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
2018-08-05 14:42:02 +10:00
|
|
|
using cruft::ieee_float;
|
2016-10-11 23:47:57 +11:00
|
|
|
|
2011-05-23 17:18:52 +10:00
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
ieee_float<E, S>::ieee_float (void)
|
|
|
|
{ ; }
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
2020-10-22 12:27:25 +11:00
|
|
|
ieee_float<E, S>::ieee_float (real_t _floating):
|
2011-05-23 17:18:52 +10:00
|
|
|
m_floating (_floating)
|
|
|
|
{ ; }
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
2015-04-13 18:06:08 +10:00
|
|
|
ieee_float<E, S>::ieee_float (const ieee_float &rhs):
|
2011-05-23 17:18:52 +10:00
|
|
|
m_bits (rhs.m_bits)
|
|
|
|
{ ; }
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
2016-03-11 13:28:56 +11:00
|
|
|
ieee_float<E, S>::is_zero (void) const
|
|
|
|
{
|
2011-05-23 17:18:52 +10:00
|
|
|
return m_components.exponent == 0 &&
|
|
|
|
m_components.significand == 0;
|
|
|
|
}
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
2016-03-11 13:28:56 +11:00
|
|
|
ieee_float<E, S>::is_subnormal (void) const
|
|
|
|
{
|
2011-05-23 17:18:52 +10:00
|
|
|
return m_components.exponent == 0 &&
|
|
|
|
m_components.significand != 0;
|
|
|
|
}
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
|
|
|
ieee_float<E, S>::is_inifinity (void) const {
|
|
|
|
return m_components.exponent == (1 << EXPONENT_BITS) - 1 &&
|
|
|
|
m_components.significand == 0;
|
|
|
|
}
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
|
|
|
ieee_float<E, S>::is_nan (void) const {
|
|
|
|
return m_components.exponent == (1 << EXPONENT_BITS) - 1 &&
|
|
|
|
m_components.significand != 0;
|
|
|
|
}
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2020-10-22 12:27:25 +11:00
|
|
|
namespace {
|
|
|
|
template <std::size_t BitsV, typename = void>
|
|
|
|
struct has_float : public std::false_type { };
|
|
|
|
|
|
|
|
template <std::size_t BitsV>
|
|
|
|
struct has_float<
|
|
|
|
BitsV,
|
|
|
|
std::void_t<
|
|
|
|
typename cruft::types::sized::bits<BitsV>::real
|
|
|
|
>
|
|
|
|
> : public std::true_type { };
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
2020-10-22 12:27:25 +11:00
|
|
|
ieee_float<E, S>::operator==(real_t _floating) const {
|
2011-05-23 17:18:52 +10:00
|
|
|
// TODO: This method really shouldn't be generated if there's no
|
|
|
|
// representative native floating point type. But I'm sick of
|
|
|
|
// C++'s template bullshit for tonight.
|
2020-10-22 12:27:25 +11:00
|
|
|
CHECK (has_float<TOTAL_BITS>::value);
|
2011-06-30 21:43:23 +10:00
|
|
|
|
|
|
|
union {
|
2020-10-22 12:27:25 +11:00
|
|
|
real_t _floating;
|
2011-06-30 21:43:23 +10:00
|
|
|
uint_t _uint;
|
|
|
|
} convertor;
|
|
|
|
|
|
|
|
convertor._floating = _floating;
|
|
|
|
|
|
|
|
return m_bits == convertor._uint;
|
2011-05-23 17:18:52 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2011-05-23 17:18:52 +10:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
2020-10-22 12:27:25 +11:00
|
|
|
ieee_float<E, S>::almost_equal (real_t a,
|
|
|
|
real_t b)
|
2015-01-21 23:32:06 +11:00
|
|
|
{
|
2015-08-25 17:18:31 +10:00
|
|
|
return almost_equal (a, b, 128u);
|
2011-05-23 17:18:52 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Based on the Cygnus `AlmostEqual2sComplement` function
|
2015-01-21 23:32:06 +11:00
|
|
|
template <unsigned int E, unsigned int S>
|
|
|
|
bool
|
2020-10-22 12:27:25 +11:00
|
|
|
ieee_float<E, S>::almost_equal (real_t _a,
|
|
|
|
real_t _b,
|
2015-01-29 15:44:30 +11:00
|
|
|
unsigned ulps)
|
2015-01-21 23:32:06 +11:00
|
|
|
{
|
2015-01-22 00:24:34 +11:00
|
|
|
// Ensure ULPs is small enough that the default NaNs won't compare as
|
|
|
|
// equal to anything else.
|
2015-11-13 17:10:10 +11:00
|
|
|
CHECK_LE (ulps, 4 * 1024 * 1024u);
|
2015-01-22 00:24:34 +11:00
|
|
|
|
2015-01-21 23:32:06 +11:00
|
|
|
union {
|
2020-10-22 12:27:25 +11:00
|
|
|
real_t f;
|
2015-01-21 23:32:06 +11:00
|
|
|
sint_t s;
|
2015-02-03 15:54:55 +11:00
|
|
|
uint_t u;
|
2015-01-21 23:32:06 +11:00
|
|
|
} a, b;
|
|
|
|
|
|
|
|
a.f = _a;
|
|
|
|
b.f = _b;
|
|
|
|
|
2015-02-03 15:54:55 +11:00
|
|
|
// Special case the NaNs early so simplify diffs
|
2015-01-21 23:32:06 +11:00
|
|
|
if (std::isnan (a.f) || std::isnan (b.f))
|
|
|
|
return false;
|
|
|
|
|
2015-02-03 15:54:55 +11:00
|
|
|
// Early out, as identity comparisons are reasonably common
|
2015-01-21 23:32:06 +11:00
|
|
|
if (a.s == b.s)
|
|
|
|
return true;
|
|
|
|
|
2015-02-03 15:54:55 +11:00
|
|
|
// Re-base negative floats to be continuous against +ve/-ve 0
|
|
|
|
static const union {
|
2020-10-22 12:27:25 +11:00
|
|
|
real_t f;
|
2015-02-03 15:54:55 +11:00
|
|
|
sint_t s;
|
2020-10-22 12:27:25 +11:00
|
|
|
} NEG_ZERO { -real_t {0} };
|
2015-02-03 15:54:55 +11:00
|
|
|
|
2015-01-29 15:44:57 +11:00
|
|
|
if (a.s < 0)
|
2015-02-03 15:54:55 +11:00
|
|
|
a.s = NEG_ZERO.s - a.s;
|
2015-01-29 15:44:57 +11:00
|
|
|
if (b.s < 0)
|
2015-02-03 15:54:55 +11:00
|
|
|
b.s = NEG_ZERO.s - b.s;
|
2015-01-29 15:44:57 +11:00
|
|
|
|
2015-02-03 15:54:55 +11:00
|
|
|
// Calculate ULP difference, but don't use abs(a.s - b.s) as it may cause
|
|
|
|
// signed overflow
|
|
|
|
uint_t diff = a.u > b.u ? a.u - b.u : b.u - a.u;
|
2015-01-21 23:32:06 +11:00
|
|
|
return diff <= ulps;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-03-11 13:28:56 +11:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2020-10-22 12:27:25 +11:00
|
|
|
//template class cruft::ieee_float< 5, 10>; // ieee_half
|
2019-01-04 17:11:53 +11:00
|
|
|
template class cruft::ieee_float< 8, 23>; // ieee_single;
|
|
|
|
template class cruft::ieee_float<11, 52>; // ieee_double;
|