11,926,827 members (56,227 online)
Add your own
alternative version

268.1K views
1.8K downloads
66 bookmarked
Posted

# Floating point utilites

, 17 Nov 2003 CPOL
 Rate this:
Please Sign up or sign in to vote.
A set of floating point utilities

## 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

```// 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.
// The value here is for testing two float values are equivalent within the
// range shown here. The implementation is:
//     if(fabs(a - b) > float_equality) ...
// See FloatsEqual(a, b) function
#define float_equality 1.0e-20f
bool FloatsEqual(const float &a, const float &b);

// Rounds a number to a specified number of digits.
// Number is the number you want to round.
// Num_digits specifies the number of digits to which you want to round number.
// If num_digits is greater than 0, then number is rounded to the
// specified number of decimal

places.
// If num_digits is 0, then number is rounded to the nearest integer.
// Examples
//        ROUND(2.15, 1)        equals 2.2
//        ROUND(2.149, 1)        equals 2.1
//        ROUND(-1.475, 2)    equals -1.48
float Round(const float &number, const int num_digits);
double RoundDouble(double doValue, int nPrecision);

// Rounds X to SigFigs significant figures.
// Examples
//        SigFig(1.23456, 2)        equals 1.2
//        SigFig(1.23456e-10, 2)    equals 1.2e-10
//        SigFig(1.23456, 5)        equals 1.2346
//        SigFig(1.23456e-10, 5)    equals 1.2346e-10
//        SigFig(0.000123456, 2)    equals 0.00012
float SigFig(float X, int SigFigs);

// Converts a floating point number to ascii (without the appended 0's)
// Rounds the value if nNumberOfDecimalPlaces >= 0
CString FloatToText(float n, int nNumberOfDecimalPlaces = -1);

// 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).
int CalcBase(const int base, int num);
// Same as CalcBase() above, except using floats
float CalcBaseFloat(const float base, float num);
// Make sure angle is between 0 and 359
int Angle(const int &angle);

// Calculates the length of a line between the following two points
float LineLength(const CPoint &point1, const CPoint &point2);

//lint -save -e*
// Converts a floating point value to an integer, very fast.
inline int RoundValue(float param)
{
// Uses the FloatToInt functionality
int a;
int *int_pointer = &a;

__asm  fld  param
__asm  mov  edx,int_pointer
__asm  FRNDINT
__asm  fistp dword ptr [edx];

return a;
}
//lint -restore

// At the assembly level the recommended workaround for the second
// FIST bug is the same for the first;
// inserting the FRNDINT instruction immediately preceding the
// FIST instruction.
// lint -e{715}
// Converts a floating point value to an integer, very fast.
inline void FloatToInt(int *int_pointer, const float &f)
{
__asm  fld  f
__asm  mov  edx,int_pointer
__asm  FRNDINT
__asm  fistp dword ptr [edx];
}

// This is about 2.12 times faster than using 1.0f / n
// r = 1/p
#define FP_INV(r,p) \
{ \
int _i = 2 * 0x3F800000 - *(int *)&(p); \
(r) = *(float *)&_i; \
(r) = (r) * (2.0f - (p) * (r)); \
}

// Makes sure Var is within range
template<CLASS T>
void CheckRange(T &Var, const T &Min, const T &Max)
{
if(Var < Min)
Var = Min;
else
if(Var > Max)
Var = Max;
}

// Makes sure Var is >= Min
template<CLASS T>
void CheckMin(T &Var, const T &Min)
{
if(Var < Min)
Var = Min;
}

// Makes sure Var is <= Max
template<CLASS T>
void CheckMax(T &Var, const T &Max)
{
if(Var > Max)
Var = Max;
}

// Performs a safe division. Checks that b is not zero before division.
template<CLASS T>
inline T Divide(const T &a, const T &b)    ```

## Source code

```// Rounds a number to a specified number of digits.
// Number is the number you want to round.
// Num_digits specifies the number of digits to which you want
// to round number.
// If num_digits is greater than 0, then number is rounded
// to the specified number of decimal

places.
// If num_digits is 0, then number is rounded to the nearest integer.
// Examples
//        ROUND(2.15, 1)        equals 2.2
//        ROUND(2.149, 1)        equals 2.1
//        ROUND(-1.475, 2)    equals -1.48
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);
}

// Rounds X to SigFigs significant figures.
// Examples
//        SigFig(1.23456, 2)        equals 1.2
//        SigFig(1.23456e-10, 2)    equals 1.2e-10
//        SigFig(1.23456, 5)        equals 1.2346
//        SigFig(1.23456e-10, 5)    equals 1.2346e-10
//        SigFig(0.000123456, 2)    equals 0.00012
float SigFig(float X, int SigFigs)
{
if(SigFigs < 1)
{
ASSERT(FALSE);
return X;
}

// log10f(0) returns NaN
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;
}

// Converts a floating point number to ascii (without the appended 0's)
// Rounds the value if nNumberOfDecimalPlaces >= 0
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);

// Sign for +ve or -ve
if(sign != 0)
str = "-";

// Copy digits up to decimal point
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);
}

// Remove appended zero's. "123.45000" become "123.45"
int nFind = str.Find(".");
if(nFind >= 0)
{
int nFinde = str.Find("e");    // 1.0e-010 Don't strip the ending zero
if(nFinde < 0)
{
while(str.GetLength() > 1 && str.Right(1) == "0")
str = str.Left(str.GetLength() - 1);
}
}

// Remove decimal point if nothing after it. "1234." becomes "1234"
if(str.Right(1) == ".")
str = str.Left(str.GetLength() - 1);

return str;
}

// 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.
// The value here is for testing two float values are equivalent within the
// range as specified by float_equality.
bool FloatsEqual(const float &a, const float &b)
{
return (fabs(a - b) <= float_equality);
}

// 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).
int CalcBase(const int base, int num)
{
if(num >= 0 && num < base)
return num;    // No adjustment neccessary

if(num < 0)
{
num %= base;
num += base;
} else {
num %= base;
}

return num;
}

// Same as CalcBase() above, except using floats
float CalcBaseFloat(const float base, float num)
{
if(num >= 0.0f && num < base)
return num;    // No adjustment neccessary

if(num < 0.0f)
return fmodf(num, base) + base;
return fmodf(num, base);
}

// Make sure angle is between 0 and 359
int Angle(const int &angle)
{
return CalcBase(360, angle);
}

// Calculates the length of a line between the following two points
float LineLength(const CPoint &point1, const CPoint &point2)
{
const CPoint dist(point1 - point2);
return sqrtf(float((dist.x * dist.x) + (dist.y * dist.y)));
}```

## License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

## About the Author

 Software Developer (Senior) www.ByBox.com United Kingdom
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.

## Comments and Discussions

 First PrevNext
 Ok, but special numbers? MNorzagaray25-Apr-13 9:00 MNorzagaray 25-Apr-13 9:00
 conversion from float to double Roman Tarasov1-Dec-09 3:48 Roman Tarasov 1-Dec-09 3:48
 Re: conversion from float to double Simon Hughes1-Dec-09 5:53 Simon Hughes 1-Dec-09 5:53
 IMHO equality test, done this way, is rather arbitrary. CPallini 31-Dec-07 11:49 CPallini 31-Dec-07 11:49
 Faster Round()? Yap Chun Wei22-Jun-06 21:27 Yap Chun Wei 22-Jun-06 21:27
 Re: Faster Round()? [modified] Simon Hughes24-Jun-06 14:11 Simon Hughes 24-Jun-06 14:11
 Re: Faster Round()? [modified] Yap Chun Wei25-Jun-06 15:52 Yap Chun Wei 25-Jun-06 15:52
 Re: Faster Round()? Simon Hughes26-Jun-06 9:42 Simon Hughes 26-Jun-06 9:42
 Re: Faster Round()? bkrahmer26-Feb-10 13:36 bkrahmer 26-Feb-10 13:36
 Re: Faster Round()? kanbang4-Aug-10 17:05 kanbang 4-Aug-10 17:05
 Re: Faster Round()? Hoornet9322-Oct-07 22:04 Hoornet93 22-Oct-07 22:04
 need help ravirevolt10-Mar-06 19:15 ravirevolt 10-Mar-06 19:15
 Double to Float Question T. Kulathu Sarma28-Nov-03 12:38 T. Kulathu Sarma 28-Nov-03 12:38
 Re: Double to Float Question Nayan Choudhary1-Sep-04 23:25 Nayan Choudhary 1-Sep-04 23:25
 Visual C++ float to string conversion problem Ed Storey8-Dec-00 6:47 Ed Storey 8-Dec-00 6:47
 Re: Visual C++ float to string conversion problem Codin' Carlos20-Jan-02 14:20 Codin' Carlos 20-Jan-02 14:20
 Re: Visual C++ float to string conversion problem tomasusan7-Nov-06 9:41 tomasusan 7-Nov-06 9:41
 Fast divides sigfpe22-Nov-00 11:01 sigfpe 22-Nov-00 11:01
 Maintaining Significant Figures Dave Aebi28-Sep-00 17:12 Dave Aebi 28-Sep-00 17:12
 SERIOUS Performance improvements for sqrt Simon Hughes27-Sep-00 6:18 Simon Hughes 27-Sep-00 6:18
 Re: SERIOUS Performance improvements for sqrt Steven J. Ackerman29-Sep-00 12:00 Steven J. Ackerman 29-Sep-00 12:00
 Re: SERIOUS Performance improvements for sqrt Simon Hughes2-Oct-00 4:12 Simon Hughes 2-Oct-00 4:12
 Your square_root() function is accurate, but is slower than sqrtf() iteself (about 3.5 times slower) :-
 Re: SERIOUS Performance improvements for sqrt Steven J. Ackerman2-Oct-00 8:18 Steven J. Ackerman 2-Oct-00 8:18
 Re: SERIOUS Performance improvements for sqrt DQNOK18-Apr-07 13:20 DQNOK 18-Apr-07 13:20
 SERIOUS Performance improvements for 1/n Simon Hughes27-Sep-00 6:14 Simon Hughes 27-Sep-00 6:14
 Re: SERIOUS Performance improvements for 1/n emilio_g19-Nov-03 0:02 emilio_g 19-Nov-03 0:02
 Re: SERIOUS Performance improvements for 1/n Simon Hughes19-Nov-03 0:59 Simon Hughes 19-Nov-03 0:59
 Re: SERIOUS Performance improvements for 1/n JasonDoucette18-Oct-04 11:21 JasonDoucette 18-Oct-04 11:21
 SERIOUS Performance improvements for RoundValue Simon Hughes27-Sep-00 6:12 Simon Hughes 27-Sep-00 6:12
 Re: SERIOUS Performance improvements for RoundValue Ilia Kirsanau2-Jun-03 22:39 Ilia Kirsanau 2-Jun-03 22:39
 Re: SERIOUS Performance improvements for RoundValue Simon Hughes19-Nov-03 1:10 Simon Hughes 19-Nov-03 1:10
 Re: SERIOUS Performance improvements for RoundValue bob1697231-Jan-08 6:14 bob16972 31-Jan-08 6:14
 Round to Nearest X function Martin MacRobert26-Sep-00 13:38 Martin MacRobert 26-Sep-00 13:38
 Re: Round to Nearest X function Gene17-Jul-01 11:22 Gene 17-Jul-01 11:22
 Re: Round to Nearest X function mier26-Nov-03 3:11 mier 26-Nov-03 3:11
 Re: Round to Nearest X function zPilott27-Oct-04 10:51 zPilott 27-Oct-04 10:51
 Rounding errata. DerekDaz22-Sep-00 11:21 DerekDaz 22-Sep-00 11:21
 Re: Rounding errata. Arlynn Smith25-Sep-00 4:49 Arlynn Smith 25-Sep-00 4:49
 Re: Rounding errata. reman18-Nov-03 18:42 reman 18-Nov-03 18:42
 Re: Rounding errata. Mosc12-Jul-07 7:58 Mosc 12-Jul-07 7:58
 Comparing floating point values for equality John Simmons / outlaw programmer20-Sep-00 4:32 John Simmons / outlaw programmer 20-Sep-00 4:32
 Re: Comparing floating point values for equality Terence Russell24-Sep-00 22:20 Terence Russell 24-Sep-00 22:20
 Re: Comparing floating point values for equality Thomas Haase25-Nov-03 22:15 Thomas Haase 25-Nov-03 22:15
 I use this for rounding John Simmons / outlaw programmer20-Sep-00 4:25 John Simmons / outlaw programmer 20-Sep-00 4:25
 Re: I use this for rounding Hemme_one26-Nov-03 1:05 Hemme_one 26-Nov-03 1:05
 A Better FloatToText() function? John Simmons / outlaw pogrammer20-Sep-00 4:13 John Simmons / outlaw pogrammer 20-Sep-00 4:13
 Re: A Better FloatToText() function? Jim Wuerch20-Sep-00 9:34 Jim Wuerch 20-Sep-00 9:34
 Re: A Better FloatToText() function? John Simmons / outlaw programmer21-Sep-00 1:26 John Simmons / outlaw programmer 21-Sep-00 1:26
 Re: A Better FloatToText() function? John Simmons / outlaw programmer21-Sep-00 2:01 John Simmons / outlaw programmer 21-Sep-00 2:01
 Re: A Better FloatToText() function? Jim Wuerch24-Sep-00 19:31 Jim Wuerch 24-Sep-00 19:31
 Last Visit: 31-Dec-99 19:00     Last Update: 27-Nov-15 3:48 Refresh 12 Next »

General    News    Suggestion    Question    Bug    Answer    Joke    Praise    Rant    Admin

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.151126.1 | Last Updated 18 Nov 2003
Article Copyright 1999 by Simon Hughes
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid