VirtualBox

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

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

IPRT: Added RTUInt128MulEx and RTUInt128MulU64Ex as well as a limited RTUInt256Xxx Api. 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 94511 2022-04-07 13:17:57Z 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.215389.xyz. 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 if (fInteger)
253 uExponent = 1;
254 }
255 else if (uExponent == RTFLOAT80U_EXP_MAX)
256 {
257 if (!fInteger)
258 {
259 if (!uFraction)
260 return fSign
261 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoInf"))
262 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoInf"));
263 if (!(fFlags & RTSTR_F_SPECIAL))
264 return fSign
265 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoNan"))
266 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoNan"));
267 pszTmp = (char *)memcpy(pszTmp, "PseudoNan[", 10) + 10;
268 }
269 else if (!(uFraction & RT_BIT_64(62)))
270 {
271 if (!(uFraction & (RT_BIT_64(62) - 1)))
272 return fSign
273 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf"))
274 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf"));
275 if (!(fFlags & RTSTR_F_SPECIAL))
276 return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("SNan"));
277 pszTmp = (char *)memcpy(pszTmp, "SNan[", 5) + 5;
278 }
279 else
280 {
281 if (!(uFraction & (RT_BIT_64(62) - 1)))
282 return fSign
283 ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Ind"))
284 : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Ind"));
285 if (!(fFlags & RTSTR_F_SPECIAL))
286 return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("QNan"));
287 pszTmp = (char *)memcpy(pszTmp, "QNan[", 5) + 5;
288 }
289 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT80U_FRACTION_BITS / 4, 0,
290 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
291 *pszTmp++ = ']';
292 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
293 }
294
295 /*
296 * Format the mantissa and exponent.
297 */
298 *pszTmp++ = fInteger ? '1' : '0';
299 *pszTmp++ = 'm';
300 pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT80U_FRACTION_BITS + 3) / 4, 0,
301 RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT);
302
303 *pszTmp++ = '^';
304 pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT80U_EXP_BIAS, 10, 0, 0,
305 RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED);
306 if (fFlags & RTSTR_F_SPECIAL)
307 {
308 if (fDenormal)
309 {
310 if (fInteger)
311 pszTmp = (char *)memcpy(pszTmp, "[PDn]", 5) + 5;
312 else
313 pszTmp = (char *)memcpy(pszTmp, "[Den]", 5) + 5;
314 }
315 else if (!fInteger)
316 pszTmp = (char *)memcpy(pszTmp, "[Unn]", 5) + 5;
317 }
318 return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]);
319}
320
321
322RTDECL(ssize_t) RTStrFormatR80u2(char *pszBuf, size_t cbBuf, PCRTFLOAT80U2 pr80Value, signed int cchWidth,
323 signed int cchPrecision, uint32_t fFlags)
324{
325 RT_NOREF(cchWidth, cchPrecision);
326#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS
327 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj64.fSign, pr80Value->sj64.fInteger,
328 pr80Value->sj64.uFraction, pr80Value->sj64.uExponent, fFlags);
329#else
330 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj.fSign, pr80Value->sj.fInteger,
331 RT_MAKE_U64(pr80Value->sj.u32FractionLow, pr80Value->sj.u31FractionHigh),
332 pr80Value->sj.uExponent, fFlags);
333#endif
334}
335
336
337RTDECL(ssize_t) RTStrFormatR80(char *pszBuf, size_t cbBuf, PCRTFLOAT80U pr80Value, signed int cchWidth,
338 signed int cchPrecision, uint32_t fFlags)
339{
340 RT_NOREF(cchWidth, cchPrecision);
341 return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->s.fSign, pr80Value->s.uMantissa >> 63,
342 pr80Value->s.uMantissa & (RT_BIT_64(63) - 1), pr80Value->s.uExponent, fFlags);
343}
344
Note: See TracBrowser for help on using the repository browser.

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