Version 8 (modified by 8 years ago) (diff) | ,
---|
Table of Contents
Real numbers
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 |