Merge pull request #299 from jlindgren90/float-printing

Allow UnityPrintFloat() to print a 7th digit.
This commit is contained in:
Mark VanderVoord
2018-11-28 15:27:37 -05:00
committed by GitHub
2 changed files with 243 additions and 80 deletions

View File

@@ -262,13 +262,25 @@ void UnityPrintMask(const UNITY_UINT mask, const UNITY_UINT number)
/*-----------------------------------------------*/
#ifndef UNITY_EXCLUDE_FLOAT_PRINT
/* This function prints a floating-point value in a format similar to
* printf("%.6g"). It can work with either single- or double-precision,
* but for simplicity, it prints only 6 significant digits in either case.
* Printing more than 6 digits accurately is hard (at least in the single-
* precision case) and isn't attempted here. */
/*
* This function prints a floating-point value in a format similar to
* printf("%.7g") on a single-precision machine or printf("%.9g") on a
* double-precision machine. The 7th digit won't always be totally correct
* in single-precision operation (for that level of accuracy, a more
* complicated algorithm would be needed).
*/
void UnityPrintFloat(const UNITY_DOUBLE input_number)
{
#ifdef UNITY_INCLUDE_DOUBLE
static const int sig_digits = 9;
static const UNITY_INT32 min_scaled = 100000000;
static const UNITY_INT32 max_scaled = 1000000000;
#else
static const int sig_digits = 7;
static const UNITY_INT32 min_scaled = 1000000;
static const UNITY_INT32 max_scaled = 10000000;
#endif
UNITY_DOUBLE number = input_number;
/* print minus sign (including for negative zero) */
@@ -293,27 +305,71 @@ void UnityPrintFloat(const UNITY_DOUBLE input_number)
}
else
{
UNITY_INT32 n_int = 0, n;
int exponent = 0;
int decimals, digits;
UNITY_INT32 n;
char buf[16] = {0};
/* scale up or down by powers of 10 */
while (number < 100000.0f / 1e6f) { number *= 1e6f; exponent -= 6; }
while (number < 100000.0f) { number *= 10.0f; exponent--; }
while (number > 1000000.0f * 1e6f) { number /= 1e6f; exponent += 6; }
while (number > 1000000.0f) { number /= 10.0f; exponent++; }
/*
* Scale up or down by powers of 10. To minimize rounding error,
* start with a factor/divisor of 10^10, which is the largest
* power of 10 that can be represented exactly. Finally, compute
* (exactly) the remaining power of 10 and perform one more
* multiplication or division.
*/
if (number < 1.0f)
{
UNITY_DOUBLE factor = 1.0f;
while (number < (UNITY_DOUBLE)max_scaled / 1e10f) { number *= 1e10f; exponent -= 10; }
while (number * factor < (UNITY_DOUBLE)min_scaled) { factor *= 10.0f; exponent--; }
number *= factor;
}
else if (number > (UNITY_DOUBLE)max_scaled)
{
UNITY_DOUBLE divisor = 1.0f;
while (number > (UNITY_DOUBLE)min_scaled * 1e10f) { number /= 1e10f; exponent += 10; }
while (number / divisor > (UNITY_DOUBLE)max_scaled) { divisor *= 10.0f; exponent++; }
number /= divisor;
}
else
{
/*
* In this range, we can split off the integer part before
* doing any multiplications. This reduces rounding error by
* freeing up significant bits in the fractional part.
*/
UNITY_DOUBLE factor = 1.0f;
n_int = (UNITY_INT32)number;
number -= (UNITY_DOUBLE)n_int;
while (n_int < min_scaled) { n_int *= 10; factor *= 10.0f; exponent--; }
number *= factor;
}
/* round to nearest integer */
n = ((UNITY_INT32)(number + number) + 1) / 2;
if (n > 999999)
#ifndef UNITY_ROUND_TIES_AWAY_FROM_ZERO
/* round to even if exactly between two integers */
if ((n & 1) && ((UNITY_DOUBLE)n - number == 0.5f))
n--;
#endif
n += n_int;
if (n >= max_scaled)
{
n = 100000;
n = min_scaled;
exponent++;
}
/* determine where to place decimal point */
decimals = (exponent <= 0 && exponent >= -9) ? -exponent : 5;
decimals = (exponent <= 0 && exponent >= -(sig_digits + 3)) ? -exponent : (sig_digits - 1);
exponent += decimals;
/* truncate trailing zeroes after decimal point */