I've tried Boost Multi-Precision (Boost MP) and ttmath.org's library, but neither emulate the single-precision float -- Boost MP's minimum precision is 16-bits instead of 8, and the case is similar for ttmath.org's library.
Do you have any recommendations on single-precision floating point libraries?
I have a small code that snaps a double value to the closest float value below it, further quantizing it.
The whole code is at: https://github.com/sjhalayka/mercury_gr_process
The bare minimum part of the code is:
custom_math::vector_3 grav_acceleration(const custom_math::vector_3& pos, const custom_math::vector_3& vel)
{
custom_math::vector_3 grav_dir = sun_pos - pos;
const double distance = grav_dir.length();
grav_dir.normalize();
custom_math::vector_3 accel = grav_dir * grav_constant * sun_mass / (distance * distance);
return accel;
}
// Snap value
double truncate_normalized_double(double d)
{
if (d < 0.0)
{
return 0.0;
}
else if (d > 1.0)
{
return 1.0;
}
return nexttowardf(d, 0.0);
}
void proceed_symplectic4(custom_math::vector_3& pos, custom_math::vector_3& vel, double dt)
{
static double const cr2 = pow(2.0, 1.0 / 3.0);
static const double c[4] =
{
1.0 / (2.0 * (2.0 - cr2)),
(1.0 - cr2) / (2.0 * (2.0 - cr2)),
(1.0 - cr2) / (2.0 * (2.0 - cr2)),
1.0 / (2.0 * (2.0 - cr2))
};
static const double d[4] =
{
1.0 / (2.0 - cr2),
-cr2 / (2.0 - cr2),
1.0 / (2.0 - cr2),
0.0
};
{
const custom_math::vector_3 grav_dir = sun_pos - pos;
const double distance = grav_dir.length();
const double Rs = 2 * grav_constant * sun_mass / (speed_of_light * speed_of_light);
const double alpha = 2.0 - sqrt(1 - (vel.length() * vel.length()) / (speed_of_light * speed_of_light));
const double beta = sqrt(1.0 - Rs / distance);
const double beta_truncated = truncate_normalized_double(beta);
pos += vel * c[0] * dt * beta_truncated;
vel += grav_acceleration(pos, vel) * d[0] * dt * alpha;
}
{
const custom_math::vector_3 grav_dir = sun_pos - pos;
const double distance = grav_dir.length();
const double Rs = 2 * grav_constant * sun_mass / (speed_of_light * speed_of_light);
const double alpha = 2.0 - sqrt(1 - (vel.length() * vel.length()) / (speed_of_light * speed_of_light));
const double beta = sqrt(1.0 - Rs / distance);
const double beta_truncated = truncate_normalized_double(beta);
pos += vel * c[1] * dt * beta_truncated;
vel += grav_acceleration(pos, vel) * d[1] * dt * alpha;
}
{
const custom_math::vector_3 grav_dir = sun_pos - pos;
const double distance = grav_dir.length();
const double Rs = 2 * grav_constant * sun_mass / (speed_of_light * speed_of_light);
const double alpha = 2.0 - sqrt(1 - (vel.length() * vel.length()) / (speed_of_light * speed_of_light));
const double beta = sqrt(1.0 - Rs / distance);
const double beta_truncated = truncate_normalized_double(beta);
pos += vel * c[2] * dt * beta_truncated;
vel += grav_acceleration(pos, vel) * d[2] * dt * alpha;
}
{
const custom_math::vector_3 grav_dir = sun_pos - pos;
const double distance = grav_dir.length();
const double Rs = 2 * grav_constant * sun_mass / (speed_of_light * speed_of_light);
const double alpha = 2.0 - sqrt(1 - (vel.length() * vel.length()) / (speed_of_light * speed_of_light));
const double beta = sqrt(1.0 - Rs / distance);
const double beta_truncated = truncate_normalized_double(beta);
pos += vel * c[3] * dt * beta_truncated;
// vel += grav_acceleration(pos, vel) * d[3] * dt * alpha; // last element d[3] is always 0
}
}