Introduction
This is a set of floating point utilities. 16 functions are provided:
FloatsEqual
Testing float's for equality. When the operands of
operators == and != are some form of floating type (float, double, or long
double). Testing for equality between two floating point quantities is suspect
because of round-off error and the lack of perfect representation of fractions.
Round
Rounds a number to a specified number of digits.
RoundDouble
Similar to Round()
above, but uses
double's instead of float's.
SigFig
Rounds a number to a specified number of significant
figures.
FloatToText
Converts a floating point number to ascii (without
the appended zeros)
CalcBase
This function wraps the given number so that it
remains within its base. Returns a number between 0 and base - 1. For example if
the base given was 10 and the parameter was 10 it would wrap it so that the
number is now a 0. If the number given were -1, then the result would be 9. This
function can also be used everywhere where a number needs to be kept within a
certain range, for example angles (0 and 360) and radians (0 to TWO_PI).
CalcBaseFloat
Same as CalcBase()
above, except
using floats
Angle
Make sure angle is between 0 and 359
LineLength
Calculates the length of a line between the
following two points
RoundValue
Converts a floating point value to an integer,
very fast
FloatToInt
Converts a floating point value to an integer,
very fast
FP_INV
This is about 2.12 times faster than using 1.0f / n
CheckRange
Makes sure Value is within range
CheckMin
Makes sure Value is >= Min
CheckMax
Makes sure Value is <= Max
Divide
Performs a safe division
The credit for Round()
and RoundDouble()
goes to
Josef Wolfsteiner.
Modifications
- Simon Hughes, 18th November 2003.
- Updated
SigFig()
to check for 0.0 being passed in as the value,
as log10f(0) returns NaN
- Added
FloatsEqual()
function
- Added
CalcBase()
function
- Added
CalcBaseFloat()
function
- Added
Angle()
function
- Added
LineLength()
function
- Modified
RoundValue()
function so it is much faster
- Added
FloatToInt()
- Added
FP_INV
for very fast 1/n calculations
- Added
CheckRange(), CheckMin(), CheckMax(), Divide()
template
functions
Header
#define float_equality 1.0e-20f
bool FloatsEqual(const float &a, const float &b);
places.
float Round(const float &number, const int num_digits);
double RoundDouble(double doValue, int nPrecision);
float SigFig(float X, int SigFigs);
CString FloatToText(float n, int nNumberOfDecimalPlaces = -1);
int CalcBase(const int base, int num);
float CalcBaseFloat(const float base, float num);
int Angle(const int &angle);
float LineLength(const CPoint &point1, const CPoint &point2);
inline int RoundValue(float param)
{
int a;
int *int_pointer = &a;
__asm fld param
__asm mov edx,int_pointer
__asm FRNDINT
__asm fistp dword ptr [edx];
return a;
}
inline void FloatToInt(int *int_pointer, const float &f)
{
__asm fld f
__asm mov edx,int_pointer
__asm FRNDINT
__asm fistp dword ptr [edx];
}
#define FP_INV(r,p) \
{ \
int _i = 2 * 0x3F800000 - *(int *)&(p); \
(r) = *(float *)&_i; \
(r) = (r) * (2.0f - (p) * (r)); \
}
template<CLASS T>
void CheckRange(T &Var, const T &Min, const T &Max)
{
if(Var < Min)
Var = Min;
else
if(Var > Max)
Var = Max;
}
template<CLASS T>
void CheckMin(T &Var, const T &Min)
{
if(Var < Min)
Var = Min;
}
template<CLASS T>
void CheckMax(T &Var, const T &Max)
{
if(Var > Max)
Var = Max;
}
template<CLASS T>
inline T Divide(const T &a, const T &b)
Source code
places.
float Round(const float &number, const int num_digits)
{
float doComplete5i, doComplete5(number * powf(10.0f, (float) (num_digits + 1)));
if(number < 0.0f)
doComplete5 -= 5.0f;
else
doComplete5 += 5.0f;
doComplete5 /= 10.0f;
modff(doComplete5, &doComplete5i);
return doComplete5i / powf(10.0f, (float) num_digits);
}
double RoundDouble(double doValue, int nPrecision)
{
static const double doBase = 10.0;
double doComplete5, doComplete5i;
doComplete5 = doValue * pow(doBase, (double) (nPrecision + 1));
if(doValue < 0.0)
doComplete5 -= 5.0;
else
doComplete5 += 5.0;
doComplete5 /= doBase;
modf(doComplete5, &doComplete5i);
return doComplete5i / pow(doBase, (double) nPrecision);
}
float SigFig(float X, int SigFigs)
{
if(SigFigs < 1)
{
ASSERT(FALSE);
return X;
}
if(X == 0.0f)
return X;
int Sign;
if(X < 0.0f)
Sign = -1;
else
Sign = 1;
X = fabsf(X);
float Powers = powf(10.0f, floorf(log10f(X)) + 1.0f);
return Sign * Round(X / Powers, SigFigs) * Powers;
}
CString FloatToText(float n, int nNumberOfDecimalPlaces)
{
CString str;
if(nNumberOfDecimalPlaces >= 0)
{
int decimal, sign;
char *buffer = _fcvt((double)n, nNumberOfDecimalPlaces, &decimal, &sign);
CString temp(buffer);
if(sign != 0)
str = "-";
if(decimal <= 0)
{
str += "0.";
for(; decimal < 0; decimal++)
str += "0";
str += temp;
} else {
str += temp.Left(decimal);
str += ".";
str += temp.Right(temp.GetLength() - decimal);
}
} else {
str.Format("%-g", n);
}
int nFind = str.Find(".");
if(nFind >= 0)
{
int nFinde = str.Find("e");
if(nFinde < 0)
{
while(str.GetLength() > 1 && str.Right(1) == "0")
str = str.Left(str.GetLength() - 1);
}
}
if(str.Right(1) == ".")
str = str.Left(str.GetLength() - 1);
return str;
}
bool FloatsEqual(const float &a, const float &b)
{
return (fabs(a - b) <= float_equality);
}
int CalcBase(const int base, int num)
{
if(num >= 0 && num < base)
return num;
if(num < 0)
{
num %= base;
num += base;
} else {
num %= base;
}
return num;
}
float CalcBaseFloat(const float base, float num)
{
if(num >= 0.0f && num < base)
return num;
if(num < 0.0f)
return fmodf(num, base) + base;
return fmodf(num, base);
}
int Angle(const int &angle)
{
return CalcBase(360, angle);
}
float LineLength(const CPoint &point1, const CPoint &point2)
{
const CPoint dist(point1 - point2);
return sqrtf(float((dist.x * dist.x) + (dist.y * dist.y)));
}
C++ and C# Developer for 21 years. Microsoft Certified.
UK Senior software developer / team leader.
I've been writing software since 1985. I pride myself on designing and creating software that is first class. That means it has to be fast, scalable, and with good use of design patterns.
I have done everything from risk analysis and explosion modelling, banking systems, to highly scalable multi-threaded arrival and departure screens in many leading airports, to state of the art wireless warehouse systems.