AlternativeUniversity.net
Alternative University

Computer Science

Multiple Precision Numbers

TTMath for C++

TTMath is a handy programming library implementing multiple precision floating point numbers on personal computers using C++ (GCC and Visual Studio). It is available as a header-only library, with liberal BSD license allowing free use in professional (commercial) applications without requiring distribution of source code.

Optional assembly language functions are included, which would require linking to a single file. This article shows how to use TTMath as a header-only library that does not require linking.

TTMath is easy to set up, and the progressive source code license allows you to change the library, without requiring original or adapted source code to be distributed.

In this article, we show how to quickly set up and use TTMath, without requiring any kind of configuration settings. Most applications only need this much. If all you need is to get multiple precision numbers implemented in a hurry, this article accomplishes doing that.

After completing this article, advanced users who need more features can then move on to implementing their own functions, for example rounding, elementary functions, etc.


Calculating Sine

We begin by calculating the sine of π/4 radians (45°). This example uses TTMath 0.9.4 (prerelease 2019.07.31).

Create a C++ console application, and replace the source code in main.cpp with this source code:

#define TTMATH_NOASM
#include <ttmath/ttmath.h>
#include <iostream>
 
typedef ttmath::Big<TTMATH_BITS(64),
    TTMATH_BITS(128)> MyBig;
 
int main()
{
  MyBig bigfloat_pi, bigfloat_OneFourth,
    bigfloat_PiDiv4,bigfloat_sin45;
 
  bigfloat_pi.SetPi();
  bigfloat_OneFourth = "0.25";
  bigfloat_PiDiv4
    = bigfloat_pi * bigfloat_OneFourth;
 
  bigfloat_sin45 = Sin(bigfloat_PiDiv4);
 
  std::cout << "bigfloat_sin45 = "
    << bigfloat_sin45 << std::endl;
}

This calculates the sine of π/4 using multiple precision floating point numbers that have a 64-bit exponent and a 128-bit significand (mantissa).

On x64 systems, used in these examples, the exponent and mantissa each need to be a multiple of 64 bits. On 32-bit systems, exponents and mantissas can be multiples of 32 bits.

Build and run the program, and use a calculator to verify that the calculated sine of 45° is correct.


Optics Example

Problem: For hot desert sand that is effectively flat (having enough concave curvature to offset Earth's convex curvature), with air temperature within 30 cm (1 ft) of the ground 44° C (111° F), and air temperature above that at 35° C (95° F), how far must a 7-meter tall building be across the desert sand for a person to see the building in a mirage reflection?

Answer: We find the critical angle of total internal reflection using Snell’s Law, and use trigonometry and geometry to calculate horizontal distances from the viewer to the critical angle reflection point, and from the reflection point to the top of the building, as follows:

The NIST Calculator gives these refractive indexes of air at 10 percent relative humidity with light that would have 633 nm wavelength in a vacuum:

35°C   n1 = 1.000258339
44°C   n2 = 1.000250873

Snell’s Law states:

\[ \frac{\sin(\theta_1)}{\sin(\theta_2)} = \frac{n_2}{n_1} \]

The angle θ1 subtends the vertical surface normal and incidence angle in medium n1 (35°C air). The other angle (θ2) is the refraction angle transmitting into medium n2 (44°C air) and will be π/2 (90°) when θ1 is the critical angle of total internal reflection (reflecting incident light back into the 35°C air, instead of allowing any of that light to transmit into the less dense 44°C air on the ground, making that interface between the two air layers look like water at a distance because it is reflecting all light at that viewing angle).

Since θ2 becomes π/2 (90°) at the critical angle of θ1:

sin(θ2) = sin(π/2) = 1

Then Snell’s Law formula becomes:

\[ \frac{\sin(\theta_1)}{\sin(\theta_2)} = \frac{\sin(\theta_1)}{1} = \sin(\theta_1) = \frac{n_2}{n_1} \]

\[ \theta_1 = \arcsin\left(\frac{n_2}{n_1}\right) \]

Using TTMath to calculate θ1:

#define TTMATH_NOASM
#include <ttmath/ttmath.h>
#include <iostream>
 
typedef ttmath::Big<TTMATH_BITS(64),
    TTMATH_BITS(128)> MyBig;
 
int main()
{
  MyBig n1, n2, n2divn1, theta1,
    num2pi, num360, theta1degrees;
 
  n1 = "1.000258339";
  n2 = "1.000250873";
  n2divn1 = n2 / n1;
  theta1 = ASin(n2divn1);
  num2pi.Set2Pi();
  num360 = "360.0";
  theta1degrees
    = theta1 * num360 / num2pi;
 
  std::cout
    << "Critical angle in degrees = "
    << std::endl
    << theta1degrees
    << std::endl;
}

gives the following result:

Critical angle in degrees =
89.77862641266625173821492140070866017

That is almost 90° (referred to as “grazing incidence”).

Next we use the trigonometry of a right triangle to calculate the horizontal distance from the viewer to the vertical surface normal at the critical angle reflection point.

Assume the viewpoint height is 1.5 m (eye level), which is 1.2 m above the interface that separates the 44° C and the 35° C air layers.

In the following right triangle, used for illustration, vertex A of the triangle is the critical angle reflection point (on the interface between the air layers), C is the viewpoint (at viewer eye level), and AB is the vertical height from the critical angle reflection point to the viewer eye level:

The critical angle of θ is 89.7786264… degrees. The vertical distance from the air layers interface to eye level (AB) is 1.2 meters.

From trigonometry, in a right triangle, for an angle that is not the right angle, the tangent of the angle equals the length of the side opposite the angle divided by the length of the adjacent side that is not the hypotenuse. In this case:

tan(θ)  =  BC ╱ AB

The horizontal distance from the viewpoint to surface normal of the critical angle reflection point is BC. Rearranging this formula to solve for BC:

BC  =  AB tan(θ)

Using TTMath to calculate BC:

MyBig AB, BC;
AB = "1.2";
BC = AB * Tan(theta1);
 
std::cout
  << "BC = " << BC
  << " meters"
  << std::endl;

gives the following result:

BC = 310.5817370318422769378978492342740621 meters

Light from the building reaching a reflection point will have the same surface normal angle as its reflection toward the viewer. That angle is denoted θ.

Even though both angles are equal, the distance from the building to the reflection point is longer than from the viewer to the reflection point, because the building is taller than the viewer:

Vertex E of the left triangle is the top of the building, which has a vertical height of 7 meters above ground level. Subtracting 30 cm for the warmer air layer at the ground, the top of the building is 6.7 meters above the reflecting interface between the two air layers. This vertical height (6.7 m) is the length of the side AD of the left triangle.

Since the two triangles are similar triangles, corresponding ratios of corresponding sides are equal:

AB ╱ BC  =  AD ╱ DE

Rearranging to solve for DE:

DE  =  (AD · BC) ╱ AB

Using TTMath to calculate DE:

MyBig AD, DE;
AD = "6.7";
DE = (AD * BC) / AB;
 
std::cout
  << "DE = " << DE
  << " meters"
  << std::endl;
 
std::cout
  << "BC + DE = " << BC + DE
  << " meters"
  << std::endl;

gives the following result:

DE = 1734.0813650944527129032629915580301799 meters
BC + DE = 2044.663102126294989841160840792304242 meters

The building needs to be at least 2.045 kilometers away.