// Tencent is pleased to support the open source community by making RapidJSON available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_
#include "../rapidjson.h"
#if defined (_MSC_VER) &&
defined (_M_AMD64)
#include <intrin.h>
#pragma intrinsic(_BitScanReverse64)
#pragma intrinsic(_umul128)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
struct DiyFp {
DiyFp() {}
DiyFp(uint64_t fp,
int exp) : f(fp), e(exp) {}
explicit DiyFp(
double d) {
union {
double d;
uint64_t u64;
} u = { d };
int biased_e =
static_cast <
int >((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e !=
0 ) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent +
1 ;
}
}
DiyFp
operator -(
const DiyFp& rhs)
const {
return DiyFp(f - rhs.f, e);
}
DiyFp
operator *(
const DiyFp& rhs)
const {
#if defined (_MSC_VER) &&
defined (_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(
1 ) <<
63 ))
// rounding
h++;
return DiyFp(h, e + rhs.e +
64 );
#elif (__GNUC__ >
4 || (__GNUC__ ==
4 && __GNUC_MINOR__ >=
6 )) &&
defined (__x86_64__)
__extension__
typedef unsigned __int128 uint128;
uint128 p =
static_cast <uint128>(f) *
static_cast <uint128>(rhs.f);
uint64_t h =
static_cast <uint64_t>(p >>
64 );
uint64_t l =
static_cast <uint64_t>(p);
if (l & (uint64_t(
1 ) <<
63 ))
// rounding
h++;
return DiyFp(h, e + rhs.e +
64 );
#else
const uint64_t M32 =
0 xFFFFFFFF;
const uint64_t a = f >>
32 ;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >>
32 ;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >>
32 ) + (ad & M32) + (bc & M32);
tmp +=
1 U <<
31 ;
/// mult_round
return DiyFp(ac + (ad >>
32 ) + (bc >>
32 ) + (tmp >>
32 ), e + rhs.e +
64 );
#endif
}
DiyFp Normalize()
const {
#if defined (_MSC_VER) &&
defined (_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (
63 - index), e - (
63 - index));
#elif defined (__GNUC__) && __GNUC__ >=
4
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *
this ;
while (!(res.f & (
static_cast <uint64_t>(
1 ) <<
63 ))) {
res.f <<=
1 ;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary()
const {
DiyFp res = *
this ;
while (!(res.f & (kDpHiddenBit <<
1 ))) {
res.f <<=
1 ;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize -
2 );
res.e = res.e - (kDiySignificandSize - kDpSignificandSize -
2 );
return res;
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus)
const {
DiyFp pl = DiyFp((f <<
1 ) +
1 , e -
1 ).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f <<
2 ) -
1 , e -
2 ) : DiyFp((f <<
1 ) -
1 , e -
1 );
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
double ToDouble()
const {
union {
double d;
uint64_t u64;
}u;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) ==
0 ) ?
0 :
static_cast <uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize =
64 ;
static const int kDpSignificandSize =
52 ;
static const int kDpExponentBias =
0 x3FF + kDpSignificandSize;
static const int kDpMaxExponent =
0 x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias +
1 ;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(
0 x7FF00000,
0 x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(
0 x000FFFFF,
0 xFFFFFFFF)
;
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0 x00100000, 0 x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPowerByIndex(size_t index) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0 xfa8fd5a0, 0 x081c0288), RAPIDJSON_UINT64_C2(0 xbaaee17f, 0 xa23ebf76),
RAPIDJSON_UINT64_C2(0 x8b16fb20, 0 x3055ac76), RAPIDJSON_UINT64_C2(0 xcf42894a, 0 x5dce35ea),
RAPIDJSON_UINT64_C2(0 x9a6bb0aa, 0 x55653b2d), RAPIDJSON_UINT64_C2(0 xe61acf03, 0 x3d1a45df),
RAPIDJSON_UINT64_C2(0 xab70fe17, 0 xc79ac6ca), RAPIDJSON_UINT64_C2(0 xff77b1fc, 0 xbebcdc4f),
RAPIDJSON_UINT64_C2(0 xbe5691ef, 0 x416bd60c), RAPIDJSON_UINT64_C2(0 x8dd01fad, 0 x907ffc3c),
RAPIDJSON_UINT64_C2(0 xd3515c28, 0 x31559a83), RAPIDJSON_UINT64_C2(0 x9d71ac8f, 0 xada6c9b5),
RAPIDJSON_UINT64_C2(0 xea9c2277, 0 x23ee8bcb), RAPIDJSON_UINT64_C2(0 xaecc4991, 0 x4078536d),
RAPIDJSON_UINT64_C2(0 x823c1279, 0 x5db6ce57), RAPIDJSON_UINT64_C2(0 xc2109436, 0 x4dfb5637),
RAPIDJSON_UINT64_C2(0 x9096ea6f, 0 x3848984f), RAPIDJSON_UINT64_C2(0 xd77485cb, 0 x25823ac7),
RAPIDJSON_UINT64_C2(0 xa086cfcd, 0 x97bf97f4), RAPIDJSON_UINT64_C2(0 xef340a98, 0 x172aace5),
RAPIDJSON_UINT64_C2(0 xb23867fb, 0 x2a35b28e), RAPIDJSON_UINT64_C2(0 x84c8d4df, 0 xd2c63f3b),
RAPIDJSON_UINT64_C2(0 xc5dd4427, 0 x1ad3cdba), RAPIDJSON_UINT64_C2(0 x936b9fce, 0 xbb25c996),
RAPIDJSON_UINT64_C2(0 xdbac6c24, 0 x7d62a584), RAPIDJSON_UINT64_C2(0 xa3ab6658, 0 x0d5fdaf6),
RAPIDJSON_UINT64_C2(0 xf3e2f893, 0 xdec3f126), RAPIDJSON_UINT64_C2(0 xb5b5ada8, 0 xaaff80b8),
RAPIDJSON_UINT64_C2(0 x87625f05, 0 x6c7c4a8b), RAPIDJSON_UINT64_C2(0 xc9bcff60, 0 x34c13053),
RAPIDJSON_UINT64_C2(0 x964e858c, 0 x91ba2655), RAPIDJSON_UINT64_C2(0 xdff97724, 0 x70297ebd),
RAPIDJSON_UINT64_C2(0 xa6dfbd9f, 0 xb8e5b88f), RAPIDJSON_UINT64_C2(0 xf8a95fcf, 0 x88747d94),
RAPIDJSON_UINT64_C2(0 xb9447093, 0 x8fa89bcf), RAPIDJSON_UINT64_C2(0 x8a08f0f8, 0 xbf0f156b),
RAPIDJSON_UINT64_C2(0 xcdb02555, 0 x653131b6), RAPIDJSON_UINT64_C2(0 x993fe2c6, 0 xd07b7fac),
RAPIDJSON_UINT64_C2(0 xe45c10c4, 0 x2a2b3b06), RAPIDJSON_UINT64_C2(0 xaa242499, 0 x697392d3),
RAPIDJSON_UINT64_C2(0 xfd87b5f2, 0 x8300ca0e), RAPIDJSON_UINT64_C2(0 xbce50864, 0 x92111aeb),
RAPIDJSON_UINT64_C2(0 x8cbccc09, 0 x6f5088cc), RAPIDJSON_UINT64_C2(0 xd1b71758, 0 xe219652c),
RAPIDJSON_UINT64_C2(0 x9c400000, 0 x00000000), RAPIDJSON_UINT64_C2(0 xe8d4a510, 0 x00000000),
RAPIDJSON_UINT64_C2(0 xad78ebc5, 0 xac620000), RAPIDJSON_UINT64_C2(0 x813f3978, 0 xf8940984),
RAPIDJSON_UINT64_C2(0 xc097ce7b, 0 xc90715b3), RAPIDJSON_UINT64_C2(0 x8f7e32ce, 0 x7bea5c70),
RAPIDJSON_UINT64_C2(0 xd5d238a4, 0 xabe98068), RAPIDJSON_UINT64_C2(0 x9f4f2726, 0 x179a2245),
RAPIDJSON_UINT64_C2(0 xed63a231, 0 xd4c4fb27), RAPIDJSON_UINT64_C2(0 xb0de6538, 0 x8cc8ada8),
RAPIDJSON_UINT64_C2(0 x83c7088e, 0 x1aab65db), RAPIDJSON_UINT64_C2(0 xc45d1df9, 0 x42711d9a),
RAPIDJSON_UINT64_C2(0 x924d692c, 0 xa61be758), RAPIDJSON_UINT64_C2(0 xda01ee64, 0 x1a708dea),
RAPIDJSON_UINT64_C2(0 xa26da399, 0 x9aef774a), RAPIDJSON_UINT64_C2(0 xf209787b, 0 xb47d6b85),
RAPIDJSON_UINT64_C2(0 xb454e4a1, 0 x79dd1877), RAPIDJSON_UINT64_C2(0 x865b8692, 0 x5b9bc5c2),
RAPIDJSON_UINT64_C2(0 xc83553c5, 0 xc8965d3d), RAPIDJSON_UINT64_C2(0 x952ab45c, 0 xfa97a0b3),
RAPIDJSON_UINT64_C2(0 xde469fbd, 0 x99a05fe3), RAPIDJSON_UINT64_C2(0 xa59bc234, 0 xdb398c25),
RAPIDJSON_UINT64_C2(0 xf6c69a72, 0 xa3989f5c), RAPIDJSON_UINT64_C2(0 xb7dcbf53, 0 x54e9bece),
RAPIDJSON_UINT64_C2(0 x88fcf317, 0 xf22241e2), RAPIDJSON_UINT64_C2(0 xcc20ce9b, 0 xd35c78a5),
RAPIDJSON_UINT64_C2(0 x98165af3, 0 x7b2153df), RAPIDJSON_UINT64_C2(0 xe2a0b5dc, 0 x971f303a),
RAPIDJSON_UINT64_C2(0 xa8d9d153, 0 x5ce3b396), RAPIDJSON_UINT64_C2(0 xfb9b7cd9, 0 xa4a7443c),
RAPIDJSON_UINT64_C2(0 xbb764c4c, 0 xa7a44410), RAPIDJSON_UINT64_C2(0 x8bab8eef, 0 xb6409c1a),
RAPIDJSON_UINT64_C2(0 xd01fef10, 0 xa657842c), RAPIDJSON_UINT64_C2(0 x9b10a4e5, 0 xe9913129),
RAPIDJSON_UINT64_C2(0 xe7109bfb, 0 xa19c0c9d), RAPIDJSON_UINT64_C2(0 xac2820d9, 0 x623bf429),
RAPIDJSON_UINT64_C2(0 x80444b5e, 0 x7aa7cf85), RAPIDJSON_UINT64_C2(0 xbf21e440, 0 x03acdd2d),
RAPIDJSON_UINT64_C2(0 x8e679c2f, 0 x5e44ff8f), RAPIDJSON_UINT64_C2(0 xd433179d, 0 x9c8cb841),
RAPIDJSON_UINT64_C2(0 x9e19db92, 0 xb4e31ba9), RAPIDJSON_UINT64_C2(0 xeb96bf6e, 0 xbadf77d9),
RAPIDJSON_UINT64_C2(0 xaf87023b, 0 x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220 , -1193 , -1166 , -1140 , -1113 , -1087 , -1060 , -1034 , -1007 , -980 ,
-954 , -927 , -901 , -874 , -847 , -821 , -794 , -768 , -741 , -715 ,
-688 , -661 , -635 , -608 , -582 , -555 , -529 , -502 , -475 , -449 ,
-422 , -396 , -369 , -343 , -316 , -289 , -263 , -236 , -210 , -183 ,
-157 , -130 , -103 , -77 , -50 , -24 , 3 , 30 , 56 , 83 ,
109 , 136 , 162 , 189 , 216 , 242 , 269 , 295 , 322 , 348 ,
375 , 402 , 428 , 455 , 481 , 508 , 534 , 561 , 588 , 614 ,
641 , 667 , 694 , 720 , 747 , 774 , 800 , 827 , 853 , 880 ,
907 , 933 , 960 , 986 , 1013 , 1039 , 1066
};
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline DiyFp GetCachedPower(int e, int * K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0 .30102999566398114 + 347 ; // dk must be positive, so can do ceiling in positive
int k = static_cast <int >(dk);
if (dk - k > 0 .0 )
k++;
unsigned index = static_cast <unsigned >((k >> 3 ) + 1 );
*K = -(-348 + static_cast <int >(index << 3 )); // decimal exponent no need lookup table
return GetCachedPowerByIndex(index);
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (static_cast <unsigned >(exp) + 348 u) / 8 u;
*outExp = -348 + static_cast <int >(index) * 8 ;
return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DIYFP_H_
Messung V0.5 in Prozent C=80 H=97 G=88
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-06-17)
¤
*© Formatika GbR, Deutschland