diff options
| author | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-03-17 20:51:20 +0000 |
|---|---|---|
| committer | vboxsync <vboxsync@cfe28804-0f27-0410-a406-dd0f0b0b656f> | 2022-03-17 20:51:20 +0000 |
| commit | 5708348ebb1f5afb4517d6dcef356b2048eb16ed (patch) | |
| tree | 02c2291cbcfc2f7909b932d56e75a1a2e98f731f /src/VBox/Runtime/common/string/strformatfloat.cpp | |
| parent | 8f9d9a7df42f63133aa63a8ae9acfec2dc0a05b4 (diff) | |
| download | VirtualBox-svn-5708348ebb1f5afb4517d6dcef356b2048eb16ed.tar.gz | |
IPRT: Added RTStrFormatR64 and RTStrFormatR32 and split out the floating point formatting from strformatnum.cpp. bugref:9898
git-svn-id: https://www.virtualbox.org/svn/vbox/trunk@94300 cfe28804-0f27-0410-a406-dd0f0b0b656f
Diffstat (limited to 'src/VBox/Runtime/common/string/strformatfloat.cpp')
| -rw-r--r-- | src/VBox/Runtime/common/string/strformatfloat.cpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/string/strformatfloat.cpp b/src/VBox/Runtime/common/string/strformatfloat.cpp new file mode 100644 index 00000000000..704b24baec9 --- /dev/null +++ b/src/VBox/Runtime/common/string/strformatfloat.cpp @@ -0,0 +1,337 @@ +/* $Id$ */ +/** @file + * IPRT - String Formatter, Floating Point Numbers (simple approach). + */ + +/* + * Copyright (C) 2010-2022 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP RTLOGGROUP_STRING +#include <iprt/string.h> +#include "internal/iprt.h" + +#include <iprt/assert.h> +#include <iprt/errcore.h> +#include "internal/string.h" + + +/** + * Helper for rtStrFormatR80Worker that copies out the resulting string. + */ +static ssize_t rtStrFormatCopyOutStr(char *pszBuf, size_t cbBuf, const char *pszSrc, size_t cchSrc) +{ + if (cchSrc < cbBuf) + { + memcpy(pszBuf, pszSrc, cchSrc); + pszBuf[cchSrc] = '\0'; + return cchSrc; + } + if (cbBuf) + { + memcpy(pszBuf, pszSrc, cbBuf - 1); + pszBuf[cbBuf - 1] = '\0'; + } + return VERR_BUFFER_OVERFLOW; +} + + +RTDECL(ssize_t) RTStrFormatR32(char *pszBuf, size_t cbBuf, PCRTFLOAT32U pr32Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags) +{ + RT_NOREF(cchWidth, cchPrecision); + + /* + * Handle some special values that does require any value annotating. + */ + bool const fSign = pr32Value->s.fSign; + if (RTFLOAT32U_IS_ZERO(pr32Value)) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0")); + if (RTFLOAT32U_IS_INF(pr32Value)) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf")); + + /* + * Output sign first. + */ + char szTmp[80]; + char *pszTmp = szTmp; + if (fSign) + *pszTmp++ = '-'; + else + *pszTmp++ = '+'; + + /* + * Normal? + */ + uint16_t const uExponent = pr32Value->s.uExponent; + uint32_t const uFraction = pr32Value->s.uFraction; + if (RTFLOAT32U_IS_NORMAL(pr32Value)) + { + *pszTmp++ = '1'; + *pszTmp++ = 'm'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT); + + *pszTmp++ = '^'; + pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT32U_EXP_BIAS, 10, 0, 0, + RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + /* + * Subnormal? + */ + else if (RTFLOAT32U_IS_SUBNORMAL(pr32Value)) + { + *pszTmp++ = '0'; + *pszTmp++ = 'm'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT); + if (fFlags & RTSTR_F_SPECIAL) + pszTmp = (char *)memcpy(pszTmp, "[SubN]", 6) + 6; + } + /* + * NaN. + */ + else + { + Assert(RTFLOAT32U_IS_NAN(pr32Value)); + if (!(fFlags & RTSTR_F_SPECIAL)) + return rtStrFormatCopyOutStr(pszBuf, cbBuf, + RTFLOAT32U_IS_SIGNALLING_NAN(pr32Value) + ? (fSign ? "-SNan[" : "+SNan[") : fSign ? "-QNan[" : "+QNan[", 5); + *pszTmp++ = RTFLOAT32U_IS_SIGNALLING_NAN(pr32Value) ? 'S' : 'Q'; + *pszTmp++ = 'N'; + *pszTmp++ = 'a'; + *pszTmp++ = 'N'; + *pszTmp++ = '['; + *pszTmp++ = '.'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + (RTFLOAT32U_FRACTION_BITS + 3) / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_32BIT); + *pszTmp++ = ']'; + } + return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]); +} + + + + +RTDECL(ssize_t) RTStrFormatR64(char *pszBuf, size_t cbBuf, PCRTFLOAT64U pr64Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags) +{ + RT_NOREF(cchWidth, cchPrecision); + + /* + * Handle some special values that does require any value annotating. + */ + bool const fSign = pr64Value->s.fSign; + if (RTFLOAT64U_IS_ZERO(pr64Value)) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0")); + if (RTFLOAT64U_IS_INF(pr64Value)) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf")); + + /* + * Output sign first. + */ + char szTmp[160]; + char *pszTmp = szTmp; + if (fSign) + *pszTmp++ = '-'; + else + *pszTmp++ = '+'; + + /* + * Normal? + */ + uint16_t const uExponent = pr64Value->s.uExponent; + uint64_t const uFraction = RT_MAKE_U64(pr64Value->s.uFractionLow, pr64Value->s.uFractionHigh); + if (RTFLOAT64U_IS_NORMAL(pr64Value)) + { + *pszTmp++ = '1'; + *pszTmp++ = 'm'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT); + + *pszTmp++ = '^'; + pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT64U_EXP_BIAS, 10, 0, 0, + RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + } + /* + * Subnormal? + */ + else if (RTFLOAT64U_IS_SUBNORMAL(pr64Value)) + { + *pszTmp++ = '0'; + *pszTmp++ = 'm'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT); + if (fFlags & RTSTR_F_SPECIAL) + pszTmp = (char *)memcpy(pszTmp, "[SubN]", 6) + 6; + } + /* + * NaN. + */ + else + { + Assert(RTFLOAT64U_IS_NAN(pr64Value)); + if (!(fFlags & RTSTR_F_SPECIAL)) + return rtStrFormatCopyOutStr(pszBuf, cbBuf, + RTFLOAT64U_IS_SIGNALLING_NAN(pr64Value) + ? (fSign ? "-SNan[" : "+SNan[") : fSign ? "-QNan[" : "+QNan[", 5); + *pszTmp++ = RTFLOAT64U_IS_SIGNALLING_NAN(pr64Value) ? 'S' : 'Q'; + *pszTmp++ = 'N'; + *pszTmp++ = 'a'; + *pszTmp++ = 'N'; + *pszTmp++ = '['; + *pszTmp++ = '.'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT); + *pszTmp++ = ']'; + } + return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]); +} + + +/** + * Common worker for RTStrFormatR80 and RTStrFormatR80u2. + */ +static ssize_t rtStrFormatR80Worker(char *pszBuf, size_t cbBuf, bool const fSign, bool const fInteger, + uint64_t const uFraction, uint16_t const uExponent, uint32_t fFlags) +{ + char szTmp[160]; + + /* + * Output sign first. + */ + char *pszTmp = szTmp; + if (fSign) + *pszTmp++ = '-'; + else + *pszTmp++ = '+'; + + /* + * Then check for special numbers (indicated by expontent). + */ + bool fDenormal = false; + if (uExponent == 0) + { + /* Zero? */ + if ( !uFraction + && !fInteger) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+0")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-0")); + fDenormal = true; + } + else if (uExponent == RTFLOAT64U_EXP_MAX) + { + if (!fInteger) + { + if (!uFraction) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoInf")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoInf")); + if (!(fFlags & RTSTR_F_SPECIAL)) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+PseudoNan")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-PseudoNan")); + pszTmp = (char *)memcpy(pszTmp, "PseudoNan[", 10) + 10; + } + else if (!(uFraction & RT_BIT_64(62))) + { + if (!(uFraction & (RT_BIT_64(62) - 1))) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Inf")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Inf")); + if (!(fFlags & RTSTR_F_SPECIAL)) + return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("SNan")); + pszTmp = (char *)memcpy(pszTmp, "SNan[", 5) + 5; + } + else + { + if (!(uFraction & (RT_BIT_64(62) - 1))) + return fSign + ? rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("+Ind")) + : rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("-Ind")); + if (!(fFlags & RTSTR_F_SPECIAL)) + return rtStrFormatCopyOutStr(pszBuf, cbBuf, RT_STR_TUPLE("QNan")); + pszTmp = (char *)memcpy(pszTmp, "QNan[", 5) + 5; + } + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT); + *pszTmp++ = ']'; + return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]); + } + + /* + * Format the mantissa and exponent. + */ + *pszTmp++ = fInteger ? '1' : '0'; + *pszTmp++ = 'm'; + pszTmp += RTStrFormatNumber(pszTmp, uFraction, 16, 2 + RTFLOAT64U_FRACTION_BITS / 4, 0, + RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD | RTSTR_F_64BIT); + + *pszTmp++ = '^'; + pszTmp += RTStrFormatNumber(pszTmp, (int32_t)uExponent - RTFLOAT64U_EXP_BIAS, 10, 0, 0, + RTSTR_F_ZEROPAD | RTSTR_F_32BIT | RTSTR_F_VALSIGNED); + if (fDenormal && (fFlags & RTSTR_F_SPECIAL)) + { + if (fInteger) + pszTmp = (char *)memcpy(pszTmp, "[PDn]", 5) + 5; + else + pszTmp = (char *)memcpy(pszTmp, "[Den]", 5) + 5; + } + return rtStrFormatCopyOutStr(pszBuf, cbBuf, szTmp, pszTmp - &szTmp[0]); +} + + +RTDECL(ssize_t) RTStrFormatR80u2(char *pszBuf, size_t cbBuf, PCRTFLOAT80U2 pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags) +{ + RT_NOREF(cchWidth, cchPrecision); +#ifdef RT_COMPILER_GROKS_64BIT_BITFIELDS + return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj64.fSign, pr80Value->sj64.fInteger, + pr80Value->sj64.uFraction, pr80Value->sj64.uExponent, fFlags); +#else + return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->sj.fSign, pr80Value->sj.fInteger, + RT_MAKE_U64(pr80Value->sj.u32FractionLow, pr80Value->sj.u31FractionHigh), + pr80Value->sj.uExponent, fFlags); +#endif +} + + +RTDECL(ssize_t) RTStrFormatR80(char *pszBuf, size_t cbBuf, PCRTFLOAT80U pr80Value, signed int cchWidth, + signed int cchPrecision, uint32_t fFlags) +{ + RT_NOREF(cchWidth, cchPrecision); + return rtStrFormatR80Worker(pszBuf, cbBuf, pr80Value->s.fSign, pr80Value->s.uMantissa >> 63, + pr80Value->s.uMantissa & (RT_BIT_64(63) - 1), pr80Value->s.uExponent, fFlags); +} + |
