Improved precision of binary-to-decimal conversion of floating-point values
on all systems but especially non-x86 systems that lake extended precision hardward floating point. FossilOrigin-Name: 32befb224b254639e756fd493f300507ff60c5222e00a7338dbcd39140133964
This commit is contained in:
commit
c9f240cea4
36
manifest
36
manifest
@ -1,5 +1,5 @@
|
||||
C Add\ssupport\sfor\ssqlite3_stmt_scanstatus_v2()\sprofiling\sof\sGROUP\sBY\sclauses\sthat\suse\sa\stemp\sb-tree,\sand\sfor\ssub-queries\simplemented\sas\sco-routines.
|
||||
D 2023-06-30T18:31:37.545
|
||||
C Improved\sprecision\sof\sbinary-to-decimal\sconversion\sof\sfloating-point\svalues\non\sall\ssystems\sbut\sespecially\snon-x86\ssystems\sthat\slake\sextended\sprecision\nhardward\sfloating\spoint.
|
||||
D 2023-07-03T15:03:59.842
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@ -590,8 +590,8 @@ F src/delete.c cd5f5cd06ed0b6a882ec1a8c2a0d73b3cecb28479ad19e9931c4706c5e2182be
|
||||
F src/expr.c 8d1656b65e26af3e34f78e947ac423f0d20c214ed25a67486e433bf16ca6b543
|
||||
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
|
||||
F src/fkey.c a7fcbf7e66d14dbb73cf49f31489ebf66d0e6006c62b95246924a3bae9f37b36
|
||||
F src/func.c 6b4804738b4d869f40625958b476a8f964d3df65b626e72a530d76051863cf32
|
||||
F src/global.c bd0892ade7289f6e20bff44c07d06371f2ff9b53cea359e7854b9b72f65adc30
|
||||
F src/func.c 6028c160f693bdd018b651b5468a0a8e790f4e01e200796916b2d10a5d3237aa
|
||||
F src/global.c a16553245e315ee0cda8f9b0bf744efef9dc99f86e9d77f58975ea58824ded92
|
||||
F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
@ -600,7 +600,7 @@ F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/json.c 14c474fb1249a46eb44e878e2361f36abfe686b134039b0d1883d93d61505b4a
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 176d6b2cb18a6ad73b133db17f6fc351c4d9a2d510deebdb76c22bde9cfd1465
|
||||
F src/main.c 5fd4b65d61ae6155f36756ed508a39b38b49355b031188961e8d923f43f4bc49
|
||||
F src/main.c 7bc04e53851c813454b73083e21f84fd8a6d3d32eaa242bb4974eda870e28fef
|
||||
F src/malloc.c 47b82c5daad557d9b963e3873e99c22570fb470719082c6658bf64e3012f7d23
|
||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
|
||||
@ -633,21 +633,21 @@ F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
F src/pragma.c 37b8fb02d090262280c86e1e2654bf59d8dbfbfe8dc6733f2b968a11374c095a
|
||||
F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
|
||||
F src/prepare.c d6c4354f8ea0dc06962fbabc4b68c4471a45276a2918c929be00f9f537f69eb1
|
||||
F src/printf.c a87473be34fa2acafa27692b8ae078275c7e23360956c93c07ff22f5d609cbd7
|
||||
F src/printf.c 84b7b4b647f336934a5ab2e7f0c52555833cc0778d2d60e016cca52ee8c6cd8f
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c 37953a5f36c60bea413c3c04efcd433b6177009f508ef2ace0494728912fe2e9
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 3ab1186290a311a8ceed1286c0e286209f7fe97b2d02c7593258004ce295dd88
|
||||
F src/shell.c.in 2c02c819349de410d63fcc0217763dfe5a42dbe58f2d68046d4ea8a376d12c26
|
||||
F src/sqlite.h.in 3076d78836b6dac53b3ab0875fc8fd15bca8077aad4d33c85336e05af6aef8c7
|
||||
F src/shell.c.in e01d7e1d8a6b158320c97c955e1b14763289b82a73e3a155fa8efe0d546f0567
|
||||
F src/sqlite.h.in f999ef3642f381d69679b2516b430dbcb6c5a2a951b7f5e43dc4751b474a5774
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
|
||||
F src/sqliteInt.h b677ba33397479f9a2fa1223fcd24b561cc8c77c7d073798f7b7118e15d69dbb
|
||||
F src/sqliteInt.h f6c5470b7db42318a3de1115757e94b76570ad7697ac547823e01f1166756f1d
|
||||
F src/sqliteLimit.h 33b1c9baba578d34efe7dfdb43193b366111cdf41476b1e82699e14c11ee1fb6
|
||||
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
F src/tclsqlite.c ecbc3c99c0d0c3ed122a913f143026c26d38d57f33e06bb71185dd5c1efe37cd
|
||||
F src/test1.c 64b8462099618a6243f63ba701eea8913046cd7377a7a77a7e3a0ada42219275
|
||||
F src/test1.c 86099cc02f22069d75b04ae9c105acde0edbce9033d5ac37262bad2e461e6000
|
||||
F src/test2.c 827446e259a3b7ab949da1542953edda7b5117982576d3e6f1c24a0dd20a5cef
|
||||
F src/test3.c e5178558c41ff53236ae0271e9acb3d6885a94981d2eb939536ee6474598840e
|
||||
F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
|
||||
@ -705,7 +705,7 @@ F src/trigger.c ad6ab9452715fa9a8075442e15196022275b414b9141b566af8cdb7a1605f2b0
|
||||
F src/update.c 0aa36561167a7c40d01163238c297297962f31a15a8d742216b3c37cdf25f731
|
||||
F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145
|
||||
F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0
|
||||
F src/util.c 4264102045fdb36e9af3ff361e390a5f7a76342a2bd7069e55d8ad332026d6b5
|
||||
F src/util.c 452f1e5e4a85b7869daf15d9b6468ac754836467004fa04c3419f2bd628eb6ad
|
||||
F src/vacuum.c 604fcdaebe76f3497c855afcbf91b8fa5046b32de3045bab89cc008d68e40104
|
||||
F src/vdbe.c 74282a947234513872a83b0bab1b8c644ece64b3e27b053ef17677c8ff9c81e0
|
||||
F src/vdbe.h 41485521f68e9437fdb7ec4a90f9d86ab294e9bb8281e33b235915e29122cfc0
|
||||
@ -775,7 +775,7 @@ F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b
|
||||
F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7
|
||||
F test/async4.test 1787e3952128aa10238bf39945126de7ca23685a
|
||||
F test/async5.test 383ab533fdb9f7ad228cc99ee66e1acb34cc0dc0
|
||||
F test/atof1.test 1f24a6f16e44892848298bd8e488159d4a60cf47be003d32747a136103c9bbac
|
||||
F test/atof1.test 191ce0d7b0d527aafeafe659c31e2433e430324b5ebce3fb066178b4d9035767
|
||||
F test/atomic.test 065a453dde33c77ff586d91ccaa6ed419829d492dbb1a5694b8a09f3f9d7d061
|
||||
F test/atomic2.test b6863b4aa552543874f80b42fb3063f1c8c2e3d8e56b6562f00a3cc347b5c1da
|
||||
F test/atrc.c c388fac43dbba05c804432a7135ae688b32e8f25818e9994ffba4b64cf60c27c
|
||||
@ -1014,6 +1014,7 @@ F test/fkey8.test 51deda7f1a1448bca95875e4a6e1a3a75b4bd7215e924e845bd60de60e4d84
|
||||
F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749
|
||||
F test/fordelete.test ba98f14446b310f9c9d935b97ec748753d0144a28b356ba30d1f4f6958fdde5c
|
||||
F test/format4.test eeae341953db8b6bda7f549044797c3278a6cc345d11ada81471671b654f8ef4
|
||||
F test/fpconv1.test d5d8aa0c427533006c112fb1957cdd1ea68c1d0709470dabb9ca02c2e4c06ad8
|
||||
F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c
|
||||
F test/fts3.test 672a040ea57036fb4b6fdc09027c18d7d24ab654
|
||||
F test/fts3_common.tcl dffad248f9ce090800e272017d2898005c28ee6314fc1dd5550643a02666907a
|
||||
@ -1399,7 +1400,7 @@ F test/returningfault.test ae4c4b5e8745813287a359d9ccdb9d5c883c2e68afb18fb076793
|
||||
F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa
|
||||
F test/rollback2.test 3f3a4e20401825017df7e7671e9f31b6de5fae5620c2b9b49917f52f8c160a8f
|
||||
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
|
||||
F test/round1.test 1bb32cf3fc505eed9e86b5e523d07e15d4428189665524587512fbcc85d114bb
|
||||
F test/round1.test 29c3c9039936ed024d672f003c4d35ee11c14c0acb75c5f7d6188ff16190cfd4
|
||||
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
|
||||
F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81
|
||||
F test/rowid.test e29025be95baf6b32f0d5edef59a7633028325896a98f1caa8019559ca910350
|
||||
@ -2041,9 +2042,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P f936f101406069b29218c89a36581b4497226fb61906782ea368f12d943c901c 4e8718dc35dbbaf75f17265a88d14acd9750dc75efbadf41377f9c97e732009c
|
||||
R 4da01a7efae23c104b98c2eba70ec2ef
|
||||
T +closed 4e8718dc35dbbaf75f17265a88d14acd9750dc75efbadf41377f9c97e732009c
|
||||
U dan
|
||||
Z 8ca5997f8884b68f398b8d0f077d59ae
|
||||
P 7afad1f759f7ceda873c6d869422fd56fe4399c2d24d47ad9bc3b84b06d830d1 02ae6caff1f7925c696ad263fe78b1036364d24b6373e1baec10d53aafb14a12
|
||||
R c19a4cd19e732c53bd925a8fc2b0f976
|
||||
U drh
|
||||
Z d52b1cd0e5057b695ef6926f80a9c961
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
@ -1 +1 @@
|
||||
7afad1f759f7ceda873c6d869422fd56fe4399c2d24d47ad9bc3b84b06d830d1
|
||||
32befb224b254639e756fd493f300507ff60c5222e00a7338dbcd39140133964
|
36
src/func.c
36
src/func.c
@ -461,7 +461,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}else if( n==0 ){
|
||||
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
|
||||
}else{
|
||||
zBuf = sqlite3_mprintf("%.*f",n,r);
|
||||
zBuf = sqlite3_mprintf("%!.*f",n,r);
|
||||
if( zBuf==0 ){
|
||||
sqlite3_result_error_nomem(context);
|
||||
return;
|
||||
@ -2371,6 +2371,37 @@ static void signFunc(
|
||||
sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
/*
|
||||
** Implementation of fpdecode(x,y,z) function.
|
||||
**
|
||||
** x is a real number that is to be decoded. y is the precision.
|
||||
** z is the maximum real precision.
|
||||
*/
|
||||
static void fpdecodeFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
FpDecode s;
|
||||
double x;
|
||||
int y, z;
|
||||
char zBuf[100];
|
||||
UNUSED_PARAMETER(argc);
|
||||
assert( argc==3 );
|
||||
x = sqlite3_value_double(argv[0]);
|
||||
y = sqlite3_value_int(argv[1]);
|
||||
z = sqlite3_value_int(argv[2]);
|
||||
sqlite3FpDecode(&s, x, y, z);
|
||||
if( s.isSpecial==2 ){
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
|
||||
}else{
|
||||
sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
|
||||
}
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
#endif /* SQLITE_DEBUG */
|
||||
|
||||
/*
|
||||
** All of the FuncDef structures in the aBuiltinFunc[] array above
|
||||
** to the global function hash table. This occurs at start-time (as
|
||||
@ -2442,6 +2473,9 @@ void sqlite3RegisterBuiltinFunctions(void){
|
||||
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
|
||||
FUNCTION(char, -1, 0, 0, charFunc ),
|
||||
FUNCTION(abs, 1, 0, 0, absFunc ),
|
||||
#ifdef SQLITE_DEBUG
|
||||
FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
|
||||
#endif
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
FUNCTION(round, 1, 0, 0, roundFunc ),
|
||||
FUNCTION(round, 2, 0, 0, roundFunc ),
|
||||
|
@ -243,6 +243,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
|
||||
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
|
||||
0, /* bSmallMalloc */
|
||||
1, /* bExtraSchemaChecks */
|
||||
sizeof(long double)>8, /* bUseLongDouble */
|
||||
0x7ffffffe, /* mxStrlen */
|
||||
0, /* neverCorrupt */
|
||||
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
|
||||
|
12
src/main.c
12
src/main.c
@ -4470,6 +4470,18 @@ int sqlite3_test_control(int op, ...){
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
|
||||
**
|
||||
** Enable long double usage if X>0. Disable if X==0. No-op if X<0.
|
||||
** Return the status of long double usage afterwards.
|
||||
*/
|
||||
case SQLITE_TESTCTRL_USELONGDOUBLE: {
|
||||
int b = va_arg(ap, int);
|
||||
if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
|
||||
rc = sqlite3Config.bUseLongDouble!=0;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
|
||||
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
|
||||
|
200
src/printf.c
200
src/printf.c
@ -105,57 +105,6 @@ static const et_info fmtinfo[] = {
|
||||
** %!S Like %S but prefer the zName over the zAlias
|
||||
*/
|
||||
|
||||
/* Floating point constants used for rounding */
|
||||
static const double arRound[] = {
|
||||
5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
|
||||
5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
|
||||
};
|
||||
|
||||
/*
|
||||
** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
|
||||
** conversions will work.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** "*val" is a double such that 0.1 <= *val < 10.0
|
||||
** Return the ascii code for the leading digit of *val, then
|
||||
** multiply "*val" by 10.0 to renormalize.
|
||||
**
|
||||
** Example:
|
||||
** input: *val = 3.14159
|
||||
** output: *val = 1.4159 function return = '3'
|
||||
**
|
||||
** The counter *cnt is incremented each time. After counter exceeds
|
||||
** 16 (the number of significant digits in a 64-bit float) '0' is
|
||||
** always returned.
|
||||
*/
|
||||
static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||
int digit;
|
||||
LONGDOUBLE_TYPE d;
|
||||
if( (*cnt)<=0 ) return '0';
|
||||
(*cnt)--;
|
||||
digit = (int)*val;
|
||||
d = digit;
|
||||
digit += '0';
|
||||
*val = (*val - d)*10.0;
|
||||
return (char)digit;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
/*
|
||||
** "*val" is a u64. *msd is a divisor used to extract the
|
||||
** most significant digit of *val. Extract that most significant
|
||||
** digit and return it.
|
||||
*/
|
||||
static char et_getdigit_int(u64 *val, u64 *msd){
|
||||
u64 x = (*val)/(*msd);
|
||||
*val -= x*(*msd);
|
||||
if( *msd>=10 ) *msd /= 10;
|
||||
return '0' + (char)(x & 15);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
||||
|
||||
/*
|
||||
** Set the StrAccum object to an error mode.
|
||||
*/
|
||||
@ -247,20 +196,15 @@ void sqlite3_str_vappendf(
|
||||
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
|
||||
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
|
||||
sqlite_uint64 longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
sqlite_uint64 msd; /* Divisor to get most-significant-digit
|
||||
** of longvalue */
|
||||
double realvalue; /* Value for real types */
|
||||
const et_info *infop; /* Pointer to the appropriate info structure */
|
||||
char *zOut; /* Rendering buffer */
|
||||
int nOut; /* Size of the rendering buffer */
|
||||
char *zExtra = 0; /* Malloced memory used by some conversion */
|
||||
#ifndef SQLITE_OMIT_FLOATING_POINT
|
||||
int exp, e2; /* exponent of real numbers */
|
||||
int nsd; /* Number of significant digits returned */
|
||||
double rounder; /* Used for rounding floating point values */
|
||||
int exp, e2; /* exponent of real numbers */
|
||||
etByte flag_dp; /* True if decimal point should be shown */
|
||||
etByte flag_rtz; /* True if trailing zeros should be removed */
|
||||
#endif
|
||||
|
||||
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
|
||||
@ -535,94 +479,61 @@ void sqlite3_str_vappendf(
|
||||
break;
|
||||
case etFLOAT:
|
||||
case etEXP:
|
||||
case etGENERIC:
|
||||
case etGENERIC: {
|
||||
FpDecode s;
|
||||
int iRound;
|
||||
int j;
|
||||
|
||||
if( bArgList ){
|
||||
realvalue = getDoubleArg(pArgList);
|
||||
}else{
|
||||
realvalue = va_arg(ap,double);
|
||||
}
|
||||
#ifdef SQLITE_OMIT_FLOATING_POINT
|
||||
length = 0;
|
||||
#else
|
||||
if( precision<0 ) precision = 6; /* Set default precision */
|
||||
#ifdef SQLITE_FP_PRECISION_LIMIT
|
||||
if( precision>SQLITE_FP_PRECISION_LIMIT ){
|
||||
precision = SQLITE_FP_PRECISION_LIMIT;
|
||||
}
|
||||
#endif
|
||||
if( realvalue<0.0 ){
|
||||
realvalue = -realvalue;
|
||||
if( xtype==etFLOAT ){
|
||||
iRound = -precision;
|
||||
}else if( xtype==etGENERIC ){
|
||||
iRound = precision;
|
||||
}else{
|
||||
iRound = precision+1;
|
||||
}
|
||||
sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
|
||||
if( s.isSpecial ){
|
||||
if( s.isSpecial==2 ){
|
||||
bufpt = flag_zeropad ? "null" : "NaN";
|
||||
length = sqlite3Strlen30(bufpt);
|
||||
break;
|
||||
}else if( flag_zeropad ){
|
||||
s.z[0] = '9';
|
||||
s.iDP = 1000;
|
||||
s.n = 1;
|
||||
}else{
|
||||
memcpy(buf, "-Inf", 5);
|
||||
bufpt = buf;
|
||||
if( s.sign=='-' ){
|
||||
/* no-op */
|
||||
}else if( flag_prefix ){
|
||||
buf[0] = flag_prefix;
|
||||
}else{
|
||||
bufpt++;
|
||||
}
|
||||
length = sqlite3Strlen30(bufpt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( s.sign=='-' ){
|
||||
prefix = '-';
|
||||
}else{
|
||||
prefix = flag_prefix;
|
||||
}
|
||||
exp = 0;
|
||||
if( xtype==etGENERIC && precision>0 ) precision--;
|
||||
testcase( precision>0xfff );
|
||||
if( realvalue<9.22e+18
|
||||
&& realvalue==(LONGDOUBLE_TYPE)(longvalue = (u64)realvalue)
|
||||
){
|
||||
/* Number is a pure integer that can be represented as u64 */
|
||||
for(msd=1; msd*10<=longvalue; msd *= 10, exp++){}
|
||||
if( exp>precision && xtype!=etFLOAT ){
|
||||
u64 rnd = msd/2;
|
||||
int kk = precision;
|
||||
while( kk-- > 0 ){ rnd /= 10; }
|
||||
longvalue += rnd;
|
||||
}
|
||||
}else{
|
||||
msd = 0;
|
||||
longvalue = 0; /* To prevent a compiler warning */
|
||||
idx = precision & 0xfff;
|
||||
rounder = arRound[idx%10];
|
||||
while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
|
||||
if( xtype==etFLOAT ){
|
||||
double rx = (double)realvalue;
|
||||
sqlite3_uint64 u;
|
||||
int ex;
|
||||
memcpy(&u, &rx, sizeof(u));
|
||||
ex = -1023 + (int)((u>>52)&0x7ff);
|
||||
if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
|
||||
realvalue += rounder;
|
||||
}
|
||||
if( sqlite3IsNaN((double)realvalue) ){
|
||||
if( flag_zeropad ){
|
||||
bufpt = "null";
|
||||
length = 4;
|
||||
}else{
|
||||
bufpt = "NaN";
|
||||
length = 3;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
if( ALWAYS(realvalue>0.0) ){
|
||||
LONGDOUBLE_TYPE scale = 1.0L;
|
||||
while( realvalue>=1e100*scale && exp<=350){ scale*=1e100L;exp+=100;}
|
||||
while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10L; exp+=10; }
|
||||
while( realvalue>=10.0*scale && exp<=350 ){ scale*=10.0L; exp++; }
|
||||
realvalue /= scale;
|
||||
while( realvalue<1e-8 ){ realvalue *= 1e8L; exp-=8; }
|
||||
while( realvalue<1.0 ){ realvalue *= 10.0L; exp--; }
|
||||
if( exp>350 ){
|
||||
if( flag_zeropad ){
|
||||
realvalue = 9.0;
|
||||
exp = 999;
|
||||
}else{
|
||||
bufpt = buf;
|
||||
buf[0] = prefix;
|
||||
memcpy(buf+(prefix!=0),"Inf",4);
|
||||
length = 3+(prefix!=0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( xtype!=etFLOAT ){
|
||||
realvalue += rounder;
|
||||
if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
exp = s.iDP-1;
|
||||
if( xtype==etGENERIC && precision>0 ) precision--;
|
||||
|
||||
/*
|
||||
** If the field type is etGENERIC, then convert to either etEXP
|
||||
@ -642,9 +553,8 @@ void sqlite3_str_vappendf(
|
||||
if( xtype==etEXP ){
|
||||
e2 = 0;
|
||||
}else{
|
||||
e2 = exp;
|
||||
e2 = s.iDP - 1;
|
||||
}
|
||||
nsd = 16 + flag_altform2*10;
|
||||
bufpt = buf;
|
||||
{
|
||||
i64 szBufNeeded; /* Size of a temporary buffer needed */
|
||||
@ -662,16 +572,12 @@ void sqlite3_str_vappendf(
|
||||
*(bufpt++) = prefix;
|
||||
}
|
||||
/* Digits prior to the decimal point */
|
||||
j = 0;
|
||||
if( e2<0 ){
|
||||
*(bufpt++) = '0';
|
||||
}else if( msd>0 ){
|
||||
for(; e2>=0; e2--){
|
||||
*(bufpt++) = et_getdigit_int(&longvalue,&msd);
|
||||
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
}
|
||||
}else{
|
||||
for(; e2>=0; e2--){
|
||||
*(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
|
||||
}
|
||||
}
|
||||
@ -681,19 +587,12 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* "0" digits after the decimal point but before the first
|
||||
** significant digit of the number */
|
||||
for(e2++; e2<0; precision--, e2++){
|
||||
assert( precision>0 );
|
||||
for(e2++; e2<0 && precision>0; precision--, e2++){
|
||||
*(bufpt++) = '0';
|
||||
}
|
||||
/* Significant digits after the decimal point */
|
||||
if( msd>0 ){
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = et_getdigit_int(&longvalue,&msd);
|
||||
}
|
||||
}else{
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = et_getdigit(&realvalue,&nsd);
|
||||
}
|
||||
while( (precision--)>0 ){
|
||||
*(bufpt++) = j<s.n ? s.z[j++] : '0';
|
||||
}
|
||||
/* Remove trailing zeros and the "." if no digits follow the "." */
|
||||
if( flag_rtz && flag_dp ){
|
||||
@ -709,6 +608,7 @@ void sqlite3_str_vappendf(
|
||||
}
|
||||
/* Add the "eNNN" suffix */
|
||||
if( xtype==etEXP ){
|
||||
exp = s.iDP - 1;
|
||||
*(bufpt++) = aDigits[infop->charset];
|
||||
if( exp<0 ){
|
||||
*(bufpt++) = '-'; exp = -exp;
|
||||
@ -742,8 +642,8 @@ void sqlite3_str_vappendf(
|
||||
while( nPad-- ) bufpt[i++] = '0';
|
||||
length = width;
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
|
||||
break;
|
||||
}
|
||||
case etSIZE:
|
||||
if( !bArgList ){
|
||||
*(va_arg(ap,int*)) = pAccum->nChar;
|
||||
|
@ -10876,6 +10876,7 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
{"seek_count", SQLITE_TESTCTRL_SEEK_COUNT, 0, "" },
|
||||
{"sorter_mmap", SQLITE_TESTCTRL_SORTER_MMAP, 0, "NMAX" },
|
||||
{"tune", SQLITE_TESTCTRL_TUNE, 1, "ID VALUE" },
|
||||
{"uselongdouble", SQLITE_TESTCTRL_USELONGDOUBLE,0,"BOOLEAN" },
|
||||
};
|
||||
int testctrl = -1;
|
||||
int iCtrl = -1;
|
||||
@ -10997,6 +10998,14 @@ static int do_meta_command(char *zLine, ShellState *p){
|
||||
}
|
||||
break;
|
||||
|
||||
/* sqlite3_test_control(int, int) */
|
||||
case SQLITE_TESTCTRL_USELONGDOUBLE: {
|
||||
int opt = nArg==3 ? booleanValue(azArg[2]) : -1;
|
||||
rc2 = sqlite3_test_control(testctrl, opt);
|
||||
isOk = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* sqlite3_test_control(sqlite3*) */
|
||||
case SQLITE_TESTCTRL_INTERNAL_FUNCTIONS:
|
||||
rc2 = sqlite3_test_control(testctrl, p->db);
|
||||
|
@ -8176,7 +8176,8 @@ int sqlite3_test_control(int op, ...);
|
||||
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
||||
#define SQLITE_TESTCTRL_TUNE 32
|
||||
#define SQLITE_TESTCTRL_LOGEST 33
|
||||
#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
|
||||
#define SQLITE_TESTCTRL_USELONGDOUBLE 34
|
||||
#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
|
||||
|
||||
/*
|
||||
** CAPI3REF: SQL Keyword Checking
|
||||
|
@ -1239,6 +1239,7 @@ typedef struct Schema Schema;
|
||||
typedef struct Expr Expr;
|
||||
typedef struct ExprList ExprList;
|
||||
typedef struct FKey FKey;
|
||||
typedef struct FpDecode FpDecode;
|
||||
typedef struct FuncDestructor FuncDestructor;
|
||||
typedef struct FuncDef FuncDef;
|
||||
typedef struct FuncDefHash FuncDefHash;
|
||||
@ -4089,6 +4090,7 @@ struct Sqlite3Config {
|
||||
u8 bUseCis; /* Use covering indices for full-scans */
|
||||
u8 bSmallMalloc; /* Avoid large memory allocations if true */
|
||||
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
|
||||
u8 bUseLongDouble; /* Make use of long double */
|
||||
int mxStrlen; /* Maximum string length */
|
||||
int neverCorrupt; /* Database is always well-formed */
|
||||
int szLookaside; /* Default lookaside buffer size */
|
||||
@ -4597,6 +4599,19 @@ struct PrintfArguments {
|
||||
sqlite3_value **apArg; /* The argument values */
|
||||
};
|
||||
|
||||
/*
|
||||
** An instance of this object receives the decoding of a floating point
|
||||
** value into an approximate decimal representation.
|
||||
*/
|
||||
struct FpDecode {
|
||||
char sign; /* '+' or '-' */
|
||||
char isSpecial; /* 1: Infinity 2: NaN */
|
||||
int n; /* Significant digits in the decode */
|
||||
int iDP; /* Location of the decimal point */
|
||||
char z[24]; /* Significiant digits */
|
||||
};
|
||||
|
||||
void sqlite3FpDecode(FpDecode*,double,int,int);
|
||||
char *sqlite3MPrintf(sqlite3*,const char*, ...);
|
||||
char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
|
||||
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
|
||||
|
86
src/test1.c
86
src/test1.c
@ -991,6 +991,46 @@ static void intrealFunction(
|
||||
sqlite3_test_control(SQLITE_TESTCTRL_RESULT_INTREAL, context);
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: strtod(X)
|
||||
**
|
||||
** Use the C-library strtod() function to convert string X into a double.
|
||||
** Used for comparing the accuracy of SQLite's internal text-to-float conversion
|
||||
** routines against the C-library.
|
||||
*/
|
||||
static void shellStrtod(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
char *z = (char*)sqlite3_value_text(apVal[0]);
|
||||
UNUSED_PARAMETER(nVal);
|
||||
if( z==0 ) return;
|
||||
sqlite3_result_double(pCtx, strtod(z,0));
|
||||
}
|
||||
|
||||
/*
|
||||
** SQL function: dtostr(X)
|
||||
**
|
||||
** Use the C-library printf() function to convert real value X into a string.
|
||||
** Used for comparing the accuracy of SQLite's internal float-to-text conversion
|
||||
** routines against the C-library.
|
||||
*/
|
||||
static void shellDtostr(
|
||||
sqlite3_context *pCtx,
|
||||
int nVal,
|
||||
sqlite3_value **apVal
|
||||
){
|
||||
double r = sqlite3_value_double(apVal[0]);
|
||||
int n = nVal>=2 ? sqlite3_value_int(apVal[1]) : 26;
|
||||
char z[400];
|
||||
if( n<1 ) n = 1;
|
||||
if( n>350 ) n = 350;
|
||||
sprintf(z, "%#+.*e", n, r);
|
||||
sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Usage: sqlite3_create_function DB
|
||||
**
|
||||
@ -1063,6 +1103,27 @@ static int SQLITE_TCLAPI test_create_function(
|
||||
0, intrealFunction, 0, 0);
|
||||
}
|
||||
|
||||
/* Functions strtod() and dtostr() work as in the shell. These routines
|
||||
** use the standard C library to convert between floating point and
|
||||
** text. This is used to compare SQLite's internal conversion routines
|
||||
** against the standard library conversion routines.
|
||||
**
|
||||
** Both routines copy/pasted from the shell.c.in implementation
|
||||
** on 2023-07-03.
|
||||
*/
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "strtod", 1, SQLITE_UTF8, 0,
|
||||
shellStrtod, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "dtostr", 1, SQLITE_UTF8, 0,
|
||||
shellDtostr, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "dtostr", 2, SQLITE_UTF8, 0,
|
||||
shellDtostr, 0, 0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
|
||||
** because it is not tested anywhere else. */
|
||||
@ -7037,6 +7098,30 @@ static int SQLITE_TCLAPI extra_schema_checks(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: use_long_double INT
|
||||
**
|
||||
** Enable or disable the use of long double. Enable if the argument is
|
||||
** positive. Disable if the argument is zero. No-op if the argument is
|
||||
** negative.
|
||||
**
|
||||
** Return the new setting.
|
||||
*/
|
||||
static int SQLITE_TCLAPI use_long_double(
|
||||
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int objc, /* Number of arguments */
|
||||
Tcl_Obj *CONST objv[] /* Command arguments */
|
||||
){
|
||||
int i = -1;
|
||||
if( objc==2 ){
|
||||
if( Tcl_GetBooleanFromObj(interp,objv[1],&i) ) return TCL_ERROR;
|
||||
}
|
||||
i = sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, i);
|
||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: database_may_be_corrupt
|
||||
**
|
||||
@ -8925,6 +9010,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||
{ "reset_prng_state", reset_prng_state, 0 },
|
||||
{ "prng_seed", prng_seed, 0 },
|
||||
{ "extra_schema_checks", extra_schema_checks, 0},
|
||||
{ "use_long_double", use_long_double, 0},
|
||||
{ "database_never_corrupt", database_never_corrupt, 0},
|
||||
{ "database_may_be_corrupt", database_may_be_corrupt, 0},
|
||||
{ "optimization_control", optimization_control,0},
|
||||
|
164
src/util.c
164
src/util.c
@ -928,6 +928,170 @@ int sqlite3Atoi(const char *z){
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Double-Double multiplication. *(z,zz) = (x,xx) * (y,yy)
|
||||
**
|
||||
** Reference:
|
||||
** T. J. Dekker, "A Floating-Point Technique for Extending the
|
||||
** Available Precision". 1971-07-26.
|
||||
*/
|
||||
static void dekkerMul2(
|
||||
double x, double xx,
|
||||
double y, double yy,
|
||||
double *z, double *zz
|
||||
){
|
||||
double hx, tx, hy, ty, p, q, c, cc;
|
||||
u64 m;
|
||||
memcpy(&m, &x, 8);
|
||||
m &= 0xfffffffffc000000L;
|
||||
memcpy(&hx, &m, 8);
|
||||
tx = x - hx;
|
||||
memcpy(&m, &y, 8);
|
||||
m &= 0xfffffffffc000000L;
|
||||
memcpy(&hy, &m, 8);
|
||||
ty = y - hy;
|
||||
p = hx*hy;
|
||||
q = hx*ty + tx*hy;
|
||||
c = p+q;
|
||||
cc = p - c + q + tx*ty;
|
||||
cc = x*yy + xx*y + cc;
|
||||
*z = c + cc;
|
||||
*zz = c - *z + cc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Decode a floating-point value into an approximate decimal
|
||||
** representation.
|
||||
**
|
||||
** Round the decimal representation to n significant digits if
|
||||
** n is positive. Or round to -n signficant digits after the
|
||||
** decimal point if n is negative. No rounding is performed if
|
||||
** n is zero.
|
||||
*/
|
||||
void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
|
||||
int i;
|
||||
u64 v;
|
||||
int e, exp = 0;
|
||||
p->isSpecial = 0;
|
||||
|
||||
/* Convert negative numbers to positive. Deal with Infinity, 0.0, and
|
||||
** NaN. */
|
||||
if( r<0.0 ){
|
||||
p->sign = '-';
|
||||
r = -r;
|
||||
}else if( r==0.0 ){
|
||||
p->sign = '+';
|
||||
p->n = 1;
|
||||
p->iDP = 1;
|
||||
p->z[0] = '0';
|
||||
return;
|
||||
}else{
|
||||
p->sign = '+';
|
||||
}
|
||||
memcpy(&v,&r,8);
|
||||
e = v>>52;
|
||||
if( (e&0x7ff)==0x7ff ){
|
||||
p->isSpecial = 1 + (v!=0x7ff0000000000000L);
|
||||
p->n = 0;
|
||||
p->iDP = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Multiply r by powers of ten until it lands somewhere in between
|
||||
** 1.0e+19 and 1.0e+17.
|
||||
*/
|
||||
if( sqlite3Config.bUseLongDouble ){
|
||||
LONGDOUBLE_TYPE rr = r;
|
||||
if( rr>=1.0e+19 ){
|
||||
while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
|
||||
while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
|
||||
while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
|
||||
}else{
|
||||
while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
|
||||
while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
|
||||
while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
|
||||
}
|
||||
v = (u64)rr;
|
||||
}else{
|
||||
/* If high-precision floating point is not available using "long double",
|
||||
** then use Dekker-style double-double computation to increase the
|
||||
** precision.
|
||||
**
|
||||
** The error terms on constants like 1.0e+100 computed using the
|
||||
** decimal extension, for example as follows:
|
||||
**
|
||||
** SELECT decimal_sci(decimal_sub('1.0e+100',decimal(1.0e+100)));
|
||||
*/
|
||||
double rr = 0.0;
|
||||
if( r>1.84e+19 ){
|
||||
while( r>1.84e+119 ){
|
||||
exp += 100;
|
||||
dekkerMul2(r, rr, 1.0e-100, -1.99918998026028836196e-117, &r, &rr);
|
||||
}
|
||||
while( r>1.84e+29 ){
|
||||
exp += 10;
|
||||
dekkerMul2(r,rr, 1.0e-10, -3.6432197315497741579e-27, &r, &rr);
|
||||
}
|
||||
while( r>1.84e+19 ){
|
||||
exp += 1;
|
||||
dekkerMul2(r,rr, 1.0e-01, -5.5511151231257827021e-18, &r, &rr);
|
||||
}
|
||||
}else{
|
||||
while( r<1.84e-82 ){
|
||||
exp -= 100;
|
||||
dekkerMul2(r, rr, 1.0e+100, -1.5902891109759918046e+83, &r, &rr);
|
||||
}
|
||||
while( r<1.84e+08 ){
|
||||
exp -= 10;
|
||||
dekkerMul2(r, rr, 1.0e+10, 0.0, &r, &rr);
|
||||
}
|
||||
while( r<1.84e+18 ){
|
||||
exp -= 1;
|
||||
dekkerMul2(r, rr, 1.0e+01, 0.0, &r, &rr);
|
||||
}
|
||||
}
|
||||
v = rr<0.0 ? (u64)r-(u64)(-rr) : (u64)r+(u64)rr;
|
||||
}
|
||||
|
||||
|
||||
/* Extract significant digits. */
|
||||
i = sizeof(p->z)-1;
|
||||
while( v ){ p->z[i--] = (v%10) + '0'; v /= 10; }
|
||||
p->n = sizeof(p->z) - 1 - i;
|
||||
p->iDP = p->n + exp;
|
||||
if( iRound<0 ){
|
||||
iRound = p->iDP - iRound;
|
||||
if( iRound==0 && p->z[i+1]>='5' ){
|
||||
iRound = 1;
|
||||
p->z[i--] = '0';
|
||||
p->n++;
|
||||
p->iDP++;
|
||||
}
|
||||
}
|
||||
if( iRound>0 && (iRound<p->n || p->n>mxRound) ){
|
||||
char *z = &p->z[i+1];
|
||||
if( iRound>mxRound ) iRound = mxRound;
|
||||
p->n = iRound;
|
||||
if( z[iRound]>='5' ){
|
||||
int j = iRound-1;
|
||||
while( 1 /*exit-by-break*/ ){
|
||||
z[j]++;
|
||||
if( z[j]<='9' ) break;
|
||||
z[j] = '0';
|
||||
if( j==0 ){
|
||||
p->z[i--] = '1';
|
||||
p->n++;
|
||||
p->iDP++;
|
||||
break;
|
||||
}else{
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memmove(p->z, &p->z[i+1], p->n);
|
||||
while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
|
||||
}
|
||||
|
||||
/*
|
||||
** Try to convert z into an unsigned 32-bit integer. Return true on
|
||||
** success and false if there is an error.
|
||||
|
@ -51,10 +51,16 @@ for {set i 1} {$i<20000} {incr i} {
|
||||
set y [db eval {SELECT $x=CAST(quote($x) AS real)}]
|
||||
if {!$y} {
|
||||
db eval {SELECT real2hex($x) a, real2hex(CAST(quote($x) AS real)) b} {}
|
||||
puts "\nIN: $a $xf"
|
||||
puts [format {QUOTE: %16s %s} {} [db eval {SELECT quote($x)}]]
|
||||
puts ""
|
||||
if {$x<0} {
|
||||
puts "[format {!SCALE: %17s 1 23456789 123456789 123456789} {}]"
|
||||
} else {
|
||||
puts "[format {!SCALE: %16s 1 23456789 123456789 123456789} {}]"
|
||||
}
|
||||
puts "!IN: $a $xf"
|
||||
puts [format {!QUOTE: %16s %s} {} [db eval {SELECT quote($x)}]]
|
||||
db eval {SELECT CAST(quote($x) AS real) c} {}
|
||||
puts "OUT: $b [format %.32e $c]"
|
||||
puts "!OUT: $b [format %.32e $c]"
|
||||
}
|
||||
set y
|
||||
} {1}
|
||||
|
44
test/fpconv1.test
Normal file
44
test/fpconv1.test
Normal file
@ -0,0 +1,44 @@
|
||||
# 2023-07-03
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
# This file contains a test that attempts to verify the claim that the
|
||||
# floatpoint-to-text conversion routines built into SQLite maintain at
|
||||
# least 15 significant digits of accuracy.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
if {[catch {load_static_extension db decimal} error]} {
|
||||
puts "Skipping decimal tests, hit load error: $error"
|
||||
finish_test; return
|
||||
}
|
||||
|
||||
sqlite3_create_function db
|
||||
do_execsql_test fpconv1-1.0 {
|
||||
WITH RECURSIVE
|
||||
/* Number of random floating-point values to try.
|
||||
** On a circa 2016 x64 linux box, this test runs at
|
||||
** about 80000 cases per second -------------------vvvvvv */
|
||||
c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100000),
|
||||
fp(y) AS MATERIALIZED (
|
||||
SELECT CAST( format('%+d.%019d0e%+03d',
|
||||
random()%10,abs(random()),random()%200) AS real)
|
||||
FROM c
|
||||
)
|
||||
SELECT y FROM fp
|
||||
WHERE -log10(abs(decimal_sub(dtostr(y,24),format('%!.24e',y))/y))<15.0;
|
||||
/* Number of digits of accuracy required -------^^^^ */
|
||||
} {}
|
||||
# ^---- Expect a empty set as the result. The output is all tested numbers
|
||||
# that fail to preserve at least 15 significant digits of accuracy.
|
||||
|
||||
finish_test
|
@ -34,8 +34,8 @@ for {set iTest 1} {$iTest<=50000} {incr iTest} {
|
||||
set r2 $x1.$x4
|
||||
set ans [string trimright $r2 0]
|
||||
if {[string match *. $ans]} {set ans ${ans}0}
|
||||
do_test $iTest/$n/${r}5=>$ans {
|
||||
set x [db one "SELECT round(${r}5,$n)"]
|
||||
do_test $iTest/$n/${r}6=>$ans {
|
||||
set x [db one "SELECT round(${r}6,$n)"]
|
||||
} $ans
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user