Merge branch 'master' of gitlab.2:f1x1t/myxlib

This commit is contained in:
Andrei Astafev 2019-11-27 21:22:29 +03:00
commit a6d359d18c
10 changed files with 427 additions and 1 deletions

@ -1 +1 @@
Subproject commit 45284f97623b7ae952020771846ccfe2e0a3cf58 Subproject commit 2c51ecc3dc681b11a6283d8ab64e6410f8b11678

View File

@ -0,0 +1,42 @@
#include <myx/math/almost_equal_relative.hpp>
#include <cmath>
namespace myx {
namespace math {
bool almost_equal_relative( const float a, const float b,
const float maxRelDiff )
{
float diff = fabsf( a - b );
float aN = fabsf( a );
float bN = fabsf( b );
float largest = ( bN > aN ) ? bN : aN;
if ( diff <= largest * maxRelDiff )
{
return( true );
}
return( false );
}
bool almost_equal_relative( const double a, const double b,
const double maxRelDiff )
{
double diff = fabs( a - b );
double aN = fabs( a );
double bN = fabs( b );
double largest = ( bN > aN ) ? bN : aN;
if ( diff <= largest * maxRelDiff )
{
return( true );
}
return( false );
}
} // namespace math
} // namespace myx

View File

@ -0,0 +1,31 @@
#ifndef MYX_MATH_ALMOST_EQUAL_RELATIVE_HPP_
#define MYX_MATH_ALMOST_EQUAL_RELATIVE_HPP_
#include <cfloat>
// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
namespace myx {
namespace math {
/**
* @brief Проверка на равенство двух аргументов типа float.
* Параметр maxRelDiff определяет максимальную относительную допустимую разницу,
* при которой аргументы считаются равными.
*/
bool almost_equal_relative( const float a, const float b,
const float maxRelDiff = FLT_EPSILON );
/**
* @brief Проверка на равенство двух аргументов типа double.
* Параметр maxRelDiff определяет максимальную относительную допустимую разницу,
* при которой аргументы считаются равными.
*/
bool almost_equal_relative( const double a, const double b,
const double maxRelDiff = DBL_EPSILON );
} // namespace math
} // namespace myx
#endif // MYX_MATH_ALMOST_EQUAL_RELATIVE_HPP_

View File

@ -0,0 +1,56 @@
#include <myx/math/almost_equal_relative_and_abs.hpp>
#include <cmath>
namespace myx {
namespace math {
bool almost_equal_relative_and_abs( const float a, const float b,
const float maxAbsDiff, const float maxRelDiff )
{
// Check if the numbers are really close -- needed
// when comparing numbers near zero.
float diff = fabsf( a - b );
if ( diff <= maxAbsDiff )
{
return( true );
}
float aN = fabsf( a );
float bN = fabsf( b );
float largest = ( bN > aN ) ? bN : aN;
if ( diff <= largest * maxRelDiff )
{
return( true );
}
return( false );
}
bool almost_equal_relative_and_abs( const double a, const double b,
const double maxAbsDiff, const double maxRelDiff )
{
// Check if the numbers are really close -- needed
// when comparing numbers near zero.
double diff = fabs( a - b );
if ( diff <= maxAbsDiff )
{
return( true );
}
double aN = fabs( a );
double bN = fabs( b );
double largest = ( bN > aN ) ? bN : aN;
if ( diff <= largest * maxRelDiff )
{
return( true );
}
return( false );
}
} // namespace math
} // namespace myx

View File

@ -0,0 +1,31 @@
#ifndef MYX_MATH_ALMOST_EQUAL_RELATIVE_AND_ABS_HPP_
#define MYX_MATH_ALMOST_EQUAL_RELATIVE_AND_ABS_HPP_
#include <cfloat>
namespace myx {
namespace math {
/**
* @brief Проверка на равенство двух аргументов типа float.
* Параметр maxAbsDiff определяет максимальную абсолютную допустимую разницу.
* Параметр maxRelDiff определяет максимальную относительную допустимую разницу,
* при которой аргументы считаются равными.
*/
bool almost_equal_relative_and_abs( const float a, const float b,
const float maxAbsDiff, const float maxRelDiff = FLT_EPSILON );
/**
* @brief Проверка на равенство двух аргументов типа double.
* Параметр maxAbsDiff определяет максимальную абсолютную допустимую разницу.
* Параметр maxRelDiff определяет максимальную относительную допустимую разницу,
* при которой аргументы считаются равными.
*/
bool almost_equal_relative_and_abs( const double a, const double b,
const double maxAbsDiff, const double maxRelDiff = DBL_EPSILON );
} // namespace math
} // namespace myx
#endif // MYX_MATH_ALMOST_EQUAL_RELATIVE_AND_ABS_HPP_

View File

@ -0,0 +1,79 @@
#include <myx/math/float_cmp_types.hpp>
#include <myx/math/almost_equal_ulps.hpp>
#include <cmath>
namespace myx {
namespace math {
bool almost_equal_ulps( const float a, const float b,
const int maxUlpsDiff )
{
float_cmp_t uA( a );
float_cmp_t uB( b );
// Если знаки разные, то числа не равны.
if ( uA.negative() != uB.negative() )
{
// Кроме случая, когда +0==-0
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
if ( a == b )
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
{
return( true );
}
return( false );
}
// Разница в младших битах.
auto ulpsDiff = std::abs( uA.i - uB.i );
if ( ulpsDiff <= maxUlpsDiff )
{
return( true );
}
return( false );
} // almost_equal_ulps
bool almost_equal_ulps( const double a, const double b,
const int maxUlpsDiff )
{
double_cmp_t uA( a );
double_cmp_t uB( b );
// Если знаки разные, то числа не равны.
if ( uA.negative() != uB.negative() )
{
// Кроме случая, когда +0==-0
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
if ( a == b )
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
{
return( true );
}
return( false );
}
// Разница в младших битах.
auto ulpsDiff = std::abs( uA.i - uB.i );
if ( ulpsDiff <= maxUlpsDiff )
{
return( true );
}
return( false );
} // almost_equal_ulps
} // namespace math
} // namespace myx

View File

@ -0,0 +1,31 @@
#ifndef MYX_MATH_ALMOST_EQUAL_ULPS_HPP_
#define MYX_MATH_ALMOST_EQUAL_ULPS_HPP_
#include <myx/math/float_cmp_types.hpp>
#include <cmath>
namespace myx {
namespace math {
/**
* @brief Проверка на равенство двух аргументов типа float.
* Параметр maxUlpsDiff определяет максимальную разницу между аргументами,
* при которой они считаются равными.
*/
bool almost_equal_ulps( const float a, const float b,
const int maxUlpsDiff );
/**
* @brief Проверка на равенство двух аргументов типа double.
* Параметр maxUlpsDiff определяет максимальную разницу между аргументами,
* при которой они считаются равными.
*/
bool almost_equal_ulps( const double a, const double b,
const int maxUlpsDiff );
} // namespace math
} // namespace myx
#endif // MYX_MATH_ALMOST_EQUAL_ULPS_HPP_

View File

@ -0,0 +1,73 @@
#include <myx/math/float_cmp_types.hpp>
#include <myx/math/almost_equal_ulps_and_abs.hpp>
#include <cmath>
namespace myx {
namespace math {
bool almost_equal_ulps_and_abs( const float a, const float b,
const float maxAbsDiff, const int maxUlpsDiff )
{
// Check if the numbers are really close -- needed
// when comparing numbers near zero.
float absDiff = fabsf( a - b );
if ( absDiff <= maxAbsDiff )
{
return( true );
}
float_cmp_t uA( a );
float_cmp_t uB( b );
// Different signs means they do not match.
if ( uA.negative() != uB.negative() )
{
return( false );
}
// Find the difference in ULPs.
int ulpsDiff = std::abs( uA.i - uB.i );
if ( ulpsDiff <= maxUlpsDiff )
{
return( true );
}
return( false );
} // almost_equal_ulps_and_abs
bool almost_equal_ulps_and_abs( const double a, const double b,
const double maxAbsDiff, const int maxUlpsDiff )
{
// Check if the numbers are really close -- needed
// when comparing numbers near zero.
double absDiff = fabs( a - b );
if ( absDiff <= maxAbsDiff )
{
return( true );
}
double_cmp_t uA( a );
double_cmp_t uB( b );
// Different signs means they do not match.
if ( uA.negative() != uB.negative() )
{
return( false );
}
// Find the difference in ULPs.
auto ulpsDiff = std::abs( uA.i - uB.i );
if ( ulpsDiff <= maxUlpsDiff )
{
return( true );
}
return( false );
} // almost_equal_ulps_and_abs
} // namespace math
} // namespace myx

View File

@ -0,0 +1,29 @@
#ifndef MYX_MATH_ALMOST_EQUAL_ULPS_HPP_
#define MYX_MATH_ALMOST_EQUAL_ULPS_HPP_
namespace myx {
namespace math {
/**
* @brief Проверка на равенство двух аргументов типа float.
* Параметр maxAbsDiff определяет максимальную абсолютную допустимую разницу.
* Параметр maxUlpsDiff определяет максимальную разницу между аргументами,
* при которой они считаются равными.
*/
bool almost_equal_ulps_and_abs( const float a, const float b,
const float maxAbsDiff, const int maxUlpsDiff );
/**
* @brief Проверка на равенство двух аргументов типа double.
* Параметр maxAbsDiff определяет максимальную абсолютную допустимую разницу.
* Параметр maxUlpsDiff определяет максимальную разницу между аргументами,
* при которой они считаются равными.
*/
bool almost_equal_ulps_and_abs( const double a, const double b,
const double maxAbsDiff, const int maxUlpsDiff );
} // namespace math
} // namespace myx
#endif // MYX_MATH_ALMOST_EQUAL_ULPS_HPP_

View File

@ -0,0 +1,54 @@
#ifndef MYX_MATH_FLOAT_CMP_TYPES_HPP_
#define MYX_MATH_FLOAT_CMP_TYPES_HPP_
#include <cstdint>
/**
* @brief Объединение для получения знака аргумента типа float.
*/
union float_cmp_t
{
int32_t i;
float f;
/**
* @brief Инициализация.
*/
float_cmp_t( float num = 0.0f ) : f( num )
{
}
/**
* @brief Функция, возращающая true, если значение отрицательное
*/
bool negative() const
{
return( i < 0 );
}
};
/**
* @brief Объединение для получения знака аргумента типа double.
*/
union double_cmp_t
{
int64_t i;
double d;
/**
* @brief Инициализация.
*/
double_cmp_t( double num = 0.0l ) : d( num )
{
}
/**
* @brief Функция, возращающая true, если значение отрицательное
*/
bool negative() const
{
return( i < 0 );
}
};
#endif // MYX_MATH_FLOAT_CMP_TYPES_HPP_