VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strformatfloat.cpp@ 94557

Last change on this file since 94557 was 94557, checked in by vboxsync, 3 years ago

IPRT: Another RTStrFormatR80* correction. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/* $Id: strformatfloat.cpp 94557 2022-04-11 13:53:21Z vboxsync $ */
2/** @file
3 * IPRT - String Formatter, Floating Point Numbers (simple approach).
4 */
5
6/*
7 * Copyright (C) 2010-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP RTLOGGROUP_STRING
32#include <iprt/string.h>
33#include "internal/iprt.h"
34
35#include <iprt/assert.h>
36#include <iprt/errcore.h>
37#include "internal/string.h"
38
39
40/**
41 * Helper for rtStrFormatR80Worker that copies out the resulting string.
42 */
43static ssize_t rtStrFormatCopyOutStr(char *pszBuf, size_t cbBuf, const char *pszSrc, size_t cchSrc)
44{
45 if (cchSrc < cbBuf)
46 {
47 memcpy(pszBuf, pszSrc, cchSrc);
48 pszBuf[cchSrc] = '\0';
49 return cchSrc;
50 }
51 if (cbBuf)
52 {
53 memcpy(pszBuf, pszSrc, cbBuf - 1);
54 pszBuf[cbBuf - 1] = '\0';
55 }
56 return VERR_BUFFER_OVERFLOW;
57}
58
59
60RTDECL(ssize_t) RTStrFormatR32(char *pszBuf, size_t cbBuf, PCRTFLOAT32U pr32Value, signed int cchWidth,
61 signed int cchPrecision, uint32_t fFlags)
62{
63 RT_NOREF(cchWidth, cchPrecision);
64
65 /*
66 * Handle some special values that does require any value annotating.
67 */
68 bool const fSign = pr32Value->s.fSign;
69 if (RTFLOAT32U_IS_ZERO(pr32Value))
70 return fSign
71 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0"))
72 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0"));
73 if (RTFLOAT32U_IS_INF(pr32Value))
74 return fSign
75 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf"))
76 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf"));
77
78 /*
79 * Output sign first.
80 */
81 char szTmp[80];
82 char *pszTmp = szTmp;
83 if (fSign)
84 *pszTmp++ = '-';
85 else
86 *pszTmp++ = '+';
87
88 /*
89 * Normal?
90 */
91 uint16_t const uExponent = pr32Value->s.uExponent;
92 uint32_t const uFraction = pr32Value->s.uFraction;
93 if (RTFLOAT32U_IS_NORMAL(pr32Value))
94 {
95 *pszTmp++ = '1';
96 *pszTmp++ = 'm';
97 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0,
98 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
99
100 *pszTmp++ = '^';
101 pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT32U_EXP_BIAS, 10, 0, 0,
102 RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED);
103 }
104 /*
105 * Subnormal?
106 */
107 else if (RTFLOAT32U_IS_SUBNORMAL(pr32Value))
108 {
109 *pszTmp++ = '0';
110 *pszTmp++ = 'm';
111 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0,
112 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
113 if (fFlags & RTSTR_F_SPECIAL)
114 pszTmp = (char *)memcpy(pszTmp, "[SubN]", 6) + 6;
115 }
116 /*
117 * NaN.
118 */
119 else
120 {
121 Assert(RTFLOAT32U_IS_NAN(pr32Value));
122 if (!(fFlags & RTSTR_F_SPECIAL))
123 return rtStrFormatCopyOutStr(pszBuf, cbBuf,
124 RTFLOAT32U_IS_SIGNALLING_NAN(pr32Value)
125 ? (fSign ? "-SNan[" : "+SNan[") : fSign ? "-QNan[" : "+QNan[", 5);
126 *pszTmp++ = RTFLOAT32U_IS_SIGNALLING_NAN(pr32Value) ? 'S' : 'Q';
127 *pszTmp++ = 'N';
128 *pszTmp++ = 'a';
129 *pszTmp++ = 'N';
130 *pszTmp++ = '[';
131 *pszTmp++ = '.';
132 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0,
133 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
134 *pszTmp++ = ']';
135 }
136 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
137}
138
139
140
141
142RTDECL(ssize_t) RTStrFormatR64(char *pszBuf, size_t cbBuf, PCRTFLOAT64U pr64Value, signed int cchWidth,
143 signed int cchPrecision, uint32_t fFlags)
144{
145 RT_NOREF(cchWidth, cchPrecision);
146
147 /*
148 * Handle some special values that does require any value annotating.
149 */
150 bool const fSign = pr64Value->s.fSign;
151 if (RTFLOAT64U_IS_ZERO(pr64Value))
152 return fSign
153 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0"))
154 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0"));
155 if (RTFLOAT64U_IS_INF(pr64Value))
156 return fSign
157 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf"))
158 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf"));
159
160 /*
161 * Output sign first.
162 */
163 char szTmp[160];
164 char *pszTmp = szTmp;
165 if (fSign)
166 *pszTmp++ = '-';
167 else
168 *pszTmp++ = '+';
169
170 /*
171 * Normal?
172 */
173 uint16_t const uExponent = pr64Value->s.uExponent;
174 uint64_t const uFraction = RT_MAKE_U64(pr64Value->s.uFractionLow, pr64Value->s.uFractionHigh);
175 if (RTFLOAT64U_IS_NORMAL(pr64Value))
176 {
177 *pszTmp++ = '1';
178 *pszTmp++ = 'm';
179 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT64U_FRACTION_BITS + 3) / 4, 0,
180 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
181
182 *pszTmp++ = '^';
183 pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT64U_EXP_BIAS, 10, 0, 0,
184 RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED);
185 }
186 /*
187 * Subnormal?
188 */
189 else if (RTFLOAT64U_IS_SUBNORMAL(pr64Value))
190 {
191 *pszTmp++ = '0';
192 *pszTmp++ = 'm';
193 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT64U_FRACTION_BITS + 3) / 4, 0,
194 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
195 if (fFlags & RTSTR_F_SPECIAL)
196 pszTmp = (char *)memcpy(pszTmp, "[SubN]", 6) + 6;
197 }
198 /*
199 * NaN.
200 */
201 else
202 {
203 Assert(RTFLOAT64U_IS_NAN(pr64Value));
204 if (!(fFlags & RTSTR_F_SPECIAL))
205 return rtStrFormatCopyOutStr(pszBuf, cbBuf,
206 RTFLOAT64U_IS_SIGNALLING_NAN(pr64Value)
207 ? (fSign ? "-SNan[" : "+SNan[") : fSign ? "-QNan[" : "+QNan[", 5);
208 *pszTmp++ = RTFLOAT64U_IS_SIGNALLING_NAN(pr64Value) ? 'S' : 'Q';
209 *pszTmp++ = 'N';
210 *pszTmp++ = 'a';
211 *pszTmp++ = 'N';
212 *pszTmp++ = '[';
213 *pszTmp++ = '.';
214 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0,
215 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
216 *pszTmp++ = ']';
217 }
218 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
219}
220
221
222/**
223 * Common worker for RTStrFormatR80 and RTStrFormatR80u2.
224 */
225static ssize_t rtStrFormatR80Worker(char *pszBuf, size_t cbBuf, bool const fSign, bool const fInteger,
226 uint64_t const uFraction, uint16_t uExponent, uint32_t fFlags)
227{
228 char szTmp[160];
229
230 /*
231 * Output sign first.
232 */
233 char *pszTmp = szTmp;
234 if (fSign)
235 *pszTmp++ = '-';
236 else
237 *pszTmp++ = '+';
238
239 /*
240 * Then check for special numbers (indicated by expontent).
241 */
242 bool fDenormal = false;
243 if (uExponent == 0)
244 {
245 /* Zero? */
246 if ( !uFraction
247 && !fInteger)
248 return fSign
249 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0"))
250 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0"));
251 fDenormal = true;
252 uExponent = 1;
253 }
254 else if (uExponent == RTFLOAT80U_EXP_MAX)
255 {
256 if (!fInteger)
257 {
258 if (!uFraction)
259 return fSign
260 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoInf"))
261 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoInf"));
262 if (!(fFlags & RTSTR_F_SPECIAL))
263 return fSign
264 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoNan"))
265 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoNan"));
266 pszTmp = (char *)memcpy(pszTmp, "PseudoNan[", 10) + 10;
267 }
268 else if (!(uFraction & RT_BIT_64(62)))
269 {
270 if (!(uFraction & (RT_BIT_64(62) - 1)))
271 return fSign
272 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf"))
273 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf"));
274 if (!(fFlags & RTSTR_F_SPECIAL))
275 return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("SNan"));
276 pszTmp = (char *)memcpy(pszTmp, "SNan[", 5) + 5;
277 }
278 else
279 {
280 if (!(uFraction & (RT_BIT_64(62) - 1)))
281 return fSign
282 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Ind"))
283 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Ind"));
284 if (!(fFlags & RTSTR_F_SPECIAL))
285 return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("QNan"));
286 pszTmp = (char *)memcpy(pszTmp, "QNan[", 5) + 5;
287 }
288 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT80U_FRACTION_BITS / 4, 0,
289 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
290 *pszTmp++ = ']';
291 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
292 }
293
294 /*
295 * Format the mantissa and exponent.
296 */
297 *pszTmp++ = fInteger ? '1' : '0';
298 *pszTmp++ = 'm';
299 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT80U_FRACTION_BITS + 3) / 4, 0,
300 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
301
302 *pszTmp++ = '^';
303 pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT80U_EXP_BIAS, 10, 0, 0,
304 RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED);
305 if (fFlags & RTSTR_F_SPECIAL)
306 {
307 if (fDenormal)
308 {
309 if (fInteger)
310 pszTmp = (char *)memcpy(pszTmp, "[PDn]", 5) + 5;
311 else
312 pszTmp = (char *)memcpy(pszTmp, "[Den]", 5) + 5;
313 }
314 else if (!fInteger)
315 pszTmp = (char *)memcpy(pszTmp, "[Unn]", 5) + 5;
316 }
317 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
318}
319
320
321RTDECL(ssize_t) RTStrFormatR80u2(char *pszBuf, size_t cbBuf, PCRTFLOAT80U2 pr80Value, signed int cchWidth,
322 signed int cchPrecision, uint32_t fFlags)
323{
324 RT_NOREF(cchWidth, cchPrecision);
325#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS
326 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj64.fSign, pr80Value->sj64.fInteger,
327 pr80Value->sj64.uFraction, pr80Value->sj64.uExponent, fFlags);
328#else
329 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj.fSign, pr80Value->sj.fInteger,
330 RT_MAKE_U64(pr80Value->sj.u32FractionLow, pr80Value->sj.u31FractionHigh),
331 pr80Value->sj.uExponent, fFlags);
332#endif
333}
334
335
336RTDECL(ssize_t) RTStrFormatR80(char *pszBuf, size_t cbBuf, PCRTFLOAT80U pr80Value, signed int cchWidth,
337 signed int cchPrecision, uint32_t fFlags)
338{
339 RT_NOREF(cchWidth, cchPrecision);
340 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->s.fSign, pr80Value->s.uMantissa >> 63,
341 pr80Value->s.uMantissa & (RT_BIT_64(63) - 1), pr80Value->s.uExponent, fFlags);
342}
343
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette