VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/strtofloat.cpp@ 96156

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

IPRT: Added RTStrToFloat, RTStrToDouble and RTStrToLongDouble. Still some rought edges; only tested on Windows. [build fixes] bugref:10261

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.5 KB
Line 
1/* $Id: strtofloat.cpp 96156 2022-08-12 00:01:44Z vboxsync $ */
2/** @file
3 * IPRT - String To Floating Point Conversion.
4 */
5
6/*
7 * Copyright (C) 2006-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#include <iprt/string.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h> /* needed for RT_C_IS_DIGIT */
37#include <iprt/err.h>
38
39#include <float.h>
40#include <math.h>
41#if !defined(_MSC_VER) || !defined(IPRT_NO_CRT) /** @todo fix*/
42# include <fenv.h>
43#endif
44
45#if defined(SOFTFLOAT_FAST_INT64) /** @todo better softfloat indicator? */
46# define USE_SOFTFLOAT /* for scaling by power of 10 */
47#endif
48#ifdef USE_SOFTFLOAT
49# include <softfloat.h>
50#endif
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56typedef struct FLOATUNION
57{
58 RTFLOAT80U2 lrd;
59 RTFLOAT64U rd;
60 RTFLOAT32U r;
61} FLOATUNION;
62
63#define RET_TYPE_FLOAT 0
64#define RET_TYPE_DOUBLE 1
65#define RET_TYPE_LONG_DOUBLE 2
66
67#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
68typedef RTFLOAT80U2 LONG_DOUBLE_U_T;
69#else
70typedef RTFLOAT64U LONG_DOUBLE_U_T;
71#endif
72
73
74/*********************************************************************************************************************************
75* Global Variables *
76*********************************************************************************************************************************/
77/* in strtonum.cpp */
78extern const unsigned char g_auchDigits[256];
79
80#define DIGITS_ZERO_TERM 254
81#define DIGITS_COLON 253
82#define DIGITS_SPACE 252
83#define DIGITS_DOT 251
84
85#if 0
86/** Maximum exponent value in the binary representation for a RET_TYPE_XXX. */
87static const int32_t g_iMaxExp[3] =
88{
89 RTFLOAT32U_EXP_MAX - 1 - RTFLOAT32U_EXP_BIAS,
90 RTFLOAT64U_EXP_MAX - 1 - RTFLOAT64U_EXP_BIAS,
91#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
92 RTFLOAT80U_EXP_MAX - 1 - RTFLOAT80U_EXP_BIAS,
93#else
94 RTFLOAT64U_EXP_MAX - 1 - RTFLOAT64U_EXP_BIAS,
95#endif
96};
97
98/** Minimum exponent value in the binary representation for a RET_TYPE_XXX. */
99static const int32_t g_iMinExp[3] =
100{
101 1 - RTFLOAT32U_EXP_BIAS,
102 1 - RTFLOAT64U_EXP_BIAS,
103#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
104 1 - RTFLOAT80U_EXP_BIAS,
105#else
106 1 - RTFLOAT64U_EXP_BIAS,
107#endif
108};
109#endif
110
111/** NaN fraction value masks. */
112static uint64_t const g_fNanMasks[3] =
113{
114 RT_BIT_64(RTFLOAT32U_FRACTION_BITS - 1) - 1, /* 22=quiet(1) / silent(0) */
115 RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) - 1, /* 51=quiet(1) / silent(0) */
116#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
117 RT_BIT_64(RTFLOAT80U_FRACTION_BITS - 1) - 1, /* bit 63=NaN; bit 62=quiet(1) / silent(0) */
118#else
119 RT_BIT_64(RTFLOAT64U_FRACTION_BITS - 1) - 1,
120#endif
121};
122
123#if 0 /* unused */
124#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
125static const long double g_lrdPowerMin10 = 1e4931L;
126static const long double g_lrdPowerMax10 = 1e4932L;
127#else
128static const long double g_lrdPowerMin10 = 1e307L;
129static const long double g_lrdPowerMax10 = 1e308L;
130#endif
131#endif
132
133#ifdef USE_SOFTFLOAT
134/** SoftFloat: Power of 10 table using 128-bit floating point.
135 *
136 * @code
137 softfloat_state_t SoftState = SOFTFLOAT_STATE_INIT_DEFAULTS();
138 float128_t Power10;
139 ui32_to_f128M(10, &Power10, &SoftState);
140 for (unsigned iBit = 0; iBit < 13; iBit++)
141 {
142 RTAssertMsg2(" { UINT64_C(%#018RX64), UINT64_C(%#018RX64) }, %c* 1e%u (%RU64) *%c\n", Power10.v[0], Power10.v[1],
143 '/', RT_BIT_32(iBit), f128M_to_ui64(&Power10, softfloat_round_near_even, false, &SoftState), '/');
144 f128M_mul(&Power10, &Power10, &Power10, &SoftState);
145 }
146 @endcode */
147static const float128_t g_ar128Power10[] =
148{
149 { UINT64_C(0x0000000000000000), UINT64_C(0x4002400000000000) }, /* 1e1 (10) */
150 { UINT64_C(0x0000000000000000), UINT64_C(0x4005900000000000) }, /* 1e2 (100) */
151 { UINT64_C(0x0000000000000000), UINT64_C(0x400c388000000000) }, /* 1e4 (10000) */
152 { UINT64_C(0x0000000000000000), UINT64_C(0x40197d7840000000) }, /* 1e8 (100000000) */
153 { UINT64_C(0x0000000000000000), UINT64_C(0x40341c37937e0800) }, /* 1e16 (10000000000000000) */
154 { UINT64_C(0x6b3be04000000000), UINT64_C(0x40693b8b5b5056e1) }, /* 1e32 (18446744073709551615) */
155 { UINT64_C(0x4daa797ed6e38ed6), UINT64_C(0x40d384f03e93ff9f) }, /* 1e64 (18446744073709551615) */
156 { UINT64_C(0x19bf8cde66d86d61), UINT64_C(0x41a827748f9301d3) }, /* 1e128 (18446744073709551615) */
157 { UINT64_C(0xbd1bbb77203731fb), UINT64_C(0x435154fdd7f73bf3) }, /* 1e256 (18446744073709551615) */
158 { UINT64_C(0x238d98cab8a97899), UINT64_C(0x46a3c633415d4c1d) }, /* 1e512 (18446744073709551615) */
159 { UINT64_C(0x182eca1a7a51e308), UINT64_C(0x4d4892eceb0d02ea) }, /* 1e1024 (18446744073709551615) */
160 { UINT64_C(0xbbc94e9a519c651e), UINT64_C(0x5a923d1676bb8a7a) }, /* 1e2048 (18446744073709551615) */
161 { UINT64_C(0x2f3592982a7f005a), UINT64_C(0x752588c0a4051441) }, /* 1e4096 (18446744073709551615) */
162 /* INF */
163};
164
165/** SoftFloat: Initial value for power of 10 scaling.
166 * This deals with the first 32 powers of 10, covering the a full 64-bit
167 * mantissa and a small exponent w/o needing to make use of g_ar128Power10.
168 *
169 * @code
170 softfloat_state_t SoftState = SOFTFLOAT_STATE_INIT_DEFAULTS();
171 float128_t Num10;
172 ui32_to_f128M(10, &Num10, &SoftState);
173 float128_t Power10;
174 ui32_to_f128M(1, &Power10, &SoftState);
175 for (unsigned cTimes = 0; cTimes < 32; cTimes++)
176 {
177 RTAssertMsg2(" { UINT64_C(%#018RX64), UINT64_C(%#018RX64) }, %c* 1e%u (%RU64) *%c\n", Power10.v[0], Power10.v[1],
178 '/', cTimes, f128M_to_ui64(&Power10, softfloat_round_near_even, false, &SoftState), '/');
179 f128M_mul(&Power10, &Num10, &Power10, &SoftState);
180 }
181 @endcode */
182static const float128_t g_ar128Power10Initial[] =
183{
184 { UINT64_C(0x0000000000000000), UINT64_C(0x3fff000000000000) }, /* 1e0 (1) */
185 { UINT64_C(0x0000000000000000), UINT64_C(0x4002400000000000) }, /* 1e1 (10) */
186 { UINT64_C(0x0000000000000000), UINT64_C(0x4005900000000000) }, /* 1e2 (100) */
187 { UINT64_C(0x0000000000000000), UINT64_C(0x4008f40000000000) }, /* 1e3 (1000) */
188 { UINT64_C(0x0000000000000000), UINT64_C(0x400c388000000000) }, /* 1e4 (10000) */
189 { UINT64_C(0x0000000000000000), UINT64_C(0x400f86a000000000) }, /* 1e5 (100000) */
190 { UINT64_C(0x0000000000000000), UINT64_C(0x4012e84800000000) }, /* 1e6 (1000000) */
191 { UINT64_C(0x0000000000000000), UINT64_C(0x4016312d00000000) }, /* 1e7 (10000000) */
192 { UINT64_C(0x0000000000000000), UINT64_C(0x40197d7840000000) }, /* 1e8 (100000000) */
193 { UINT64_C(0x0000000000000000), UINT64_C(0x401cdcd650000000) }, /* 1e9 (1000000000) */
194 { UINT64_C(0x0000000000000000), UINT64_C(0x40202a05f2000000) }, /* 1e10 (10000000000) */
195 { UINT64_C(0x0000000000000000), UINT64_C(0x402374876e800000) }, /* 1e11 (100000000000) */
196 { UINT64_C(0x0000000000000000), UINT64_C(0x4026d1a94a200000) }, /* 1e12 (1000000000000) */
197 { UINT64_C(0x0000000000000000), UINT64_C(0x402a2309ce540000) }, /* 1e13 (10000000000000) */
198 { UINT64_C(0x0000000000000000), UINT64_C(0x402d6bcc41e90000) }, /* 1e14 (100000000000000) */
199 { UINT64_C(0x0000000000000000), UINT64_C(0x4030c6bf52634000) }, /* 1e15 (1000000000000000) */
200 { UINT64_C(0x0000000000000000), UINT64_C(0x40341c37937e0800) }, /* 1e16 (10000000000000000) */
201 { UINT64_C(0x0000000000000000), UINT64_C(0x40376345785d8a00) }, /* 1e17 (100000000000000000) */
202 { UINT64_C(0x0000000000000000), UINT64_C(0x403abc16d674ec80) }, /* 1e18 (1000000000000000000) */
203 { UINT64_C(0x0000000000000000), UINT64_C(0x403e158e460913d0) }, /* 1e19 (10000000000000000000) */
204 { UINT64_C(0x0000000000000000), UINT64_C(0x40415af1d78b58c4) }, /* 1e20 (18446744073709551615) */
205 { UINT64_C(0x0000000000000000), UINT64_C(0x4044b1ae4d6e2ef5) }, /* 1e21 (18446744073709551615) */
206 { UINT64_C(0x2000000000000000), UINT64_C(0x40480f0cf064dd59) }, /* 1e22 (18446744073709551615) */
207 { UINT64_C(0x6800000000000000), UINT64_C(0x404b52d02c7e14af) }, /* 1e23 (18446744073709551615) */
208 { UINT64_C(0x4200000000000000), UINT64_C(0x404ea784379d99db) }, /* 1e24 (18446744073709551615) */
209 { UINT64_C(0x0940000000000000), UINT64_C(0x405208b2a2c28029) }, /* 1e25 (18446744073709551615) */
210 { UINT64_C(0x4b90000000000000), UINT64_C(0x40554adf4b732033) }, /* 1e26 (18446744073709551615) */
211 { UINT64_C(0x1e74000000000000), UINT64_C(0x40589d971e4fe840) }, /* 1e27 (18446744073709551615) */
212 { UINT64_C(0x1308800000000000), UINT64_C(0x405c027e72f1f128) }, /* 1e28 (18446744073709551615) */
213 { UINT64_C(0x17caa00000000000), UINT64_C(0x405f431e0fae6d72) }, /* 1e29 (18446744073709551615) */
214 { UINT64_C(0x9dbd480000000000), UINT64_C(0x406293e5939a08ce) }, /* 1e30 (18446744073709551615) */
215 { UINT64_C(0x452c9a0000000000), UINT64_C(0x4065f8def8808b02) }, /* 1e31 (18446744073709551615) */
216};
217
218#else /* !USE_SOFTFLOAT */
219/** Long Double: Power of 10 table scaling table.
220 * @note LDBL_MAX_10_EXP is 4932 for 80-bit and 308 for 64-bit type. */
221static const long double a_lrdPower10[] =
222{
223 1e1L,
224 1e2L,
225 1e4L,
226 1e8L,
227 1e16L,
228 1e32L,
229 1e64L,
230 1e128L,
231 1e256L,
232# ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
233 1e512L,
234 1e1024L,
235 1e2048L,
236 1e4096L,
237# endif
238};
239
240/** Long double: Initial value for power of 10 scaling.
241 * This deals with the first 32 powers of 10, covering the a full 64-bit
242 * mantissa and a small exponent w/o needing to make use of g_ar128Power10. */
243static const long double g_alrdPower10Initial[] =
244{
245 1e0L,
246 1e1L,
247 1e2L,
248 1e3L,
249 1e4L,
250 1e5L,
251 1e6L,
252 1e7L,
253 1e8L,
254 1e9L,
255 1e10L,
256 1e11L,
257 1e12L,
258 1e13L,
259 1e14L,
260 1e15L,
261 1e16L,
262 1e17L,
263 1e18L,
264 1e19L,
265 1e20L,
266 1e21L,
267 1e22L,
268 1e23L,
269 1e24L,
270 1e25L,
271 1e26L,
272 1e27L,
273 1e28L,
274 1e29L,
275 1e30L,
276 1e31L,
277};
278
279/* Tell the compiler that we'll mess with the FPU environment. */
280# ifdef _MSC_VER
281# pragma fenv_access(on)
282# endif
283#endif /*!USE_SOFTFLOAT */
284
285
286/**
287 * Multiply @a pVal by 10 to the power of @a iExponent10.
288 *
289 * This is currently a weak point where we might end up with rounding issues.
290 */
291static int rtStrToLongDoubleExp10(LONG_DOUBLE_U_T *pVal, int iExponent10)
292{
293 AssertReturn(iExponent10 != 0, VINF_SUCCESS);
294#ifdef USE_SOFTFLOAT
295 /* Use 128-bit precision floating point from softfloat to improve accuracy. */
296
297 softfloat_state_t SoftState = SOFTFLOAT_STATE_INIT_DEFAULTS();
298 float128_t Val;
299#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
300 extFloat80M Tmp = EXTFLOAT80M_INIT(pVal->s2.uSignAndExponent, pVal->s2.uMantissa);
301 extF80M_to_f128M(&Tmp, &Val, &SoftState);
302#else
303 float64_t Tmp = { pVal->u };
304 f64_to_f128M(Tmp, &Val, &SoftState);
305#endif
306
307 /*
308 * Calculate the scaling factor. If we need to make use of the last table
309 * entry, we will do part of the scaling here to avoid overflowing Factor.
310 */
311 unsigned uAbsExp = (unsigned)RT_ABS(iExponent10);
312 AssertCompile(RT_ELEMENTS(g_ar128Power10Initial) == 32);
313 unsigned iBit = 5;
314 float128_t Factor = g_ar128Power10Initial[uAbsExp & 31];
315 uAbsExp >>= iBit;
316 while (uAbsExp != 0)
317 {
318 if (iBit < RT_ELEMENTS(g_ar128Power10))
319 {
320 if (uAbsExp & 1)
321 {
322 if (iBit < RT_ELEMENTS(g_ar128Power10) - 1)
323 f128M_mul(&Factor, &g_ar128Power10[iBit], &Factor, &SoftState);
324 else
325 {
326 /* Must do it in two steps to avoid prematurely overflowing the factor value. */
327 if (iExponent10 > 0)
328 f128M_mul(&Val, &Factor, &Val, &SoftState);
329 else
330 f128M_div(&Val, &Factor, &Val, &SoftState);
331 Factor = g_ar128Power10[iBit];
332 }
333 }
334 }
335 else if (iExponent10 < 0)
336 {
337 pVal->r = pVal->r < 0.0L ? -0.0L : +0.0L;
338 return VERR_FLOAT_UNDERFLOW;
339 }
340 else
341 {
342 pVal->r = pVal->r < 0.0L ? -INFINITY : +INFINITY;
343 return VERR_FLOAT_OVERFLOW;
344 }
345 iBit++;
346 uAbsExp >>= 1;
347 }
348
349 /*
350 * Do the scaling (or what remains).
351 */
352 if (iExponent10 > 0)
353 f128M_mul(&Val, &Factor, &Val, &SoftState);
354 else
355 f128M_div(&Val, &Factor, &Val, &SoftState);
356
357#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
358 f128M_to_extF80M(&Val, &Tmp, &SoftState);
359 pVal->s2.uSignAndExponent = Tmp.signExp;
360 pVal->s2.uMantissa = Tmp.signif;
361#else
362 Tmp = f128M_to_f64(&Val, &SoftState);
363 pVal->u = Tmp.v;
364#endif
365
366 /*
367 * Check for under/overflow and return.
368 */
369 int rc;
370 if (!(SoftState.exceptionFlags & (softfloat_flag_underflow | softfloat_flag_overflow)))
371 rc = VINF_SUCCESS;
372 else if (SoftState.exceptionFlags & softfloat_flag_underflow)
373 {
374RTAssertMsg2("VERR_FLOAT_UNDERFLOW r128=%.16Rhxs r64=%.8Rhxs\n", &Val, &Tmp);
375 rc = VERR_FLOAT_UNDERFLOW;
376 }
377 else
378 rc = VERR_FLOAT_OVERFLOW;
379
380#else
381# if 0
382 /*
383 * Use RTBigNum, falling back on the simple approach if we don't need the
384 * precision or run out of memory?
385 */
386 /** @todo implement RTBigNum approach */
387# endif
388
389 /*
390 * Simple approach.
391 */
392# if !defined(_MSC_VER) || !defined(IPRT_NO_CRT) /** @todo fix*/
393 fenv_t SavedFpuEnv;
394 feholdexcept(&SavedFpuEnv);
395# endif
396
397 /*
398 * Calculate the scaling factor. If we need to make use of the last table
399 * entry, we will do part of the scaling here to avoid overflowing lrdFactor.
400 */
401 AssertCompile(RT_ELEMENTS(g_alrdPower10Initial) == 32);
402 int rc = VINF_SUCCESS;
403 unsigned uAbsExp = (unsigned)RT_ABS(iExponent10);
404 long double lrdFactor = g_alrdPower10Initial[uAbsExp & 31];
405 unsigned iBit = 5;
406 uAbsExp >>= iBit;
407
408 while (uAbsExp != 0)
409 {
410 if (iBit < RT_ELEMENTS(a_lrdPower10))
411 {
412 if (uAbsExp & 1)
413 {
414 if (iBit < RT_ELEMENTS(a_lrdPower10) - 1)
415 lrdFactor *= a_lrdPower10[iBit];
416 else
417 {
418 /* Must do it in two steps to avoid prematurely overflowing the factor value. */
419 if (iExponent10 < 0)
420 pVal->r /= lrdFactor;
421 else
422 pVal->r *= lrdFactor;
423 lrdFactor = a_lrdPower10[iBit];
424 }
425 }
426 }
427 else if (iExponent10 < 0)
428 {
429 pVal->r = pVal->r < 0.0L ? -0.0L : +0.0L;
430 rc = VERR_FLOAT_UNDERFLOW;
431 break;
432 }
433 else
434 {
435 pVal->r = pVal->r < 0.0L ? -INFINITY : +INFINITY;
436 rc = VERR_FLOAT_OVERFLOW;
437 break;
438 }
439 iBit++;
440 uAbsExp >>= 1;
441 }
442
443 /*
444 * Do the scaling (or what remains).
445 */
446 if (iExponent10 < 0)
447 pVal->r /= lrdFactor;
448 else
449 pVal->r *= lrdFactor;
450
451# if !defined(_MSC_VER) || !defined(IPRT_NO_CRT) /** @todo fix*/
452 fesetenv(&SavedFpuEnv);
453# endif
454
455#endif
456 return rc;
457}
458
459
460
461/**
462 * Set @a ppszNext and check for trailing spaces & chars if @a rc is
463 * VINF_SUCCESS.
464 *
465 * @returns IPRT status code.
466 * @param psz The current input position.
467 * @param ppszNext Where to return the pointer to the end of the value.
468 * Optional.
469 * @param cchMax Number of bytes left in the string starting at @a psz.
470 * @param rc The status code to return.
471 */
472static int rtStrToLongDoubleReturnChecks(const char *psz, char **ppszNext, size_t cchMax, int rc)
473{
474 if (ppszNext)
475 *ppszNext = (char *)psz;
476
477 /* Trailing spaces/chars warning: */
478 if (rc == VINF_SUCCESS && cchMax > 0 && *psz)
479 {
480 do
481 {
482 char ch = *psz++;
483 if (ch == ' ' || ch == '\t')
484 cchMax--;
485 else
486 return ch == '\0' ? VWRN_TRAILING_SPACES : VWRN_TRAILING_CHARS;
487 } while (cchMax > 0);
488 rc = VWRN_TRAILING_SPACES;
489 }
490 return rc;
491}
492
493
494/**
495 * Set @a pRet to infinity, set @a ppszNext, and check for trailing spaces &
496 * chars if @a rc is VINF_SUCCESS.
497 *
498 * @returns IPRT status code.
499 * @param psz The current input position.
500 * @param ppszNext Where to return the pointer to the end of the value.
501 * Optional.
502 * @param cchMax Number of bytes left in the string starting at @a psz.
503 * @param rc The status code to return.
504 */
505static int rtStrToLongDoubleReturnInf(const char *psz, char **ppszNext, size_t cchMax, bool fPositive,
506 int rc, unsigned iRetType, FLOATUNION *pRet)
507{
508 /*
509 * Skip to the end of long form?
510 */
511 char ch;
512 if ( cchMax >= 5
513 && ((ch = psz[0]) == 'i' || ch == 'I')
514 && ((ch = psz[1]) == 'n' || ch == 'N')
515 && ((ch = psz[2]) == 'i' || ch == 'I')
516 && ((ch = psz[3]) == 't' || ch == 'T')
517 && ((ch = psz[4]) == 'y' || ch == 'Y'))
518 {
519 psz += 5;
520 cchMax -= 5;
521 }
522
523 /*
524 * Set the return value:
525 */
526 switch (iRetType)
527 {
528 case RET_TYPE_FLOAT:
529 {
530 RTFLOAT32U const uRet = RTFLOAT32U_INIT_INF(!fPositive);
531 AssertCompile(sizeof(uRet) == sizeof(pRet->r.r));
532 pRet->r.r = uRet.r;
533 break;
534 }
535
536 case RET_TYPE_LONG_DOUBLE:
537#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
538 {
539 RTFLOAT80U2 const uRet = RTFLOAT80U_INIT_INF(!fPositive);
540 pRet->lrd.lrd = uRet.lrd;
541 break;
542 }
543#else
544 AssertCompile(sizeof(long double) == sizeof(pRet->rd.rd));
545 RT_FALL_THRU();
546#endif
547 case RET_TYPE_DOUBLE:
548 {
549 RTFLOAT64U const uRet = RTFLOAT64U_INIT_INF(!fPositive);
550 AssertCompile(sizeof(uRet) == sizeof(pRet->rd.rd));
551 pRet->rd.rd = uRet.rd;
552 break;
553 }
554
555 default: AssertFailedBreak();
556 }
557
558 /*
559 * Deal with whatever follows and return:
560 */
561 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, rc);
562}
563
564
565/**
566 * Parses the tag of a "NaN(tag)" value.
567 *
568 * We take the tag to be a number to be put in the mantissa of the NaN, possibly
569 * prefixed by 'quiet_' or 'silent_' (all or part) to indicate the type of NaN.
570 *
571 * @returns Value found in the tag string. Caller must mask it to fit in the
572 * target format.
573 * @param pchTag The tag string to parse. Not zero terminated.
574 * @param cchTag The length of the tag string value.
575 * @param pfQuiet Where to return the type of NaN. Default is quiet.
576 */
577static uint64_t rtStrParseNanTag(const char *pchTag, size_t cchTag, bool *pfQuiet)
578{
579 *pfQuiet = true;
580
581 /*
582 * Skip 0x - content is hexadecimal, so this is not necessary.
583 */
584 if (cchTag > 2 && pchTag[0] == '0' && (pchTag[1] == 'x' || pchTag[1] == 'X'))
585 {
586 pchTag += 2;
587 cchTag -= 2;
588 }
589
590 /*
591 * Parse the number, ignoring overflows and stopping on non-xdigit.
592 */
593 uint64_t uRet = 0;
594 while (cchTag > 0)
595 {
596 unsigned char uch = (unsigned char)*pchTag;
597 unsigned char uchDigit = g_auchDigits[uch];
598 if (uchDigit >= 16)
599 break;
600 uRet *= 16;
601 uRet += uchDigit;
602 pchTag++;
603 cchTag--;
604 }
605
606 /*
607 * Check for special "non-standard" quiet / signalling indicator.
608 */
609 while (cchTag > 0 && *pchTag == '_')
610 pchTag++, cchTag--;
611 if (cchTag > 0)
612 {
613 char const ch = pchTag[0];
614 if (ch == 'q' || ch == 'Q')
615 *pfQuiet = true;
616 else if (ch == 's' || ch == 'S')
617 *pfQuiet = false;
618 }
619
620 return uRet;
621}
622
623
624/**
625 * Finish parsing NaN, set @a pRet to NaN, set @a ppszNext, and check for
626 * trailing spaces & chars if @a rc is VINF_SUCCESS.
627 *
628 * @returns IPRT status code.
629 * @param psz The current input position.
630 * @param ppszNext Where to return the pointer to the end of the value.
631 * Optional.
632 * @param cchMax Number of bytes left in the string starting at @a psz.
633 * @param rc The status code to return.
634 */
635static int rtStrToLongDoubleReturnNan(const char *psz, char **ppszNext, size_t cchMax, bool fPositive,
636 unsigned iRetType, FLOATUNION *pRet)
637{
638 /*
639 * Any NaN sub-number? E.g. NaN(1) or Nan(0x42). We'll require a closing
640 * parenthesis or we'll just ignore it.
641 */
642 bool fQuiet = true;
643 uint64_t uNum = 1;
644 if (cchMax >= 2 && *psz == '(')
645 {
646 unsigned cch = 1;
647 char ch = '\0';
648 while (cch < cchMax && (RT_C_IS_ALNUM((ch = psz[cch])) || ch == '_'))
649 cch++;
650 if (ch == ')')
651 {
652 uNum = rtStrParseNanTag(psz + 1, cch - 1, &fQuiet);
653 psz += cch + 1;
654 cchMax -= cch + 1;
655
656 Assert(iRetType < RT_ELEMENTS(g_fNanMasks));
657 uNum &= g_fNanMasks[iRetType];
658 if (!uNum)
659 uNum = 1; /* must not be zero, or it'll turn into an infinity */
660 }
661 }
662
663 /*
664 * Set the return value.
665 */
666 switch (iRetType)
667 {
668 case RET_TYPE_FLOAT:
669 {
670 RTFLOAT32U const uRet = RTFLOAT32U_INIT_NAN_EX(fQuiet, !fPositive, (uint32_t)uNum);
671 pRet->r = uRet;
672 break;
673 }
674
675 case RET_TYPE_LONG_DOUBLE:
676#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
677 {
678 RTFLOAT80U2 const uRet = RTFLOAT80U_INIT_NAN_EX(fQuiet, !fPositive, uNum);
679 pRet->lrd = uRet;
680 break;
681 }
682#else
683 AssertCompile(sizeof(long double) == sizeof(pRet->rd.rd));
684 RT_FALL_THRU();
685#endif
686 case RET_TYPE_DOUBLE:
687 {
688 RTFLOAT64U const uRet = RTFLOAT64U_INIT_NAN_EX(fQuiet, !fPositive, uNum);
689 pRet->rd = uRet;
690 break;
691 }
692
693 default: AssertFailedBreak();
694 }
695
696 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, VINF_SUCCESS);
697}
698
699
700/**
701 * Set @a pRet to zero, set @a ppszNext, and check for trailing spaces &
702 * chars if @a rc is VINF_SUCCESS.
703 *
704 * @returns IPRT status code.
705 * @param psz The current input position.
706 * @param ppszNext Where to return the pointer to the end of the value.
707 * Optional.
708 * @param cchMax Number of bytes left in the string starting at @a psz.
709 * @param rc The status code to return.
710 */
711static int rtStrToLongDoubleReturnZero(const char *psz, char **ppszNext, size_t cchMax, bool fPositive,
712 int rc, unsigned iRetType, FLOATUNION *pRet)
713{
714 switch (iRetType)
715 {
716 case RET_TYPE_FLOAT:
717 pRet->r.r = fPositive ? +0.0F : -0.0F;
718 break;
719
720 case RET_TYPE_LONG_DOUBLE:
721#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
722 pRet->lrd.lrd = fPositive ? +0.0L : -0.0L;
723 break;
724#else
725 AssertCompile(sizeof(long double) == sizeof(pRet->rd.rd));
726 RT_FALL_THRU();
727#endif
728 case RET_TYPE_DOUBLE:
729 pRet->rd.rd = fPositive ? +0.0 : -0.0;
730 break;
731
732 default: AssertFailedBreak();
733 }
734
735 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, rc);
736}
737
738
739/**
740 * Return overflow or underflow - setting @a pRet and @a ppszNext accordingly.
741 *
742 * @returns IPRT status code.
743 * @param psz The current input position.
744 * @param ppszNext Where to return the pointer to the end of the value.
745 * Optional.
746 * @param cchMax Number of bytes left in the string starting at @a psz.
747 * @param rc The status code to return.
748 */
749static int rtStrToLongDoubleReturnOverflow(const char *psz, char **ppszNext, size_t cchMax, bool fPositive,
750 int32_t iExponent, unsigned iRetType, FLOATUNION *pRet)
751{
752 if (iExponent > 0)
753 return rtStrToLongDoubleReturnInf(psz, ppszNext, cchMax, fPositive, VERR_FLOAT_OVERFLOW, iRetType, pRet);
754 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VERR_FLOAT_UNDERFLOW, iRetType, pRet);
755}
756
757
758/**
759 * Returns a denormal/subnormal value.
760 *
761 * This implies that iRetType is long double, or double if they are the same,
762 * and that we should warn about underflowing.
763 */
764static int rtStrToLongDoubleReturnSubnormal(const char *psz, char **ppszNext, size_t cchMax, LONG_DOUBLE_U_T const *pVal,
765 unsigned iRetType, FLOATUNION *pRet)
766{
767#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
768 Assert(iRetType == RET_TYPE_LONG_DOUBLE);
769 pRet->lrd = *pVal;
770#else
771 Assert(iRetType == RET_TYPE_LONG_DOUBLE || iRetType == RET_TYPE_DOUBLE);
772 pRet->rd = *pVal;
773#endif
774 RT_NOREF(iRetType);
775 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, VWRN_FLOAT_UNDERFLOW);
776}
777
778
779/**
780 * Packs the given sign, mantissa, and (power of 2) exponent into the
781 * return value.
782 */
783static int rtStrToLongDoubleReturnValue(const char *psz, char **ppszNext, size_t cchMax,
784 bool fPositive, uint64_t uMantissa, int32_t iExponent,
785 unsigned iRetType, FLOATUNION *pRet)
786{
787 int rc = VINF_SUCCESS;
788 switch (iRetType)
789 {
790 case RET_TYPE_FLOAT:
791 iExponent += RTFLOAT32U_EXP_BIAS;
792 if (iExponent <= 0)
793 {
794 /* Produce a subnormal value if it's within range, otherwise return zero. */
795 if (iExponent < -RTFLOAT32U_FRACTION_BITS)
796 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_UNDERFLOW, iRetType, pRet);
797 rc = VWRN_FLOAT_UNDERFLOW;
798 uMantissa >>= -iExponent + 1;
799 iExponent = 0;
800 }
801 else if (iExponent >= RTFLOAT32U_EXP_MAX)
802 return rtStrToLongDoubleReturnInf(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_OVERFLOW, iRetType, pRet);
803
804 pRet->r.s.uFraction = (uMantissa >> (63 - RTFLOAT32U_FRACTION_BITS)) & (RT_BIT_64(RTFLOAT32U_FRACTION_BITS) - 1);
805 pRet->r.s.uExponent = iExponent;
806 pRet->r.s.fSign = !fPositive;
807 break;
808
809 case RET_TYPE_LONG_DOUBLE:
810#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
811 iExponent += RTFLOAT80U_EXP_BIAS;
812 if (iExponent <= 0)
813 {
814 /* Produce a subnormal value if it's within range, otherwise return zero. */
815 if (iExponent < -RTFLOAT80U_FRACTION_BITS)
816 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_UNDERFLOW, iRetType, pRet);
817 rc = VWRN_FLOAT_UNDERFLOW;
818 uMantissa >>= -iExponent + 1;
819 iExponent = 0;
820 }
821 else if (iExponent >= RTFLOAT80U_EXP_MAX)
822 return rtStrToLongDoubleReturnInf(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_OVERFLOW, iRetType, pRet);
823
824 pRet->lrd.s.uMantissa = uMantissa;
825 pRet->lrd.s.uExponent = iExponent;
826 pRet->lrd.s.fSign = !fPositive;
827 break;
828#else
829 AssertCompile(sizeof(long double) == sizeof(pRet->rd.rd));
830 RT_FALL_THRU();
831#endif
832 case RET_TYPE_DOUBLE:
833 iExponent += RTFLOAT64U_EXP_BIAS;
834 if (iExponent <= 0)
835 {
836 /* Produce a subnormal value if it's within range, otherwise return zero. */
837 if (iExponent < -RTFLOAT64U_FRACTION_BITS)
838 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_UNDERFLOW, iRetType, pRet);
839 rc = VWRN_FLOAT_UNDERFLOW;
840 uMantissa >>= -iExponent + 1;
841 iExponent = 0;
842 }
843 else if (iExponent >= RTFLOAT64U_EXP_MAX)
844 return rtStrToLongDoubleReturnInf(psz, ppszNext, cchMax, fPositive, VWRN_FLOAT_OVERFLOW, iRetType, pRet);
845
846 pRet->rd.s64.uFraction = (uMantissa >> (63 - RTFLOAT64U_FRACTION_BITS)) & (RT_BIT_64(RTFLOAT64U_FRACTION_BITS) - 1);
847 pRet->rd.s64.uExponent = iExponent;
848 pRet->rd.s64.fSign = !fPositive;
849 break;
850
851 default:
852 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
853 }
854 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, rc);
855}
856
857
858/**
859 * Worker for RTStrToLongDoubleEx, RTStrToDoubleEx and RTStrToFloatEx.
860 *
861 * @returns IPRT status code
862 * @param pszValue The string value to convert.
863 * @param ppszNext Where to return the pointer to the end of the value.
864 * Optional.
865 * @param cchMax Number of bytes left in the string starting at @a psz.
866 * @param iRetType The return type: float, double or long double.
867 * @param pRet The return value union.
868 */
869static int rtStrToLongDoubleWorker(const char *pszValue, char **ppszNext, size_t cchMax, unsigned iRetType, FLOATUNION *pRet)
870{
871 const char *psz = pszValue;
872 if (!cchMax)
873 cchMax = ~(size_t)cchMax;
874
875 /*
876 * Sign.
877 */
878 bool fPositive = true;
879 while (cchMax > 0)
880 {
881 if (*psz == '+')
882 fPositive = true;
883 else if (*psz == '-')
884 fPositive = !fPositive;
885 else
886 break;
887 psz++;
888 cchMax--;
889 }
890
891 /*
892 * Constant like "Inf", "Infinity", "NaN" or "NaN(hexstr)"?
893 */
894 /* "Inf" or "Infinity"? */
895 if (cchMax == 0)
896 return rtStrToLongDoubleReturnZero(pszValue, ppszNext, cchMax, fPositive, VERR_NO_DIGITS, iRetType, pRet);
897 if (cchMax >= 3)
898 {
899 char ch = *psz;
900 /* Inf: */
901 if (ch == 'i' || ch == 'I')
902 {
903 if ( ((ch = psz[1]) == 'n' || ch == 'N')
904 && ((ch = psz[2]) == 'f' || ch == 'F'))
905 return rtStrToLongDoubleReturnInf(psz + 3, ppszNext, cchMax - 3, fPositive, VINF_SUCCESS, iRetType, pRet);
906 }
907 /* Nan: */
908 else if (ch == 'n' || ch == 'N')
909 {
910 if ( ((ch = psz[1]) == 'a' || ch == 'A')
911 && ((ch = psz[2]) == 'n' || ch == 'N'))
912 return rtStrToLongDoubleReturnNan(psz + 3, ppszNext, cchMax - 3, fPositive, iRetType, pRet);
913 }
914 }
915
916 /*
917 * Check for hex prefix.
918 */
919#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
920 unsigned cMaxDigits = 19;
921#else
922 unsigned cMaxDigits = 18;
923#endif
924 unsigned uBase = 10;
925 unsigned uExpDigitFactor = 1;
926 if (cchMax >= 2 && psz[0] == '0' && (psz[1] == 'x' || psz[1] == 'X'))
927 {
928 cMaxDigits = 16;
929 uBase = 16;
930 uExpDigitFactor = 4;
931 cchMax -= 2;
932 psz += 2;
933 }
934
935 /*
936 * Now, parse the mantissa.
937 */
938 uint8_t abDigits[20];
939 unsigned cDigits = 0;
940 unsigned cFractionDigits = 0;
941 uint8_t fSeenNonZeroDigit = 0;
942 bool fInFraction = false;
943 bool fSeenDigits = false;
944 while (cchMax > 0)
945 {
946 uint8_t b = g_auchDigits[(unsigned char)*psz];
947 if (b < uBase)
948 {
949 fSeenDigits = true;
950 fSeenNonZeroDigit |= b;
951 if (fSeenNonZeroDigit)
952 {
953 if (cDigits < RT_ELEMENTS(abDigits))
954 abDigits[cDigits] = b;
955 cDigits++;
956 cFractionDigits += fInFraction;
957 }
958 }
959 else if (b == DIGITS_DOT && !fInFraction)
960 fInFraction = true;
961 else
962 break;
963 psz++;
964 cchMax--;
965 }
966
967 /* If we've seen no digits, or just a dot, return zero already. */
968 if (!fSeenDigits)
969 {
970 if (fInFraction) /* '+.' => 0.0 ? */
971 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VINF_SUCCESS, iRetType, pRet);
972 if (uBase == 16) /* '+0x' => 0.0 & *=pszNext="x..." */
973 return rtStrToLongDoubleReturnZero(psz - 1, ppszNext, cchMax, fPositive, VINF_SUCCESS, iRetType, pRet);
974 /* '' and '+' -> no digits + 0.0. */
975 return rtStrToLongDoubleReturnZero(pszValue, ppszNext, cchMax, fPositive, VERR_NO_DIGITS, iRetType, pRet);
976 }
977
978 /*
979 * Parse the exponent.
980 * This is optional and we ignore incomplete ones like "e+".
981 */
982 int32_t iExponent = 0;
983 if (cchMax >= 2) /* min "e0" */
984 {
985 char ch = *psz;
986 if (uBase == 10 ? ch == 'e' || ch == 'E' : ch == 'p' || ch == 'P')
987 {
988 bool fExpOverflow = false;
989 bool fPositiveExp = true;
990 size_t off = 1;
991 ch = psz[off];
992 if (ch == '+' || ch == '-')
993 {
994 fPositiveExp = ch == '+';
995 off++;
996 }
997 uint8_t b;
998 if ( off < cchMax
999 && (b = g_auchDigits[(unsigned char)psz[off]]) < 10)
1000 {
1001 do
1002 {
1003 int32_t const iPreviousExponent = iExponent;
1004 iExponent *= 10;
1005 iExponent += b;
1006 if (iExponent < iPreviousExponent)
1007 fExpOverflow = true;
1008 off++;
1009 } while (off < cchMax && (b = g_auchDigits[(unsigned char)psz[off]]) < 10);
1010 if (!fPositiveExp)
1011 iExponent = -iExponent;
1012 cchMax -= off;
1013 psz += off;
1014 }
1015 if (fExpOverflow || iExponent <= -65536 || iExponent >= 65536)
1016 return rtStrToLongDoubleReturnOverflow(pszValue, ppszNext, cchMax, fPositive, iExponent, iRetType, pRet);
1017 }
1018 }
1019
1020 /* If the mantissa was all zeros, we can return zero now that we're past the exponent. */
1021 if (!fSeenNonZeroDigit)
1022 return rtStrToLongDoubleReturnZero(psz, ppszNext, cchMax, fPositive, VINF_SUCCESS, iRetType, pRet);
1023
1024 /*
1025 * Adjust the expontent so we've got all digits to the left of the decimal point.
1026 */
1027 iExponent -= cFractionDigits * uExpDigitFactor;
1028
1029 /*
1030 * Drop digits we won't translate.
1031 */
1032 if (cDigits > cMaxDigits)
1033 {
1034 iExponent += (cDigits - cMaxDigits) * uExpDigitFactor;
1035 cDigits = cMaxDigits;
1036 }
1037
1038 /*
1039 * Strip least significant zero digits.
1040 */
1041 while (cDigits > 0 && abDigits[cDigits - 1] == 0)
1042 {
1043 cDigits--;
1044 iExponent += uExpDigitFactor;
1045 }
1046
1047 /*
1048 * The hexadecimal is relatively straight forward.
1049 */
1050 if (uBase == 16)
1051 {
1052 uint64_t uMantissa = 0;
1053 for (unsigned iDigit = 0; iDigit < cDigits; iDigit++)
1054 {
1055 uMantissa |= (uint64_t)abDigits[iDigit] << (64 - 4 - iDigit * 4);
1056 iExponent += 4;
1057 }
1058 Assert(uMantissa != 0);
1059
1060 /* Shift to the left till the most significant bit is 1. */
1061 if (!(uMantissa & RT_BIT_64(63)))
1062 {
1063 unsigned cShift = 64 - ASMBitLastSetU64(uMantissa);
1064 uMantissa <<= cShift;
1065 iExponent -= cShift;
1066 Assert(uMantissa & RT_BIT_64(63));
1067 }
1068
1069 /* Account for the 1 left of the decimal point. */
1070 iExponent--;
1071
1072 /*
1073 * Produce the return value.
1074 */
1075 return rtStrToLongDoubleReturnValue(psz, ppszNext, cchMax, fPositive, uMantissa, iExponent, iRetType, pRet);
1076 }
1077
1078 /*
1079 * For the decimal format, we'll rely on the floating point conversion of
1080 * the compiler/CPU for the mantissa.
1081 */
1082 uint64_t uMantissa = 0;
1083 for (unsigned iDigit = 0; iDigit < cDigits; iDigit++)
1084 {
1085 uMantissa *= 10;
1086 uMantissa += abDigits[iDigit];
1087 }
1088 Assert(uMantissa != 0);
1089
1090 LONG_DOUBLE_U_T uTmp;
1091 uTmp.r = fPositive ? (long double)uMantissa : -(long double)uMantissa;
1092
1093 /*
1094 * Here comes the fun part, scaling it according to the power of 10 exponent.
1095 * We only need to consider overflows and underflows when scaling, when
1096 * iExponent is zero we can be sure the target type can handle the result.
1097 */
1098 if (iExponent != 0)
1099 {
1100 rtStrToLongDoubleExp10(&uTmp, iExponent);
1101#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
1102 if (!RTFLOAT80U_IS_NORMAL(&uTmp))
1103#else
1104 if (!RTFLOAT64U_IS_NORMAL(&uTmp))
1105#endif
1106 {
1107#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
1108 if (RTFLOAT80U_IS_DENORMAL(&uTmp) && iRetType == RET_TYPE_LONG_DOUBLE)
1109#else
1110 if (RTFLOAT64U_IS_SUBNORMAL(&uTmp) && iRetType != RET_TYPE_FLOAT)
1111#endif
1112 return rtStrToLongDoubleReturnSubnormal(psz, ppszNext, cchMax, &uTmp, iRetType, pRet);
1113 return rtStrToLongDoubleReturnOverflow(psz, ppszNext, cchMax, fPositive, iExponent, iRetType, pRet);
1114 }
1115 }
1116
1117 /*
1118 * We've got a normal value in uTmp when we get here, just repack it in the
1119 * target format and return.
1120 */
1121#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
1122 Assert(RTFLOAT80U_IS_NORMAL(&uTmp));
1123 if (iRetType == RET_TYPE_LONG_DOUBLE)
1124 {
1125 pRet->lrd = uTmp;
1126 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, VINF_SUCCESS);
1127 }
1128 fPositive = uTmp.s.fSign;
1129 iExponent = uTmp.s.uExponent - RTFLOAT80U_EXP_BIAS;
1130 uMantissa = uTmp.s.uMantissa;
1131#else
1132 Assert(RTFLOAT64U_IS_NORMAL(&uTmp));
1133 if ( iRetType == RET_TYPE_DOUBLE
1134 || iRetType == RET_TYPE_LONG_DOUBLE)
1135 {
1136 pRet->rd = uTmp;
1137 return rtStrToLongDoubleReturnChecks(psz, ppszNext, cchMax, VINF_SUCCESS);
1138 }
1139 fPositive = uTmp.s64.fSign;
1140 iExponent = uTmp.s64.uExponent - RTFLOAT64U_EXP_BIAS;
1141 uMantissa = uTmp.s64.uFraction | RT_BIT_64(RTFLOAT64U_FRACTION_BITS);
1142#endif
1143 return rtStrToLongDoubleReturnValue(psz, ppszNext, cchMax, fPositive, uMantissa, iExponent, iRetType, pRet);
1144}
1145
1146
1147RTDECL(int) RTStrToLongDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, long double *plrd)
1148{
1149 FLOATUNION u;
1150 int rc = rtStrToLongDoubleWorker(pszValue, ppszNext, cchMax, RET_TYPE_LONG_DOUBLE, &u);
1151 if (plrd)
1152#ifdef RT_COMPILER_WITH_80BIT_LONG_DOUBLE
1153 *plrd = u.lrd.lrd;
1154#else
1155 *plrd = u.rd.rd;
1156#endif
1157 return rc;
1158}
1159
1160
1161RTDECL(int) RTStrToDoubleEx(const char *pszValue, char **ppszNext, size_t cchMax, double *prd)
1162{
1163 FLOATUNION u;
1164 int rc = rtStrToLongDoubleWorker(pszValue, ppszNext, cchMax, RET_TYPE_DOUBLE, &u);
1165 if (prd)
1166 *prd = u.rd.rd;
1167 return rc;
1168}
1169
1170
1171RTDECL(int) RTStrToFloatEx(const char *pszValue, char **ppszNext, size_t cchMax, float *pr)
1172{
1173 FLOATUNION u;
1174 int rc = rtStrToLongDoubleWorker(pszValue, ppszNext, cchMax, RET_TYPE_FLOAT, &u);
1175 if (pr)
1176 *pr = u.r.r;
1177 return rc;
1178}
1179
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