VirtualBox

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

Last change on this file since 106579 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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