Version 10 (modified by sam, 10 years ago) (diff)

link to source browser

<lol/math/real.h>

View this file in the source browser: trunk/src/lol/math/real.h

Real numbers are a custom class that stores floating-point numbers with approximately 150 digits of precision.

Bug warning: it is not yet possible to change the precision without recompiling everything.

Care has been taken to make the use of the real object as close as possible to float or double.

Usage

Support for real numbers is straightforward:

#include <lol/math/real.h>
using lol::real;

If you are not using the full Lol Engine but a stripped down version such as LolRemez, make sure you compile real.cpp together with your application.

If you do not wish to have a using declaration, simply use lol::real everywhere instead of real.

Creation

You can create a real number using numeric literals:

real x = 1.25, y = 2.0f;
real z = 0x100000;
real w(5);

It is also possible to use a string representation:

real w = "1.202056903159594285399738161511449990764986292";

Warning: it is critical that you understand the difference between "0.1" and 0.1 here:

real correct = "0.1";
real wrong = 0.1;

When you write 0.1 the compiler understands this as a double precision floating point literal whose actual value is 0.1000000000000000055511151231257827021181583404541015625, so you only get 17 digits of precision. When you write "0.1" the real number constructor will understand what you mean and will create an object with the highest possible precision.

Note that parsing a string to build a real number is expensive. Whenever possible, try to initialise reused variables only once, or use the constants provided by the real class.

Constants

Some commonly used constants are provided by the real class. They are similar to the M_PI, M_E etc. variables provided by the <math.h> header except they have the R_ prefix for “real”.

R_0 the integer value 0
R_1 the integer value 1
R_2 the integer value 2
R_3 the integer value 3
R_10 the integer value 10
R_E Euler’s number e
R_LOG2E the reciprocal of ln(2)
R_LOG10E the reciprocal of ln(10)
R_LN2 ln(2), the natural logarithm of 2
R_LN10 ln(10), the natural logarithm of 10
R_PI Archimede’s constant pi
R_PI_2 pi divided by 2
R_PI_3 pi divided by 3
R_PI_4 pi divided by 4
R_1_PI the reciprocal of pi
R_2_PI 2 divided by pi
R_2_SQRTPI 2 divided by the square root of pi
R_SQRT2 Pythagoras’ constant, the square root of 2
R_SQRT3 Theodorus’ constant, the square root of 3
R_SQRT1_2 the square root of 1/2

All these constants are accurate up to the full precision of the real number class.

Conversions

Real numbers can be cast implicitly to numeric types with basically the same rules as float or double:

real r ("1.5");
float f = r;

double d = real::R_LN10;

You can also print a real number to stdout with an arbitrary number of decimals:

real r("3.1415");
r.print(10);
3.141500000

Bug warning: it is not yet possible to output a real number to a standard C++ stream.

Operators

Most expected operators are available for real numbers:

  • +, -, *, /
  • unary +, unary -
  • +=, -=, *=, /=
  • ==, !=, <, <=, >, >=
  • implicit boolean conversion and ! operator

Example

Compute the first 150 digits of the golden ratio as the quotient of two very large Fibonacci numbers:

real a0(1), a1(1);
for (int i = 0; i < 400; i++)
{
    real tmp = a0 + a1;
    a0 = a1; a1 = tmp;
}
(a0 / a1).print(150);
6.18033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137484754088075386891752126633862223536931793180060766e-1

Functions

Most expected <math.h> functions are available for real numbers, even those only introduced in the C99 standard.

Trigonometric functions

sin sine function
cos cosine function
tan tangent function
asin arcsine function
acos arccosine function
atan arctangent function
atan2 two-argument arctangent

Hyperbolic functions

sinh hyperbolic sine
cosh hyperbolic cosine
tanh hyperbolic tangent

Exponentials and logarithms

exp(x) exponential
exp2(x) base-2 exponential
log(x) natural logarithm
log2(x) base-2 logarithm
log10(x) base-10 logarithm
frexp(x,&exp) split number into a normalised fraction and an exponent
ldexp(x,exp) multiply x by two to the power of exp
modf(x) split x into an integral part and a fractional part
ulp(x) return the smallest real e such that x+e != x
nextafter(x,y) return the next representable real following x in the direction of y

Power functions

re reciprocal: 1 divided by x
sqrt square root
cbrt cubic root
pow x raised to the power y
gamma the gamma function

Bug warning: as of now, the gamma function is only accurate to about 100 decimals instead of the expected 150.

Rounding, absolute value, remainder etc.

ceil the ceiling function
copysign copy x’s sign to y
floor the floor function
fabs absolute value
round the rounding function
fmod modulo: remainder of dividing x by y

Example

Find the solution to cos(x) = x³ using Newton-Raphson:

real x(0.5);
for (int i = 0; i < 10; i++)
    x = x - (cos(x) - x * x * x) / (-sin(x) - real::R_3 * x * x);
x.print(150);
8.65474033101614446620685901186228747792911931818935500889279915855447006056021560514064272319562802280528781987092146472497110319687730308211712150975e-1

Tips

Multiplication by powers of two

For fast multiplication or division by a power of two, use ldexp or integer operands:

real a = real::R_PI * (real)8; /* DO NOT USE: SLOW! */
real b = real::R_PI * 8.0f;    /* DO NOT USE: SLOW! */
real c = real::R_PI * 8;       /* OK, will be optimised */
real d = ldexp(real::R_PI, 3); /* OK, even better than above */

Multiplication by an integer type (int, long int etc.) detects powers of two automatically.

General speed observations

The Lol Engine real numbers target accuracy rather than speed: we expect functions such as sin, exp or pow to always be accurate to the last digit of precision. However, they may be very slow.

The table shows the relative timings you may expect from various operations:

operation speed (milliseconds)
+ (real) 0.14
* (real) 0.54
/ (real) 6.50
sin (real) 90.00
exp (real) 160.00

As a comparison, here are some values for floats:

operation speed (milliseconds)
/ (float) 0.001
sin (float) 0.40
exp (float) 0.08