1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | #include "clib.h" |
54 | #include "dmath.h" |
55 | #include "dprint.h" |
56 | #include "dragon4.h" |
57 | #include <dstandard.h> |
58 | |
59 | #define memcpyMemCopy MemCopy |
60 | #define memmoveMemCopy MemCopy |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | union tFloatUnion32 |
69 | { |
70 | tB IsNegative() const { |
71 | return (m_integer >> 31) != 0; |
72 | } |
73 | tU32 GetExponent() const { |
74 | return (m_integer >> 23) & 0xFF; |
75 | } |
76 | tU32 GetMantissa() const { |
77 | return m_integer & 0x7FFFFF; |
78 | } |
79 | |
80 | tF32 m_floatingPoint; |
81 | tU32 m_integer; |
82 | }; |
83 | |
84 | |
85 | |
86 | |
87 | |
88 | |
89 | |
90 | union tFloatUnion64 |
91 | { |
92 | tB IsNegative() const { |
93 | return (m_integer >> 63) != 0; |
94 | } |
95 | tU32 GetExponent() const { |
96 | return (m_integer >> 52) & 0x7FF; |
97 | } |
98 | tU64 GetMantissa() const { |
99 | return m_integer & 0xFFFFFFFFFFFFFull; |
100 | } |
101 | |
102 | tF64 m_floatingPoint; |
103 | tU64 m_integer; |
104 | }; |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | tU32 FormatPositional |
112 | ( |
113 | tC8 * pOutBuffer, |
114 | tU32 bufferSize, |
115 | tU64 mantissa, |
116 | tS32 exponent, |
117 | tU32 mantissaHighBitIdx, |
118 | tB hasUnequalMargins, |
119 | tS32 precision, |
120 | tC8 decimalPoint |
121 | |
122 | |
123 | ) |
124 | { |
125 | RJ_ASSERT(bufferSize > 0); |
126 | |
127 | tS32 printExponent; |
128 | tU32 numPrintDigits; |
129 | |
130 | tU32 maxPrintLen = bufferSize - 1; |
131 | |
132 | if (precision < 0) |
133 | { |
134 | numPrintDigits = Dragon4( mantissa, |
135 | exponent, |
136 | mantissaHighBitIdx, |
137 | hasUnequalMargins, |
138 | CutoffMode_Unique, |
139 | 0, |
140 | pOutBuffer, |
141 | maxPrintLen, |
142 | &printExponent ); |
143 | } |
144 | else |
145 | { |
146 | numPrintDigits = Dragon4( mantissa, |
147 | exponent, |
148 | mantissaHighBitIdx, |
149 | hasUnequalMargins, |
150 | CutoffMode_FractionLength, |
151 | precision, |
152 | pOutBuffer, |
153 | maxPrintLen, |
154 | &printExponent ); |
155 | } |
156 | |
157 | RJ_ASSERT( numPrintDigits > 0 ); |
158 | RJ_ASSERT( numPrintDigits <= bufferSize ); |
159 | |
160 | |
161 | tU32 numFractionDigits = 0; |
162 | |
163 | |
164 | if (printExponent >= 0) |
165 | { |
166 | |
167 | tU32 numWholeDigits = printExponent+1; |
168 | if (numPrintDigits < numWholeDigits) |
169 | { |
170 | |
171 | if (numWholeDigits > maxPrintLen) |
172 | numWholeDigits = maxPrintLen; |
173 | |
174 | |
175 | for ( ; numPrintDigits < numWholeDigits; ++numPrintDigits ) |
176 | pOutBuffer[numPrintDigits] = '0'; |
177 | } |
178 | |
179 | else if (numPrintDigits > (tU32)numWholeDigits) |
180 | { |
181 | numFractionDigits = numPrintDigits - numWholeDigits; |
182 | tU32 maxFractionDigits = maxPrintLen - numWholeDigits - 1; |
183 | if (numFractionDigits > maxFractionDigits) |
184 | numFractionDigits = maxFractionDigits; |
185 | |
186 | memmoveMemCopy(pOutBuffer + numWholeDigits + 1, pOutBuffer + numWholeDigits, numFractionDigits); |
187 | pOutBuffer[numWholeDigits] = decimalPoint; |
188 | numPrintDigits = numWholeDigits + 1 + numFractionDigits; |
189 | } |
190 | } |
191 | else |
192 | { |
193 | |
194 | if (maxPrintLen > 2) |
195 | { |
196 | tU32 numFractionZeros = (tU32)-printExponent - 1; |
197 | tU32 maxFractionZeros = maxPrintLen - 2; |
198 | if (numFractionZeros > maxFractionZeros) |
199 | numFractionZeros = maxFractionZeros; |
200 | |
201 | tU32 digitsStartIdx = 2 + numFractionZeros; |
202 | |
203 | |
204 | numFractionDigits = numPrintDigits; |
205 | tU32 maxFractionDigits = maxPrintLen - digitsStartIdx; |
206 | if (numFractionDigits > maxFractionDigits) |
207 | numFractionDigits = maxFractionDigits; |
208 | |
209 | memmoveMemCopy(pOutBuffer + digitsStartIdx, pOutBuffer, numFractionDigits); |
210 | |
211 | |
212 | for (tU32 i = 2; i < digitsStartIdx; ++i) |
213 | pOutBuffer[i] = '0'; |
214 | |
215 | |
216 | numFractionDigits += numFractionZeros; |
217 | numPrintDigits = numFractionDigits; |
218 | } |
219 | |
220 | |
221 | if (maxPrintLen > 1) |
222 | { |
223 | pOutBuffer[1] = decimalPoint; |
224 | numPrintDigits += 1; |
225 | } |
226 | |
227 | |
228 | if (maxPrintLen > 0) |
229 | { |
230 | pOutBuffer[0] = '0'; |
231 | numPrintDigits += 1; |
232 | } |
233 | } |
234 | |
235 | |
236 | if (precision > (tS32)numFractionDigits && numPrintDigits < maxPrintLen) |
237 | { |
238 | |
239 | if (numFractionDigits == 0) |
240 | { |
241 | pOutBuffer[numPrintDigits++] = decimalPoint; |
242 | } |
243 | |
244 | |
245 | tU32 totalDigits = numPrintDigits + (precision - numFractionDigits); |
246 | if (totalDigits > maxPrintLen) |
247 | totalDigits = maxPrintLen; |
248 | |
249 | for ( ; numPrintDigits < totalDigits; ++numPrintDigits ) |
250 | pOutBuffer[numPrintDigits] = '0'; |
251 | } |
252 | |
253 | |
254 | RJ_ASSERT( numPrintDigits <= maxPrintLen ); |
255 | pOutBuffer[numPrintDigits] = '\0'; |
256 | |
257 | return numPrintDigits; |
258 | } |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | tU32 FormatScientific |
266 | ( |
267 | tC8 * pOutBuffer, |
268 | tU32 bufferSize, |
269 | tU64 mantissa, |
270 | tS32 exponent, |
271 | tU32 mantissaHighBitIdx, |
272 | tB hasUnequalMargins, |
273 | tS32 precision, |
274 | tC8 decimalPoint |
275 | |
276 | |
277 | ) |
278 | { |
279 | RJ_ASSERT(bufferSize > 0); |
280 | |
281 | tS32 printExponent; |
282 | tU32 numPrintDigits; |
283 | |
284 | if (precision < 0) |
285 | { |
286 | numPrintDigits = Dragon4( mantissa, |
287 | exponent, |
288 | mantissaHighBitIdx, |
289 | hasUnequalMargins, |
290 | CutoffMode_Unique, |
291 | 0, |
292 | pOutBuffer, |
293 | bufferSize, |
294 | &printExponent ); |
295 | } |
296 | else |
297 | { |
298 | numPrintDigits = Dragon4( mantissa, |
299 | exponent, |
300 | mantissaHighBitIdx, |
301 | hasUnequalMargins, |
302 | CutoffMode_TotalLength, |
303 | precision + 1, |
304 | pOutBuffer, |
305 | bufferSize, |
306 | &printExponent ); |
307 | } |
308 | |
309 | RJ_ASSERT( numPrintDigits > 0 ); |
310 | RJ_ASSERT( numPrintDigits <= bufferSize ); |
311 | |
312 | tC8 * pCurOut = pOutBuffer; |
313 | |
314 | |
315 | if (bufferSize > 1) |
316 | { |
317 | pCurOut += 1; |
318 | bufferSize -= 1; |
319 | } |
320 | |
321 | |
322 | tU32 numFractionDigits = numPrintDigits-1; |
323 | if (numFractionDigits > 0 && bufferSize > 1) |
324 | { |
325 | tU32 maxFractionDigits = bufferSize-2; |
326 | if (numFractionDigits > maxFractionDigits) |
327 | numFractionDigits = maxFractionDigits; |
328 | |
329 | memmoveMemCopy(pCurOut + 1, pCurOut, numFractionDigits); |
330 | pCurOut[0] = decimalPoint; |
331 | pCurOut += (1 + numFractionDigits); |
332 | bufferSize -= (1 + numFractionDigits); |
333 | } |
334 | |
335 | |
336 | if (precision > (tS32)numFractionDigits && bufferSize > 1) |
337 | { |
338 | |
339 | if (numFractionDigits == 0) |
340 | { |
341 | *pCurOut = decimalPoint; |
342 | ++pCurOut; |
343 | --bufferSize; |
344 | } |
345 | |
346 | |
347 | tU32 numZeros = (precision - numFractionDigits); |
348 | if (numZeros > bufferSize-1) |
349 | numZeros = bufferSize-1; |
350 | |
351 | for (tC8 * pEnd = pCurOut + numZeros; pCurOut < pEnd; ++pCurOut ) |
352 | *pCurOut = '0'; |
353 | } |
354 | |
355 | |
356 | if (bufferSize > 1) |
357 | { |
358 | tC8 exponentBuffer[5]; |
359 | exponentBuffer[0] = 'e'; |
360 | if (printExponent >= 0) |
361 | { |
362 | exponentBuffer[1] = '+'; |
363 | } |
364 | else |
365 | { |
366 | exponentBuffer[1] = '-'; |
367 | printExponent = -printExponent; |
368 | } |
369 | |
370 | RJ_ASSERT(printExponent < 1000); |
371 | tU32 hundredsPlace = printExponent / 100; |
372 | tU32 tensPlace = (printExponent - hundredsPlace*100) / 10; |
373 | tU32 onesPlace = (printExponent - hundredsPlace*100 - tensPlace*10); |
374 | |
375 | exponentBuffer[2] = (tC8)('0' + hundredsPlace); |
376 | exponentBuffer[3] = (tC8)('0' + tensPlace); |
377 | exponentBuffer[4] = (tC8)('0' + onesPlace); |
378 | |
379 | |
380 | tU32 maxExponentSize = bufferSize-1; |
381 | tU32 exponentSize = (5 < maxExponentSize) ? 5 : maxExponentSize; |
382 | memcpyMemCopy( pCurOut, exponentBuffer, exponentSize ); |
383 | |
384 | pCurOut += exponentSize; |
385 | bufferSize -= exponentSize; |
| Value stored to 'bufferSize' is never read |
386 | } |
387 | |
388 | RJ_ASSERT( bufferSize > 0 ); |
389 | pCurOut[0] = '\0'; |
390 | |
391 | return pCurOut - pOutBuffer; |
392 | } |
393 | |
394 | |
395 | |
396 | |
397 | |
398 | |
399 | static tU32 PrintHex(tC8 * pOutBuffer, tU32 bufferSize, tU64 value, tU32 width) |
400 | { |
401 | const tC8 digits[] = "0123456789abcdef"; |
402 | |
403 | RJ_ASSERT(bufferSize > 0); |
404 | |
405 | tU32 maxPrintLen = bufferSize-1; |
406 | if (width > maxPrintLen) |
407 | width = maxPrintLen; |
408 | |
409 | tC8 * pCurOut = pOutBuffer; |
410 | while (width > 0) |
411 | { |
412 | --width; |
413 | |
414 | tU8 digit = (tU8)((value >> 4ull*(tU64)width) & 0xF); |
415 | *pCurOut = digits[digit]; |
416 | |
417 | ++pCurOut; |
418 | } |
419 | |
420 | *pCurOut = '\0'; |
421 | return pCurOut - pOutBuffer; |
422 | } |
423 | |
424 | |
425 | |
426 | |
427 | |
428 | |
429 | static tU32 PrintInfNan(tC8 * pOutBuffer, tU32 bufferSize, tU64 mantissa, tU32 mantissaHexWidth) |
430 | { |
431 | RJ_ASSERT(bufferSize > 0); |
432 | |
433 | tU32 maxPrintLen = bufferSize-1; |
434 | |
435 | |
436 | if (mantissa == 0) |
437 | { |
438 | |
439 | tU32 printLen = (3 < maxPrintLen) ? 3 : maxPrintLen; |
440 | ::memcpyMemCopy( pOutBuffer, "Inf", printLen ); |
441 | pOutBuffer[printLen] = '\0'; |
442 | return printLen; |
443 | } |
444 | else |
445 | { |
446 | |
447 | tU32 printLen = (3 < maxPrintLen) ? 3 : maxPrintLen; |
448 | ::memcpyMemCopy( pOutBuffer, "NaN", printLen ); |
449 | pOutBuffer[printLen] = '\0'; |
450 | |
451 | |
452 | if (maxPrintLen > 3) |
453 | printLen += PrintHex(pOutBuffer+3, bufferSize-3, mantissa, mantissaHexWidth); |
454 | |
455 | return printLen; |
456 | } |
457 | } |
458 | |
459 | |
460 | |
461 | |
462 | |
463 | |
464 | tU32 PrintFloat32 |
465 | ( |
466 | tC8 * pOutBuffer, |
467 | tU32 bufferSize, |
468 | tF32 value, |
469 | tPrintFloatFormat format, |
470 | tS32 precision, |
471 | tC8 decimalPoint |
472 | |
473 | |
474 | ) |
475 | { |
476 | if (bufferSize == 0) |
477 | return 0; |
478 | |
479 | if (bufferSize == 1) |
480 | { |
481 | pOutBuffer[0] = '\0'; |
482 | return 1; |
483 | } |
484 | |
485 | |
486 | tFloatUnion32 floatUnion; |
487 | floatUnion.m_floatingPoint = value; |
488 | tU32 floatExponent = floatUnion.GetExponent(); |
489 | tU32 floatMantissa = floatUnion.GetMantissa(); |
490 | |
491 | |
492 | if (floatUnion.IsNegative()) |
493 | { |
494 | pOutBuffer[0] = '-'; |
495 | ++pOutBuffer; |
496 | --bufferSize; |
497 | RJ_ASSERT(bufferSize > 0); |
498 | } |
499 | |
500 | |
501 | if (floatExponent == 0xFF) |
502 | { |
503 | return PrintInfNan(pOutBuffer, bufferSize, floatMantissa, 6); |
504 | } |
505 | |
506 | else |
507 | { |
508 | |
509 | tU32 mantissa; |
510 | tS32 exponent; |
511 | tU32 mantissaHighBitIdx; |
512 | tB hasUnequalMargins; |
513 | if (floatExponent != 0) |
514 | { |
515 | |
516 | |
517 | |
518 | |
519 | |
520 | |
521 | |
522 | |
523 | |
524 | mantissa = (1UL << 23) | floatMantissa; |
525 | exponent = floatExponent - 127 - 23; |
526 | mantissaHighBitIdx = 23; |
527 | hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); |
528 | } |
529 | else |
530 | { |
531 | |
532 | |
533 | |
534 | |
535 | |
536 | |
537 | |
538 | |
539 | |
540 | mantissa = floatMantissa; |
541 | exponent = 1 - 127 - 23; |
542 | mantissaHighBitIdx = LogBase2(mantissa); |
543 | hasUnequalMargins = false; |
544 | } |
545 | |
546 | |
547 | switch (format) |
548 | { |
549 | case PrintFloatFormat_Positional: |
550 | return FormatPositional( pOutBuffer, |
551 | bufferSize, |
552 | mantissa, |
553 | exponent, |
554 | mantissaHighBitIdx, |
555 | hasUnequalMargins, |
556 | precision, |
557 | decimalPoint ); |
558 | |
559 | case PrintFloatFormat_Scientific: |
560 | return FormatScientific( pOutBuffer, |
561 | bufferSize, |
562 | mantissa, |
563 | exponent, |
564 | mantissaHighBitIdx, |
565 | hasUnequalMargins, |
566 | precision, |
567 | decimalPoint ); |
568 | |
569 | default: |
570 | pOutBuffer[0] = '\0'; |
571 | return 0; |
572 | } |
573 | } |
574 | } |
575 | |
576 | |
577 | |
578 | |
579 | |
580 | |
581 | tU32 PrintFloat64 |
582 | ( |
583 | tC8 * pOutBuffer, |
584 | tU32 bufferSize, |
585 | tF64 value, |
586 | tPrintFloatFormat format, |
587 | tS32 precision, |
588 | tC8 decimalPoint |
589 | |
590 | |
591 | ) |
592 | { |
593 | if (bufferSize == 0) |
594 | return 0; |
595 | |
596 | if (bufferSize == 1) |
597 | { |
598 | pOutBuffer[0] = '\0'; |
599 | return 1; |
600 | } |
601 | |
602 | |
603 | tFloatUnion64 floatUnion; |
604 | floatUnion.m_floatingPoint = value; |
605 | tU32 floatExponent = floatUnion.GetExponent(); |
606 | tU64 floatMantissa = floatUnion.GetMantissa(); |
607 | |
608 | |
609 | if (floatUnion.IsNegative()) |
610 | { |
611 | pOutBuffer[0] = '-'; |
612 | ++pOutBuffer; |
613 | --bufferSize; |
614 | RJ_ASSERT(bufferSize > 0); |
615 | } |
616 | |
617 | |
618 | if (floatExponent == 0x7FF) |
619 | { |
620 | return PrintInfNan(pOutBuffer, bufferSize, floatMantissa, 13); |
621 | } |
622 | |
623 | else |
624 | { |
625 | |
626 | tU64 mantissa; |
627 | tS32 exponent; |
628 | tU32 mantissaHighBitIdx; |
629 | tB hasUnequalMargins; |
630 | |
631 | if (floatExponent != 0) |
632 | { |
633 | |
634 | |
635 | |
636 | |
637 | |
638 | |
639 | |
640 | |
641 | |
642 | mantissa = (1ull << 52) | floatMantissa; |
643 | exponent = floatExponent - 1023 - 52; |
644 | mantissaHighBitIdx = 52; |
645 | hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0); |
646 | } |
647 | else |
648 | { |
649 | |
650 | |
651 | |
652 | |
653 | |
654 | |
655 | |
656 | |
657 | |
658 | mantissa = floatMantissa; |
659 | exponent = 1 - 1023 - 52; |
660 | mantissaHighBitIdx = LogBase2(mantissa); |
661 | hasUnequalMargins = false; |
662 | } |
663 | |
664 | |
665 | switch (format) |
666 | { |
667 | case PrintFloatFormat_Positional: |
668 | return FormatPositional( pOutBuffer, |
669 | bufferSize, |
670 | mantissa, |
671 | exponent, |
672 | mantissaHighBitIdx, |
673 | hasUnequalMargins, |
674 | precision, |
675 | decimalPoint ); |
676 | |
677 | case PrintFloatFormat_Scientific: |
678 | return FormatScientific( pOutBuffer, |
679 | bufferSize, |
680 | mantissa, |
681 | exponent, |
682 | mantissaHighBitIdx, |
683 | hasUnequalMargins, |
684 | precision, |
685 | decimalPoint ); |
686 | |
687 | default: |
688 | pOutBuffer[0] = '\0'; |
689 | return 0; |
690 | } |
691 | } |
692 | } |