From 4df23a3248c864e7b5781e30434ada5a75b5e5dd Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 23 Feb 2023 21:18:47 +0000 Subject: [PATCH 1/3] Increased precision of floating-point to decimal conversions when the floating point value has no fractional part. [forum:/forumpost/d1387c3979c7f557|Forum post d1387c3979c7f557] FossilOrigin-Name: 18de3a8e6b431a075143631eafdcf0e1b1a21868b417394c365d46d2feca10b5 --- manifest | 14 +++--- manifest.uuid | 2 +- src/printf.c | 127 ++++++++++++++++++++++++++++++++--------------- test/printf.test | 35 +++++++++++++ 4 files changed, 130 insertions(+), 48 deletions(-) diff --git a/manifest b/manifest index e6f9823458..5e91b785cb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sand\sa\scode\sindentation\serror. -D 2023-02-23T14:43:15.500 +C Increased\sprecision\sof\sfloating-point\sto\sdecimal\sconversions\swhen\sthe\nfloating\spoint\svalue\shas\sno\sfractional\spart.\n[forum:/forumpost/d1387c3979c7f557|Forum\spost\sd1387c3979c7f557] +D 2023-02-23T21:18:47.560 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -617,7 +617,7 @@ F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc F src/pragma.c 82d5090a35eac75876d3b41f48d06b2370553c9576bf2942233c462e03eb94c9 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c ce87a08cfddd45a147150db34190b1986f2d4a0e0828858cb6bd908c78fb02e3 -F src/printf.c ff4b05e38bf928ff1b80d3dda4f977b10fe39ecbfe69c018224c7e5594fb2455 +F src/printf.c d7b8c87d3525ee3eea3c4d291023540c88788e47a65c5b1dcff1b432ec9dbda5 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d62c5665279cc7485f9d45b5e20911cc7b19c203f268321a90d05d74f4725750 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 @@ -1381,7 +1381,7 @@ F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8 F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102 F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8 F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9 -F test/printf.test 390d0d7fcffc3c4ea3c1bb4cbb267444e32b33b048ae21895f23a291844fe1da +F test/printf.test 22449e13983e9d94fe9a671db68a086c4c55dea51daad825ef7ebb3d192ee997 F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc @@ -2046,8 +2046,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 7ee22f95e7a7d8650f961f20e304e56c7813e624f05655d7392ca9347748270f -R 6f3dc9114a2c05702b3aef7d84d0887b +P de6c5c6bb49a0beca793cdc0462da2c17bb05f3292e08dd815be29b45b59a8fb +R 4769ae3a046ae725cd776ab02bbf2890 U drh -Z ad82adef5ba3f74b5f1d1691fda9e306 +Z bc3a2ae65a6e7b1f83be3e57f2f8ed26 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1982ec0f0e..1b7ffdec93 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -de6c5c6bb49a0beca793cdc0462da2c17bb05f3292e08dd815be29b45b59a8fb \ No newline at end of file +18de3a8e6b431a075143631eafdcf0e1b1a21868b417394c365d46d2feca10b5 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 335ad06844..5a1b7761f9 100644 --- a/src/printf.c +++ b/src/printf.c @@ -142,6 +142,20 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ } #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. */ @@ -234,6 +248,8 @@ void sqlite3_str_vappendf( 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 */ const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ @@ -540,52 +556,72 @@ void sqlite3_str_vappendf( }else{ prefix = flag_prefix; } + exp = 0; if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); - 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; - } - /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - exp = 0; - if( sqlite3IsNaN((double)realvalue) ){ - bufpt = "NaN"; - length = 3; - break; - } - if( realvalue>0.0 ){ - LONGDOUBLE_TYPE scale = 1.0; - while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} - while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; } - while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } - realvalue /= scale; - while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } - while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } - if( exp>350 ){ - bufpt = buf; - buf[0] = prefix; - memcpy(buf+(prefix!=0),"Inf",4); - length = 3+(prefix!=0); + if( realvalue<1.0e+16 + && 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 ){ rnd /= 10; } + longvalue += rnd; + } + }else{ + msd = 0; + longvalue = 0; /* To prevent a compiler warning */ + idx = precision & 0xfff; + if( idx>20 ){ + rounder = 0.0; + }else{ + 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) ){ + bufpt = "NaN"; + length = 3; break; } + + /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ + if( realvalue>0.0 ){ + LONGDOUBLE_TYPE scale = 1.0; + while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;} + while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; } + while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } + realvalue /= scale; + while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } + while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } + if( exp>350 ){ + 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++; } + } + } } - bufpt = buf; + /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ - if( xtype!=etFLOAT ){ - realvalue += rounder; - if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } - } if( xtype==etGENERIC ){ flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ @@ -602,6 +638,8 @@ void sqlite3_str_vappendf( }else{ e2 = exp; } + nsd = 16 + flag_altform2*10; + bufpt = buf; { i64 szBufNeeded; /* Size of a temporary buffer needed */ szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; @@ -611,7 +649,6 @@ void sqlite3_str_vappendf( } } zOut = bufpt; - nsd = 16 + flag_altform2*10; flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2; /* The sign in front of the number */ if( prefix ){ @@ -620,6 +657,10 @@ void sqlite3_str_vappendf( /* Digits prior to the decimal point */ if( e2<0 ){ *(bufpt++) = '0'; + }else if( msd>0 ){ + for(; e2>=0; e2--){ + *(bufpt++) = et_getdigit_int(&longvalue,&msd); + } }else{ for(; e2>=0; e2--){ *(bufpt++) = et_getdigit(&realvalue,&nsd); @@ -636,8 +677,14 @@ void sqlite3_str_vappendf( *(bufpt++) = '0'; } /* Significant digits after the decimal point */ - while( (precision--)>0 ){ - *(bufpt++) = et_getdigit(&realvalue,&nsd); + if( msd>0 ){ + while( (precision--)>0 ){ + *(bufpt++) = et_getdigit_int(&longvalue,&msd); + } + }else{ + while( (precision--)>0 ){ + *(bufpt++) = et_getdigit(&realvalue,&nsd); + } } /* Remove trailing zeros and the "." if no digits follow the "." */ if( flag_rtz && flag_dp ){ diff --git a/test/printf.test b/test/printf.test index 445470fc07..24b78529f6 100644 --- a/test/printf.test +++ b/test/printf.test @@ -3786,4 +3786,39 @@ do_execsql_test printf-16.1 { SELECT printf('%.*g',2147483647,0.01); } {0.01} +# 2023-02-23 https://sqlite.org/forum/forumpost/d1387c3979c7f557 +# Loss of precision when doing floating-point to decimal +# conversions on values that have no factional part. +# +do_execsql_test printf-17.1 { + SELECT format('%!.20g', 13.0); +} 13.0 +do_execsql_test printf-17.2 { + SELECT format('%.3e', 199990000.0); +} 2.000e+08 +do_execsql_test printf-17.3 { + SELECT format('%.3f', 199990000.0); +} 199990000.000 +do_execsql_test printf-17.4 { + SELECT format('%.3g', 199990000.0); +} 2e+08 +do_execsql_test printf-17.5 { + SELECT format('%.4e', 199990000.0); +} 1.9999e+08 +do_execsql_test printf-17.6 { + SELECT format('%.4f', 199990000.0); +} 199990000.0000 +do_execsql_test printf-17.7 { + SELECT format('%.4g', 199990000.0); +} 2e+08 +do_execsql_test printf-17.8 { + SELECT format('%.5e', 199990000.0); +} 1.99990e+08 +do_execsql_test printf-17.9 { + SELECT format('%.5f', 199990000.0); +} 199990000.00000 +do_execsql_test printf-17.10 { + SELECT format('%.5g', 199990000.0); +} 1.9999e+08 + finish_test From ed530c022174b1db212a8336c917c3fcfa539a57 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 23 Feb 2023 22:08:22 +0000 Subject: [PATCH 2/3] Omit unnecessary branches from the enhanced floating-point conversion logic. FossilOrigin-Name: 32b0ba0d27481d85a4b0037ec36befcbffecdec75891eba58569acb160045553 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/printf.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 5e91b785cb..a18b8b9b9e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Increased\sprecision\sof\sfloating-point\sto\sdecimal\sconversions\swhen\sthe\nfloating\spoint\svalue\shas\sno\sfractional\spart.\n[forum:/forumpost/d1387c3979c7f557|Forum\spost\sd1387c3979c7f557] -D 2023-02-23T21:18:47.560 +C Omit\sunnecessary\sbranches\sfrom\sthe\senhanced\sfloating-point\sconversion\nlogic. +D 2023-02-23T22:08:22.561 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -617,7 +617,7 @@ F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc F src/pragma.c 82d5090a35eac75876d3b41f48d06b2370553c9576bf2942233c462e03eb94c9 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c ce87a08cfddd45a147150db34190b1986f2d4a0e0828858cb6bd908c78fb02e3 -F src/printf.c d7b8c87d3525ee3eea3c4d291023540c88788e47a65c5b1dcff1b432ec9dbda5 +F src/printf.c 74e763868698df16ae24e96558c2a6ab9232ceaa373d326087bf519d2b75708d F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d62c5665279cc7485f9d45b5e20911cc7b19c203f268321a90d05d74f4725750 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 @@ -2046,8 +2046,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 de6c5c6bb49a0beca793cdc0462da2c17bb05f3292e08dd815be29b45b59a8fb -R 4769ae3a046ae725cd776ab02bbf2890 +P 18de3a8e6b431a075143631eafdcf0e1b1a21868b417394c365d46d2feca10b5 +R b615a8a32d1ccae3d6ecef9da1392398 U drh -Z bc3a2ae65a6e7b1f83be3e57f2f8ed26 +Z 97c2ef6d7f0bcb8f23c758a013f9c50f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 1b7ffdec93..346f81dbc0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -18de3a8e6b431a075143631eafdcf0e1b1a21868b417394c365d46d2feca10b5 \ No newline at end of file +32b0ba0d27481d85a4b0037ec36befcbffecdec75891eba58569acb160045553 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 5a1b7761f9..49a2789312 100644 --- a/src/printf.c +++ b/src/printf.c @@ -567,7 +567,7 @@ void sqlite3_str_vappendf( if( exp>precision && xtype!=etFLOAT ){ u64 rnd = msd/2; int kk = precision; - while( kk-- > 0 && rnd ){ rnd /= 10; } + while( kk-- > 0 ){ rnd /= 10; } longvalue += rnd; } }else{ @@ -596,7 +596,7 @@ void sqlite3_str_vappendf( } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - if( realvalue>0.0 ){ + if( ALWAYS(realvalue>0.0) ){ LONGDOUBLE_TYPE scale = 1.0; while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;} while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; } From 4b04ced3e05f46afb0e86631566a1adeb3113935 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 24 Feb 2023 01:08:35 +0000 Subject: [PATCH 3/3] Fix an incorrect optimization that was attempted as part of check-in [18de3a8e6b431a07]. FossilOrigin-Name: f32055e8110a2eac6c9e26d1d1e620f0668bcb475d49d309dc549cea05e1e582 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/printf.c | 24 ++++++++++-------------- test/printf.test | 3 +++ 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index a18b8b9b9e..560f711aaa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Omit\sunnecessary\sbranches\sfrom\sthe\senhanced\sfloating-point\sconversion\nlogic. -D 2023-02-23T22:08:22.561 +C Fix\san\sincorrect\soptimization\sthat\swas\sattempted\sas\spart\sof\ncheck-in\s[18de3a8e6b431a07]. +D 2023-02-24T01:08:35.334 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -617,7 +617,7 @@ F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc F src/pragma.c 82d5090a35eac75876d3b41f48d06b2370553c9576bf2942233c462e03eb94c9 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c ce87a08cfddd45a147150db34190b1986f2d4a0e0828858cb6bd908c78fb02e3 -F src/printf.c 74e763868698df16ae24e96558c2a6ab9232ceaa373d326087bf519d2b75708d +F src/printf.c 5957a30d107a3916a411cb979b9ee80447dc3717aecc4648a4d8cce0f929e508 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c d62c5665279cc7485f9d45b5e20911cc7b19c203f268321a90d05d74f4725750 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 @@ -1381,7 +1381,7 @@ F test/pragma4.test ca5e4dfc46adfe490f75d73734f70349d95a199e6510973899e502eef2c8 F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d9102 F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8 F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9 -F test/printf.test 22449e13983e9d94fe9a671db68a086c4c55dea51daad825ef7ebb3d192ee997 +F test/printf.test 931381fede4f901d5f76275959339502f7d3312492c8df129972487951ff9fd1 F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc @@ -2046,8 +2046,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 18de3a8e6b431a075143631eafdcf0e1b1a21868b417394c365d46d2feca10b5 -R b615a8a32d1ccae3d6ecef9da1392398 +P 32b0ba0d27481d85a4b0037ec36befcbffecdec75891eba58569acb160045553 +R d1a241fa3d7686eec8ef50c8409ad626 U drh -Z 97c2ef6d7f0bcb8f23c758a013f9c50f +Z 23dd6be15d54b437c81982a9d1edbb20 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 346f81dbc0..7e680c44f2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -32b0ba0d27481d85a4b0037ec36befcbffecdec75891eba58569acb160045553 \ No newline at end of file +f32055e8110a2eac6c9e26d1d1e620f0668bcb475d49d309dc549cea05e1e582 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 49a2789312..45a31ec8dc 100644 --- a/src/printf.c +++ b/src/printf.c @@ -574,20 +574,16 @@ void sqlite3_str_vappendf( msd = 0; longvalue = 0; /* To prevent a compiler warning */ idx = precision & 0xfff; - if( idx>20 ){ - rounder = 0.0; - }else{ - 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; - } + 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) ){ bufpt = "NaN"; diff --git a/test/printf.test b/test/printf.test index 24b78529f6..e4beb12dd0 100644 --- a/test/printf.test +++ b/test/printf.test @@ -3820,5 +3820,8 @@ do_execsql_test printf-17.9 { do_execsql_test printf-17.10 { SELECT format('%.5g', 199990000.0); } 1.9999e+08 +do_execsql_test printf-17.11 { + SELECT format('%.30f',1.0000000000000000076e-50); +} 0.000000000000000000000000000000 finish_test