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