[833] | 1 | // One modification by macko in FormatScientific(): use 3 digits of exponent only if necessary (e+123), otherwise use two if necessary (e+45), otherwise use one (e+6).
|
---|
[823] | 2 | // This is consistent with java and javascript, and partially with python (which never uses one digit, only two or three).
|
---|
[833] | 3 | // To always print 3 digits in exponent (zero-padding if necessary), uncomment:
|
---|
| 4 | // #define PRINTFLOAT_DRAGON4_ALWAYS_3_DIGIT_EXPONENT
|
---|
[823] | 5 |
|
---|
| 6 |
|
---|
| 7 | /******************************************************************************
|
---|
| 8 | Copyright (c) 2014 Ryan Juckett
|
---|
| 9 | http://www.ryanjuckett.com/
|
---|
| 10 |
|
---|
| 11 | This software is provided 'as-is', without any express or implied
|
---|
| 12 | warranty. In no event will the authors be held liable for any damages
|
---|
| 13 | arising from the use of this software.
|
---|
| 14 |
|
---|
| 15 | Permission is granted to anyone to use this software for any purpose,
|
---|
| 16 | including commercial applications, and to alter it and redistribute it
|
---|
| 17 | freely, subject to the following restrictions:
|
---|
| 18 |
|
---|
| 19 | 1. The origin of this software must not be misrepresented; you must not
|
---|
| 20 | claim that you wrote the original software. If you use this software
|
---|
| 21 | in a product, an acknowledgment in the product documentation would be
|
---|
| 22 | appreciated but is not required.
|
---|
| 23 |
|
---|
| 24 | 2. Altered source versions must be plainly marked as such, and must not be
|
---|
| 25 | misrepresented as being the original software.
|
---|
| 26 |
|
---|
| 27 | 3. This notice may not be removed or altered from any source
|
---|
| 28 | distribution.
|
---|
| 29 | ******************************************************************************/
|
---|
| 30 |
|
---|
| 31 | #include "PrintFloat.h"
|
---|
| 32 | #include "Dragon4.h"
|
---|
[834] | 33 | #include "MathDragon4.h"
|
---|
[823] | 34 |
|
---|
| 35 | #include <string.h>
|
---|
| 36 |
|
---|
| 37 | //******************************************************************************
|
---|
| 38 | // Helper union to decompose a 32-bit IEEE float.
|
---|
| 39 | // sign: 1 bit
|
---|
| 40 | // exponent: 8 bits
|
---|
| 41 | // mantissa: 23 bits
|
---|
| 42 | //******************************************************************************
|
---|
| 43 | union tFloatUnion32
|
---|
| 44 | {
|
---|
| 45 | tB IsNegative() const { return (m_integer >> 31) != 0; }
|
---|
| 46 | tU32 GetExponent() const { return (m_integer >> 23) & 0xFF; }
|
---|
| 47 | tU32 GetMantissa() const { return m_integer & 0x7FFFFF; }
|
---|
| 48 |
|
---|
| 49 | tF32 m_floatingPoint;
|
---|
| 50 | tU32 m_integer;
|
---|
| 51 | };
|
---|
| 52 |
|
---|
| 53 | //******************************************************************************
|
---|
| 54 | // Helper union to decompose a 64-bit IEEE float.
|
---|
| 55 | // sign: 1 bit
|
---|
| 56 | // exponent: 11 bits
|
---|
| 57 | // mantissa: 52 bits
|
---|
| 58 | //******************************************************************************
|
---|
| 59 | union tFloatUnion64
|
---|
| 60 | {
|
---|
| 61 | tB IsNegative() const { return (m_integer >> 63) != 0; }
|
---|
| 62 | tU32 GetExponent() const { return (m_integer >> 52) & 0x7FF; }
|
---|
| 63 | tU64 GetMantissa() const { return m_integer & 0xFFFFFFFFFFFFFull; }
|
---|
| 64 |
|
---|
| 65 | tF64 m_floatingPoint;
|
---|
| 66 | tU64 m_integer;
|
---|
| 67 | };
|
---|
| 68 |
|
---|
| 69 | //******************************************************************************
|
---|
| 70 | // Outputs the positive number with positional notation: ddddd.dddd
|
---|
| 71 | // The output is always NUL terminated and the output length (not including the
|
---|
| 72 | // NUL) is returned.
|
---|
| 73 | //******************************************************************************
|
---|
| 74 | tU32 FormatPositional
|
---|
| 75 | (
|
---|
| 76 | tC8 * pOutBuffer, // buffer to output into
|
---|
| 77 | tU32 bufferSize, // maximum characters that can be printed to pOutBuffer
|
---|
| 78 | tU64 mantissa, // value significand
|
---|
| 79 | tS32 exponent, // value exponent in base 2
|
---|
| 80 | tU32 mantissaHighBitIdx, // index of the highest set mantissa bit
|
---|
| 81 | tB hasUnequalMargins, // is the high margin twice as large as the low margin
|
---|
| 82 | tS32 precision // Negative prints as many digits as are needed for a unique
|
---|
| 83 | // number. Positive specifies the maximum number of
|
---|
| 84 | // significant digits to print past the decimal point.
|
---|
| 85 | )
|
---|
| 86 | {
|
---|
| 87 | RJ_ASSERT(bufferSize > 0);
|
---|
| 88 |
|
---|
| 89 | tS32 printExponent;
|
---|
| 90 | tU32 numPrintDigits;
|
---|
| 91 |
|
---|
| 92 | tU32 maxPrintLen = bufferSize - 1;
|
---|
| 93 |
|
---|
| 94 | if (precision < 0)
|
---|
| 95 | {
|
---|
| 96 | numPrintDigits = Dragon4( mantissa,
|
---|
| 97 | exponent,
|
---|
| 98 | mantissaHighBitIdx,
|
---|
| 99 | hasUnequalMargins,
|
---|
| 100 | CutoffMode_Unique,
|
---|
| 101 | 0,
|
---|
| 102 | pOutBuffer,
|
---|
| 103 | maxPrintLen,
|
---|
| 104 | &printExponent );
|
---|
| 105 | }
|
---|
| 106 | else
|
---|
| 107 | {
|
---|
| 108 | numPrintDigits = Dragon4( mantissa,
|
---|
| 109 | exponent,
|
---|
| 110 | mantissaHighBitIdx,
|
---|
| 111 | hasUnequalMargins,
|
---|
| 112 | CutoffMode_FractionLength,
|
---|
| 113 | precision,
|
---|
| 114 | pOutBuffer,
|
---|
| 115 | maxPrintLen,
|
---|
| 116 | &printExponent );
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | RJ_ASSERT( numPrintDigits > 0 );
|
---|
| 120 | RJ_ASSERT( numPrintDigits <= bufferSize );
|
---|
| 121 |
|
---|
| 122 | // track the number of digits past the decimal point that have been printed
|
---|
| 123 | tU32 numFractionDigits = 0;
|
---|
| 124 |
|
---|
| 125 | // if output has a whole number
|
---|
| 126 | if (printExponent >= 0)
|
---|
| 127 | {
|
---|
| 128 | // leave the whole number at the start of the buffer
|
---|
| 129 | tU32 numWholeDigits = printExponent+1;
|
---|
| 130 | if (numPrintDigits < numWholeDigits)
|
---|
| 131 | {
|
---|
| 132 | // don't overflow the buffer
|
---|
| 133 | if (numWholeDigits > maxPrintLen)
|
---|
| 134 | numWholeDigits = maxPrintLen;
|
---|
| 135 |
|
---|
| 136 | // add trailing zeros up to the decimal point
|
---|
| 137 | for ( ; numPrintDigits < numWholeDigits; ++numPrintDigits )
|
---|
| 138 | pOutBuffer[numPrintDigits] = '0';
|
---|
| 139 | }
|
---|
| 140 | // insert the decimal point prior to the fraction
|
---|
| 141 | else if (numPrintDigits > (tU32)numWholeDigits)
|
---|
| 142 | {
|
---|
| 143 | numFractionDigits = numPrintDigits - numWholeDigits;
|
---|
| 144 | tU32 maxFractionDigits = maxPrintLen - numWholeDigits - 1;
|
---|
| 145 | if (numFractionDigits > maxFractionDigits)
|
---|
| 146 | numFractionDigits = maxFractionDigits;
|
---|
| 147 |
|
---|
| 148 | memmove(pOutBuffer + numWholeDigits + 1, pOutBuffer + numWholeDigits, numFractionDigits);
|
---|
| 149 | pOutBuffer[numWholeDigits] = '.';
|
---|
| 150 | numPrintDigits = numWholeDigits + 1 + numFractionDigits;
|
---|
| 151 | }
|
---|
| 152 | }
|
---|
| 153 | else
|
---|
| 154 | {
|
---|
| 155 | // shift out the fraction to make room for the leading zeros
|
---|
| 156 | if (maxPrintLen > 2)
|
---|
| 157 | {
|
---|
| 158 | tU32 numFractionZeros = (tU32)-printExponent - 1;
|
---|
| 159 | tU32 maxFractionZeros = maxPrintLen - 2;
|
---|
| 160 | if (numFractionZeros > maxFractionZeros)
|
---|
| 161 | numFractionZeros = maxFractionZeros;
|
---|
| 162 |
|
---|
| 163 | tU32 digitsStartIdx = 2 + numFractionZeros;
|
---|
| 164 |
|
---|
| 165 | // shift the significant digits right such that there is room for leading zeros
|
---|
| 166 | numFractionDigits = numPrintDigits;
|
---|
| 167 | tU32 maxFractionDigits = maxPrintLen - digitsStartIdx;
|
---|
| 168 | if (numFractionDigits > maxFractionDigits)
|
---|
| 169 | numFractionDigits = maxFractionDigits;
|
---|
| 170 |
|
---|
| 171 | memmove(pOutBuffer + digitsStartIdx, pOutBuffer, numFractionDigits);
|
---|
| 172 |
|
---|
| 173 | // insert the leading zeros
|
---|
| 174 | for (tU32 i = 2; i < digitsStartIdx; ++i)
|
---|
| 175 | pOutBuffer[i] = '0';
|
---|
| 176 |
|
---|
| 177 | // update the counts
|
---|
| 178 | numFractionDigits += numFractionZeros;
|
---|
| 179 | numPrintDigits = numFractionDigits;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | // add the decimal point
|
---|
| 183 | if (maxPrintLen > 1)
|
---|
| 184 | {
|
---|
| 185 | pOutBuffer[1] = '.';
|
---|
| 186 | numPrintDigits += 1;
|
---|
| 187 | }
|
---|
| 188 |
|
---|
| 189 | // add the initial zero
|
---|
| 190 | if (maxPrintLen > 0)
|
---|
| 191 | {
|
---|
| 192 | pOutBuffer[0] = '0';
|
---|
| 193 | numPrintDigits += 1;
|
---|
| 194 | }
|
---|
| 195 | }
|
---|
| 196 |
|
---|
| 197 | // add trailing zeros up to precision length
|
---|
| 198 | if (precision > (tS32)numFractionDigits && numPrintDigits < maxPrintLen)
|
---|
| 199 | {
|
---|
| 200 | // add a decimal point if this is the first fractional digit we are printing
|
---|
| 201 | if (numFractionDigits == 0)
|
---|
| 202 | {
|
---|
| 203 | pOutBuffer[numPrintDigits++] = '.';
|
---|
| 204 | }
|
---|
| 205 |
|
---|
| 206 | // compute the number of trailing zeros needed
|
---|
| 207 | tU32 totalDigits = numPrintDigits + (precision - numFractionDigits);
|
---|
| 208 | if (totalDigits > maxPrintLen)
|
---|
| 209 | totalDigits = maxPrintLen;
|
---|
| 210 |
|
---|
| 211 | for ( ; numPrintDigits < totalDigits; ++numPrintDigits )
|
---|
| 212 | pOutBuffer[numPrintDigits] = '0';
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | // terminate the buffer
|
---|
| 216 | RJ_ASSERT( numPrintDigits <= maxPrintLen );
|
---|
| 217 | pOutBuffer[numPrintDigits] = '\0';
|
---|
| 218 |
|
---|
| 219 | return numPrintDigits;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | //******************************************************************************
|
---|
| 223 | // Outputs the positive number with scientific notation: d.dddde[sign]ddd
|
---|
| 224 | // The output is always NUL terminated and the output length (not including the
|
---|
| 225 | // NUL) is returned.
|
---|
| 226 | //******************************************************************************
|
---|
| 227 | tU32 FormatScientific
|
---|
| 228 | (
|
---|
| 229 | tC8 * pOutBuffer, // buffer to output into
|
---|
| 230 | tU32 bufferSize, // maximum characters that can be printed to pOutBuffer
|
---|
| 231 | tU64 mantissa, // value significand
|
---|
| 232 | tS32 exponent, // value exponent in base 2
|
---|
| 233 | tU32 mantissaHighBitIdx, // index of the highest set mantissa bit
|
---|
| 234 | tB hasUnequalMargins, // is the high margin twice as large as the low margin
|
---|
| 235 | tS32 precision // Negative prints as many digits as are needed for a unique
|
---|
| 236 | // number. Positive specifies the maximum number of
|
---|
| 237 | // significant digits to print past the decimal point.
|
---|
| 238 | )
|
---|
| 239 | {
|
---|
| 240 | RJ_ASSERT(bufferSize > 0);
|
---|
| 241 |
|
---|
| 242 | tS32 printExponent;
|
---|
| 243 | tU32 numPrintDigits;
|
---|
| 244 |
|
---|
| 245 | if (precision < 0)
|
---|
| 246 | {
|
---|
| 247 | numPrintDigits = Dragon4( mantissa,
|
---|
| 248 | exponent,
|
---|
| 249 | mantissaHighBitIdx,
|
---|
| 250 | hasUnequalMargins,
|
---|
| 251 | CutoffMode_Unique,
|
---|
| 252 | 0,
|
---|
| 253 | pOutBuffer,
|
---|
| 254 | bufferSize,
|
---|
| 255 | &printExponent );
|
---|
| 256 | }
|
---|
| 257 | else
|
---|
| 258 | {
|
---|
| 259 | numPrintDigits = Dragon4( mantissa,
|
---|
| 260 | exponent,
|
---|
| 261 | mantissaHighBitIdx,
|
---|
| 262 | hasUnequalMargins,
|
---|
| 263 | CutoffMode_TotalLength,
|
---|
| 264 | precision + 1,
|
---|
| 265 | pOutBuffer,
|
---|
| 266 | bufferSize,
|
---|
| 267 | &printExponent );
|
---|
| 268 | }
|
---|
| 269 |
|
---|
| 270 | RJ_ASSERT( numPrintDigits > 0 );
|
---|
| 271 | RJ_ASSERT( numPrintDigits <= bufferSize );
|
---|
| 272 |
|
---|
| 273 | tC8 * pCurOut = pOutBuffer;
|
---|
| 274 |
|
---|
| 275 | // keep the whole number as the first digit
|
---|
| 276 | if (bufferSize > 1)
|
---|
| 277 | {
|
---|
| 278 | pCurOut += 1;
|
---|
| 279 | bufferSize -= 1;
|
---|
| 280 | }
|
---|
| 281 |
|
---|
| 282 | // insert the decimal point prior to the fractional number
|
---|
| 283 | tU32 numFractionDigits = numPrintDigits-1;
|
---|
| 284 | if (numFractionDigits > 0 && bufferSize > 1)
|
---|
| 285 | {
|
---|
| 286 | tU32 maxFractionDigits = bufferSize-2;
|
---|
| 287 | if (numFractionDigits > maxFractionDigits)
|
---|
| 288 | numFractionDigits = maxFractionDigits;
|
---|
| 289 |
|
---|
| 290 | memmove(pCurOut + 1, pCurOut, numFractionDigits);
|
---|
| 291 | pCurOut[0] = '.';
|
---|
| 292 | pCurOut += (1 + numFractionDigits);
|
---|
| 293 | bufferSize -= (1 + numFractionDigits);
|
---|
| 294 | }
|
---|
| 295 |
|
---|
| 296 | // add trailing zeros up to precision length
|
---|
| 297 | if (precision > (tS32)numFractionDigits && bufferSize > 1)
|
---|
| 298 | {
|
---|
| 299 | // add a decimal point if this is the first fractional digit we are printing
|
---|
| 300 | if (numFractionDigits == 0)
|
---|
| 301 | {
|
---|
| 302 | *pCurOut = '.';
|
---|
| 303 | ++pCurOut;
|
---|
| 304 | --bufferSize;
|
---|
| 305 | }
|
---|
| 306 |
|
---|
| 307 | // compute the number of trailing zeros needed
|
---|
| 308 | tU32 numZeros = (precision - numFractionDigits);
|
---|
| 309 | if (numZeros > bufferSize-1)
|
---|
| 310 | numZeros = bufferSize-1;
|
---|
| 311 |
|
---|
| 312 | for (tC8 * pEnd = pCurOut + numZeros; pCurOut < pEnd; ++pCurOut )
|
---|
| 313 | *pCurOut = '0';
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | // print the exponent into a local buffer and copy into output buffer
|
---|
| 317 | if (bufferSize > 1)
|
---|
| 318 | {
|
---|
| 319 | tC8 exponentBuffer[5]; //we will need 3, 4 or 5 chars
|
---|
| 320 | exponentBuffer[0] = 'e';
|
---|
| 321 | if (printExponent >= 0)
|
---|
| 322 | {
|
---|
| 323 | exponentBuffer[1] = '+';
|
---|
| 324 | }
|
---|
| 325 | else
|
---|
| 326 | {
|
---|
| 327 | exponentBuffer[1] = '-';
|
---|
| 328 | printExponent = -printExponent;
|
---|
| 329 | }
|
---|
| 330 |
|
---|
| 331 | RJ_ASSERT(printExponent < 1000);
|
---|
| 332 | tU32 hundredsPlace = printExponent / 100;
|
---|
| 333 | tU32 tensPlace = (printExponent - hundredsPlace*100) / 10;
|
---|
| 334 | tU32 onesPlace = (printExponent - hundredsPlace*100 - tensPlace*10);
|
---|
| 335 |
|
---|
| 336 | // modified by macko: use 3 digits of exponent only if necessary (e+123), otherwise use two if necessary (e+45), otherwise use one (e+6)
|
---|
| 337 | unsigned int bufferIndex = 2;
|
---|
[833] | 338 | #ifndef PRINTFLOAT_DRAGON4_ALWAYS_3_DIGIT_EXPONENT
|
---|
[823] | 339 | if (hundredsPlace != 0) //3 digits needed
|
---|
[833] | 340 | #endif
|
---|
[823] | 341 | exponentBuffer[bufferIndex++] = (tC8)('0' + hundredsPlace);
|
---|
[833] | 342 | #ifndef PRINTFLOAT_DRAGON4_ALWAYS_3_DIGIT_EXPONENT
|
---|
[823] | 343 | if (hundredsPlace != 0 || tensPlace != 0) //2 digits needed
|
---|
[833] | 344 | #endif
|
---|
[823] | 345 | exponentBuffer[bufferIndex++] = (tC8)('0' + tensPlace);
|
---|
| 346 | exponentBuffer[bufferIndex++] = (tC8)('0' + onesPlace);
|
---|
| 347 | // now bufferIndex indicates how many characters of exponentBuffer were used
|
---|
| 348 |
|
---|
| 349 | // copy the exponent buffer into the output
|
---|
| 350 | tU32 maxExponentSize = bufferSize - 1;
|
---|
| 351 | tU32 exponentSize = (bufferIndex < maxExponentSize) ? bufferIndex : maxExponentSize;
|
---|
| 352 | memcpy( pCurOut, exponentBuffer, exponentSize );
|
---|
| 353 |
|
---|
| 354 | pCurOut += exponentSize;
|
---|
| 355 | bufferSize -= exponentSize;
|
---|
| 356 | }
|
---|
| 357 |
|
---|
| 358 | RJ_ASSERT( bufferSize > 0 );
|
---|
| 359 | pCurOut[0] = '\0';
|
---|
| 360 |
|
---|
| 361 | return pCurOut - pOutBuffer;
|
---|
| 362 | }
|
---|
| 363 |
|
---|
| 364 | //******************************************************************************
|
---|
| 365 | // Print a hexadecimal value with a given width.
|
---|
| 366 | // The output string is always NUL terminated and the string length (not
|
---|
| 367 | // including the NUL) is returned.
|
---|
| 368 | //******************************************************************************
|
---|
| 369 | static tU32 PrintHex(tC8 * pOutBuffer, tU32 bufferSize, tU64 value, tU32 width)
|
---|
| 370 | {
|
---|
| 371 | const tC8 digits[] = "0123456789abcdef";
|
---|
| 372 |
|
---|
| 373 | RJ_ASSERT(bufferSize > 0);
|
---|
| 374 |
|
---|
| 375 | tU32 maxPrintLen = bufferSize-1;
|
---|
| 376 | if (width > maxPrintLen)
|
---|
| 377 | width = maxPrintLen;
|
---|
| 378 |
|
---|
| 379 | tC8 * pCurOut = pOutBuffer;
|
---|
| 380 | while (width > 0)
|
---|
| 381 | {
|
---|
| 382 | --width;
|
---|
| 383 |
|
---|
| 384 | tU8 digit = (tU8)((value >> 4ull*(tU64)width) & 0xF);
|
---|
| 385 | *pCurOut = digits[digit];
|
---|
| 386 |
|
---|
| 387 | ++pCurOut;
|
---|
| 388 | }
|
---|
| 389 |
|
---|
| 390 | *pCurOut = '\0';
|
---|
| 391 | return pCurOut - pOutBuffer;
|
---|
| 392 | }
|
---|
| 393 |
|
---|
| 394 | //******************************************************************************
|
---|
| 395 | // Print special case values for infinities and NaNs.
|
---|
| 396 | // The output string is always NUL terminated and the string length (not
|
---|
| 397 | // including the NUL) is returned.
|
---|
| 398 | //******************************************************************************
|
---|
| 399 | static tU32 PrintInfNan(tC8 * pOutBuffer, tU32 bufferSize, tU64 mantissa, tU32 mantissaHexWidth)
|
---|
| 400 | {
|
---|
| 401 | RJ_ASSERT(bufferSize > 0);
|
---|
| 402 |
|
---|
| 403 | tU32 maxPrintLen = bufferSize-1;
|
---|
| 404 |
|
---|
| 405 | // Check for infinity
|
---|
| 406 | if (mantissa == 0)
|
---|
| 407 | {
|
---|
| 408 | // copy and make sure the buffer is terminated
|
---|
| 409 | tU32 printLen = (3 < maxPrintLen) ? 3 : maxPrintLen;
|
---|
| 410 | ::memcpy( pOutBuffer, "Inf", printLen );
|
---|
| 411 | pOutBuffer[printLen] = '\0';
|
---|
| 412 | return printLen;
|
---|
| 413 | }
|
---|
| 414 | else
|
---|
| 415 | {
|
---|
| 416 | // copy and make sure the buffer is terminated
|
---|
| 417 | tU32 printLen = (3 < maxPrintLen) ? 3 : maxPrintLen;
|
---|
| 418 | ::memcpy( pOutBuffer, "NaN", printLen );
|
---|
| 419 | pOutBuffer[printLen] = '\0';
|
---|
| 420 |
|
---|
| 421 | // append HEX value
|
---|
| 422 | if (maxPrintLen > 3)
|
---|
| 423 | printLen += PrintHex(pOutBuffer+3, bufferSize-3, mantissa, mantissaHexWidth);
|
---|
| 424 |
|
---|
| 425 | return printLen;
|
---|
| 426 | }
|
---|
| 427 | }
|
---|
| 428 |
|
---|
| 429 | //******************************************************************************
|
---|
| 430 | // Print a 32-bit floating-point number as a decimal string.
|
---|
| 431 | // The output string is always NUL terminated and the string length (not
|
---|
| 432 | // including the NUL) is returned.
|
---|
| 433 | //******************************************************************************
|
---|
| 434 | tU32 PrintFloat32
|
---|
| 435 | (
|
---|
| 436 | tC8 * pOutBuffer, // buffer to output into
|
---|
| 437 | tU32 bufferSize, // size of pOutBuffer
|
---|
| 438 | tF32 value, // value to print
|
---|
| 439 | tPrintFloatFormat format, // format to print with
|
---|
| 440 | tS32 precision // If negative, the minimum number of digits to represent a
|
---|
| 441 | // unique 32-bit floating point value is output. Otherwise,
|
---|
| 442 | // this is the number of digits to print past the decimal point.
|
---|
| 443 | )
|
---|
| 444 | {
|
---|
| 445 | if (bufferSize == 0)
|
---|
| 446 | return 0;
|
---|
| 447 |
|
---|
| 448 | if (bufferSize == 1)
|
---|
| 449 | {
|
---|
| 450 | pOutBuffer[0] = '\0';
|
---|
| 451 | return 0;
|
---|
| 452 | }
|
---|
| 453 |
|
---|
| 454 | // deconstruct the floating point value
|
---|
| 455 | tFloatUnion32 floatUnion;
|
---|
| 456 | floatUnion.m_floatingPoint = value;
|
---|
| 457 | tU32 floatExponent = floatUnion.GetExponent();
|
---|
| 458 | tU32 floatMantissa = floatUnion.GetMantissa();
|
---|
| 459 | tU32 prefixLength = 0;
|
---|
| 460 |
|
---|
| 461 | // output the sign
|
---|
| 462 | if (floatUnion.IsNegative())
|
---|
| 463 | {
|
---|
| 464 | pOutBuffer[0] = '-';
|
---|
| 465 | ++pOutBuffer;
|
---|
| 466 | --bufferSize;
|
---|
| 467 | ++prefixLength;
|
---|
| 468 | RJ_ASSERT(bufferSize > 0);
|
---|
| 469 | }
|
---|
| 470 |
|
---|
| 471 | // if this is a special value
|
---|
| 472 | if (floatExponent == 0xFF)
|
---|
| 473 | {
|
---|
| 474 | return PrintInfNan(pOutBuffer, bufferSize, floatMantissa, 6) + prefixLength;
|
---|
| 475 | }
|
---|
| 476 | // else this is a number
|
---|
| 477 | else
|
---|
| 478 | {
|
---|
| 479 | // factor the value into its parts
|
---|
| 480 | tU32 mantissa;
|
---|
| 481 | tS32 exponent;
|
---|
| 482 | tU32 mantissaHighBitIdx;
|
---|
| 483 | tB hasUnequalMargins;
|
---|
| 484 | if (floatExponent != 0)
|
---|
| 485 | {
|
---|
| 486 | // normalized
|
---|
| 487 | // The floating point equation is:
|
---|
| 488 | // value = (1 + mantissa/2^23) * 2 ^ (exponent-127)
|
---|
| 489 | // We convert the integer equation by factoring a 2^23 out of the exponent
|
---|
| 490 | // value = (1 + mantissa/2^23) * 2^23 * 2 ^ (exponent-127-23)
|
---|
| 491 | // value = (2^23 + mantissa) * 2 ^ (exponent-127-23)
|
---|
| 492 | // Because of the implied 1 in front of the mantissa we have 24 bits of precision.
|
---|
| 493 | // m = (2^23 + mantissa)
|
---|
| 494 | // e = (exponent-127-23)
|
---|
| 495 | mantissa = (1UL << 23) | floatMantissa;
|
---|
| 496 | exponent = floatExponent - 127 - 23;
|
---|
| 497 | mantissaHighBitIdx = 23;
|
---|
| 498 | hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
|
---|
| 499 | }
|
---|
| 500 | else
|
---|
| 501 | {
|
---|
| 502 | // denormalized
|
---|
| 503 | // The floating point equation is:
|
---|
| 504 | // value = (mantissa/2^23) * 2 ^ (1-127)
|
---|
| 505 | // We convert the integer equation by factoring a 2^23 out of the exponent
|
---|
| 506 | // value = (mantissa/2^23) * 2^23 * 2 ^ (1-127-23)
|
---|
| 507 | // value = mantissa * 2 ^ (1-127-23)
|
---|
| 508 | // We have up to 23 bits of precision.
|
---|
| 509 | // m = (mantissa)
|
---|
| 510 | // e = (1-127-23)
|
---|
| 511 | mantissa = floatMantissa;
|
---|
| 512 | exponent = 1 - 127 - 23;
|
---|
| 513 | mantissaHighBitIdx = LogBase2(mantissa);
|
---|
| 514 | hasUnequalMargins = false;
|
---|
| 515 | }
|
---|
| 516 |
|
---|
| 517 | // format the value
|
---|
| 518 | switch (format)
|
---|
| 519 | {
|
---|
| 520 | case PrintFloatFormat_Positional:
|
---|
| 521 | return FormatPositional( pOutBuffer,
|
---|
| 522 | bufferSize,
|
---|
| 523 | mantissa,
|
---|
| 524 | exponent,
|
---|
| 525 | mantissaHighBitIdx,
|
---|
| 526 | hasUnequalMargins,
|
---|
| 527 | precision ) + prefixLength;
|
---|
| 528 |
|
---|
| 529 | case PrintFloatFormat_Scientific:
|
---|
| 530 | return FormatScientific( pOutBuffer,
|
---|
| 531 | bufferSize,
|
---|
| 532 | mantissa,
|
---|
| 533 | exponent,
|
---|
| 534 | mantissaHighBitIdx,
|
---|
| 535 | hasUnequalMargins,
|
---|
| 536 | precision ) + prefixLength;
|
---|
| 537 |
|
---|
| 538 | default:
|
---|
| 539 | pOutBuffer[0] = '\0';
|
---|
| 540 | return 0;
|
---|
| 541 | }
|
---|
| 542 | }
|
---|
| 543 | }
|
---|
| 544 |
|
---|
| 545 | //******************************************************************************
|
---|
| 546 | // Print a 64-bit floating-point number as a decimal string.
|
---|
| 547 | // The output string is always NUL terminated and the string length (not
|
---|
| 548 | // including the NUL) is returned.
|
---|
| 549 | //******************************************************************************
|
---|
| 550 | tU32 PrintFloat64
|
---|
| 551 | (
|
---|
| 552 | tC8 * pOutBuffer, // buffer to output into
|
---|
| 553 | tU32 bufferSize, // size of pOutBuffer
|
---|
| 554 | tF64 value, // value to print
|
---|
| 555 | tPrintFloatFormat format, // format to print with
|
---|
| 556 | tS32 precision // If negative, the minimum number of digits to represent a
|
---|
| 557 | // unique 64-bit floating point value is output. Otherwise,
|
---|
| 558 | // this is the number of digits to print past the decimal point.
|
---|
| 559 | )
|
---|
| 560 | {
|
---|
| 561 | if (bufferSize == 0)
|
---|
| 562 | return 0;
|
---|
| 563 |
|
---|
| 564 | if (bufferSize == 1)
|
---|
| 565 | {
|
---|
| 566 | pOutBuffer[0] = '\0';
|
---|
| 567 | return 0;
|
---|
| 568 | }
|
---|
| 569 |
|
---|
| 570 | // deconstruct the floating point value
|
---|
| 571 | tFloatUnion64 floatUnion;
|
---|
| 572 | floatUnion.m_floatingPoint = value;
|
---|
| 573 | tU32 floatExponent = floatUnion.GetExponent();
|
---|
| 574 | tU64 floatMantissa = floatUnion.GetMantissa();
|
---|
| 575 | tU32 prefixLength = 0;
|
---|
| 576 |
|
---|
| 577 | // output the sign
|
---|
| 578 | if (floatUnion.IsNegative())
|
---|
| 579 | {
|
---|
| 580 | pOutBuffer[0] = '-';
|
---|
| 581 | ++pOutBuffer;
|
---|
| 582 | --bufferSize;
|
---|
| 583 | ++prefixLength;
|
---|
| 584 | RJ_ASSERT(bufferSize > 0);
|
---|
| 585 | }
|
---|
| 586 |
|
---|
| 587 | // if this is a special value
|
---|
| 588 | if (floatExponent == 0x7FF)
|
---|
| 589 | {
|
---|
| 590 | return PrintInfNan(pOutBuffer, bufferSize, floatMantissa, 13) + prefixLength;
|
---|
| 591 | }
|
---|
| 592 | // else this is a number
|
---|
| 593 | else
|
---|
| 594 | {
|
---|
| 595 | // factor the value into its parts
|
---|
| 596 | tU64 mantissa;
|
---|
| 597 | tS32 exponent;
|
---|
| 598 | tU32 mantissaHighBitIdx;
|
---|
| 599 | tB hasUnequalMargins;
|
---|
| 600 |
|
---|
| 601 | if (floatExponent != 0)
|
---|
| 602 | {
|
---|
| 603 | // normal
|
---|
| 604 | // The floating point equation is:
|
---|
| 605 | // value = (1 + mantissa/2^52) * 2 ^ (exponent-1023)
|
---|
| 606 | // We convert the integer equation by factoring a 2^52 out of the exponent
|
---|
| 607 | // value = (1 + mantissa/2^52) * 2^52 * 2 ^ (exponent-1023-52)
|
---|
| 608 | // value = (2^52 + mantissa) * 2 ^ (exponent-1023-52)
|
---|
| 609 | // Because of the implied 1 in front of the mantissa we have 53 bits of precision.
|
---|
| 610 | // m = (2^52 + mantissa)
|
---|
| 611 | // e = (exponent-1023+1-53)
|
---|
| 612 | mantissa = (1ull << 52) | floatMantissa;
|
---|
| 613 | exponent = floatExponent - 1023 - 52;
|
---|
| 614 | mantissaHighBitIdx = 52;
|
---|
| 615 | hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
|
---|
| 616 | }
|
---|
| 617 | else
|
---|
| 618 | {
|
---|
| 619 | // subnormal
|
---|
| 620 | // The floating point equation is:
|
---|
| 621 | // value = (mantissa/2^52) * 2 ^ (1-1023)
|
---|
| 622 | // We convert the integer equation by factoring a 2^52 out of the exponent
|
---|
| 623 | // value = (mantissa/2^52) * 2^52 * 2 ^ (1-1023-52)
|
---|
| 624 | // value = mantissa * 2 ^ (1-1023-52)
|
---|
| 625 | // We have up to 52 bits of precision.
|
---|
| 626 | // m = (mantissa)
|
---|
| 627 | // e = (1-1023-52)
|
---|
| 628 | mantissa = floatMantissa;
|
---|
| 629 | exponent = 1 - 1023 - 52;
|
---|
| 630 | mantissaHighBitIdx = LogBase2(mantissa);
|
---|
| 631 | hasUnequalMargins = false;
|
---|
| 632 | }
|
---|
| 633 |
|
---|
| 634 | // format the value
|
---|
| 635 | switch (format)
|
---|
| 636 | {
|
---|
| 637 | case PrintFloatFormat_Positional:
|
---|
| 638 | return FormatPositional( pOutBuffer,
|
---|
| 639 | bufferSize,
|
---|
| 640 | mantissa,
|
---|
| 641 | exponent,
|
---|
| 642 | mantissaHighBitIdx,
|
---|
| 643 | hasUnequalMargins,
|
---|
| 644 | precision ) + prefixLength;
|
---|
| 645 |
|
---|
| 646 | case PrintFloatFormat_Scientific:
|
---|
| 647 | return FormatScientific( pOutBuffer,
|
---|
| 648 | bufferSize,
|
---|
| 649 | mantissa,
|
---|
| 650 | exponent,
|
---|
| 651 | mantissaHighBitIdx,
|
---|
| 652 | hasUnequalMargins,
|
---|
| 653 | precision ) + prefixLength;
|
---|
| 654 |
|
---|
| 655 | default:
|
---|
| 656 | pOutBuffer[0] = '\0';
|
---|
| 657 | return 0;
|
---|
| 658 | }
|
---|
| 659 | }
|
---|
| 660 | }
|
---|