From 557cc60f4d21212dcf05e432cab74c8ff9816fd6 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 13 Aug 2005 12:59:14 +0000 Subject: [PATCH] Add the "!" flag to the "%g" mprintf conversion parameter to force a decimal point. This prevents floating point values from appearing as integers. Use this flag when converting floating point to text. Ticket #1362. (CVS 2586) FossilOrigin-Name: 4b98dace6b90abf4a6fe1cd51e6392fd213358c4 --- manifest | 20 ++++---- manifest.uuid | 2 +- src/printf.c | 117 ++++++++++++++++++++++++++++------------------- src/vdbemem.c | 2 +- test/misc1.test | 8 ++-- test/printf.test | 27 ++++++++++- test/sort.test | 18 ++++---- 7 files changed, 121 insertions(+), 73 deletions(-) diff --git a/manifest b/manifest index 3bc74a872a..7a55f04255 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sthe\sround()\sfunction\swork\scorrectly\son\snumbers\swith\svery\slarge\sexponents.\nTicket\s#1340.\s(CVS\s2585) -D 2005-08-13T03:07:47 +C Add\sthe\s"!"\sflag\sto\sthe\s"%g"\smprintf\sconversion\sparameter\sto\sforce\sa\ndecimal\spoint.\s\sThis\sprevents\sfloating\spoint\svalues\sfrom\sappearing\sas\nintegers.\s\sUse\sthis\sflag\swhen\sconverting\sfloating\spoint\sto\stext.\nTicket\s#1362.\s(CVS\s2586) +D 2005-08-13T12:59:15 F Makefile.in 22ea9c0fe748f591712d8fe3c6d972c6c173a165 F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -60,7 +60,7 @@ F src/pager.h 0d9153d6269d60d04af3dd84a0cc0a96253cf4a4 F src/parse.y d57cdd2adc0923762b40314f08683c836a2e0c90 F src/pragma.c 59ab7073465a11a531af2796e0385727194accb8 F src/prepare.c fa0f6068d9b8ec6d5c419c65d4d8ff747d49c5c6 -F src/printf.c a06d3527c677334a97eaaa1573d0c644c987acf6 +F src/printf.c d1fa64c696bc05f50471a960bc68cd9b6e861823 F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4 F src/select.c c611471052773b94af771693686bd5bcdbbb0dba F src/shell.c 86c16f0d534aa51cc82cf9f66903d4eb681580e7 @@ -85,7 +85,7 @@ F src/vdbeInt.h 9be9a6c43d38124bd03cc5cf05715605b1789fd9 F src/vdbeapi.c dc5b78cabf8d6e33318bd3d4ed25307d2aadce9a F src/vdbeaux.c d53139d819b887dac608ac4ae9a501baee3cd311 F src/vdbefifo.c b8805850afe13b43f1de78d58088cb5d66f88e1e -F src/vdbemem.c da8e8d6f29dd1323f782f000d7cd120027c9ff03 +F src/vdbemem.c 89154caae3b8d4d0397e1235390fc4ff8aba4233 F src/where.c ac754c021f716e17337f45ffdc2436c6d5109fd3 F tclinstaller.tcl 046e3624671962dc50f0481d7c25b38ef803eb42 F test/all.test 7f0988442ab811dfa41793b5b550f5828ce316f3 @@ -169,7 +169,7 @@ F test/malloc2.test 655b972372d2754a3f6c6ed54d7cfd18fde9bd32 F test/memdb.test 1860e060be810bf0775bc57408a5b7c4954bcaea F test/memleak.test df2b2b96e77f8ba159a332299535b1e5f18e49ac F test/minmax.test 9429a06f1f93acf76fcacafd17160a4392e88526 -F test/misc1.test a4fe87c71f756ee36b08a698da46ea9c3b2471e7 +F test/misc1.test be8aa484569fb82766ce14961ba377aed92f3d8b F test/misc2.test 5c699af2fede2694736a9f45aea7e2f052686e15 F test/misc3.test 7bd937e2c62bcc6be71939faf068d506467b1e03 F test/misc4.test edd3e3adf5b6e3b995b29843565ca58dd602f9a7 @@ -182,7 +182,7 @@ F test/pager2.test 49c0f57c7da0b060f0486b85fdd074025caa694e F test/pager3.test 2323bf27fd5bd887b580247e5bce500ceee994b4 F test/pagesize.test cbc6a312b6f6c0f02619b189985df2a14164b690 F test/pragma.test 95ea907adf68459e1be6f310c9ae94d1d59c465b -F test/printf.test 96ae2891aa9e9ad3eba0bd7608ffe536437dd045 +F test/printf.test dc39f7c66db3adfe754b4fc0b97fdd97fa06a9c8 F test/progress.test 16496001da445e6534afb94562c286708316d82f x F test/quick.test a94d12658a2b590c1a5be580bef09bbb04c1266b F test/quote.test 6d75cf635d93ba2484dc9cb378d88cbae9dc2c62 @@ -198,7 +198,7 @@ F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca F test/select5.test 2d414f712bff8e590091e08f9b7287600731be00 F test/select6.test 6559d16ad16edb7d6864f7e74a3d204d0af72486 F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6 -F test/sort.test 8aaec2e01bf97691c96fd2f0294e635540bebcda +F test/sort.test 131787aadaa0eca8bc97eaf244bbde2380a4bb77 F test/subquery.test 0df3de0dbb65165b96ebe895550f1549d5439856 F test/subselect.test 3f3f7a940dc3195c3139f4d530385cb54665d614 F test/table.test d0e05ede3f6e5a8b79f8661ddcc4618cf7e69f8a @@ -291,7 +291,7 @@ F www/tclsqlite.tcl 3df553505b6efcad08f91e9b975deb2e6c9bb955 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b F www/whentouse.tcl 528299b8316726dbcc5548e9aa0648c8b1bd055b -P 25cfe9390dda79bb2a7740b3d7380f517a4e8d1b -R c6274d9ed3a9c273a8983dbfcf799ac8 +P 4f47c3c884e38b810450b6127ab33c7b86e6743c +R b3c296ac5d6a7b19a3b058edd9a64bc2 U drh -Z 745b1dec57cb9cc3d543dad039e1c761 +Z faea32e5bc1b77c04bb69a0132002ae9 diff --git a/manifest.uuid b/manifest.uuid index 4a2eac1c4a..ee931c5810 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f47c3c884e38b810450b6127ab33c7b86e6743c \ No newline at end of file +4b98dace6b90abf4a6fe1cd51e6392fd213358c4 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index 2157ea7efe..634391611c 100644 --- a/src/printf.c +++ b/src/printf.c @@ -111,6 +111,7 @@ static const char aPrefix[] = "-x0\000X0"; static const et_info fmtinfo[] = { { 'd', 10, 1, etRADIX, 0, 0 }, { 's', 0, 4, etSTRING, 0, 0 }, + { 'g', 0, 1, etGENERIC, 30, 0 }, { 'z', 0, 6, etDYNSTRING, 0, 0 }, { 'q', 0, 4, etSQLESCAPE, 0, 0 }, { 'Q', 0, 4, etSQLESCAPE2, 0, 0 }, @@ -122,7 +123,6 @@ static const et_info fmtinfo[] = { { 'f', 0, 1, etFLOAT, 0, 0 }, { 'e', 0, 1, etEXP, 30, 0 }, { 'E', 0, 1, etEXP, 14, 0 }, - { 'g', 0, 1, etGENERIC, 30, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, { 'i', 10, 1, etRADIX, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, @@ -210,6 +210,7 @@ static int vxprintf( etByte flag_plussign; /* True if "+" flag is present */ etByte flag_blanksign; /* True if " " flag is present */ etByte flag_alternateform; /* True if "#" flag is present */ + etByte flag_altform2; /* True if "$" flag is present */ etByte flag_zeropad; /* True if field width constant starts with zero */ etByte flag_long; /* True if "l" flag is present */ etByte flag_longlong; /* True if the "ll" flag is present */ @@ -225,7 +226,7 @@ static int vxprintf( " "; #define etSPACESIZE (sizeof(spaces)-1) #ifndef etNOFLOATINGPOINT - int exp; /* exponent of real numbers */ + int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ @@ -254,13 +255,14 @@ static int vxprintf( } /* Find out what flags are present */ flag_leftjustify = flag_plussign = flag_blanksign = - flag_alternateform = flag_zeropad = 0; + flag_alternateform = flag_altform2 = flag_zeropad = 0; do{ switch( c ){ case '-': flag_leftjustify = 1; c = 0; break; case '+': flag_plussign = 1; c = 0; break; case ' ': flag_blanksign = 1; c = 0; break; case '#': flag_alternateform = 1; c = 0; break; + case '!': flag_altform2 = 1; c = 0; break; case '0': flag_zeropad = 1; c = 0; break; default: break; } @@ -436,9 +438,9 @@ static int vxprintf( /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ exp = 0; if( realvalue>0.0 ){ - while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } - while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } - while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } + while( realvalue>1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; } + while( realvalue>1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } + while( realvalue>10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } if( exp>350 || exp<-350 ){ @@ -468,51 +470,72 @@ static int vxprintf( }else{ flag_rtz = 0; } - /* - ** The "exp+precision" test causes output to be of type etEXP if - ** the precision is too large to fit in buf[]. + /* If exp+precision causes the output to be too big for etFLOAT, then + ** do etEXP instead */ + if( xtype==etFLOAT && exp+precision>=etBUFSIZE-30 ){ + xtype = etEXP; + } + if( xtype==etEXP ){ + e2 = 0; + }else{ + e2 = exp; + } nsd = 0; - if( xtype==etFLOAT && exp+precision0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ - else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd); - if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ - for(exp++; exp<0 && precision>0; precision--, exp++){ - *(bufpt++) = '0'; - } - while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); - *(bufpt--) = 0; /* Null terminate */ - if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - }else{ /* etEXP or etGENERIC */ - flag_dp = (precision>0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */ - if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ - while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd); - bufpt--; /* point to last digit */ - if( flag_rtz && flag_dp ){ /* Remove tail zeros */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - if( exp || flag_exp ){ - *(bufpt++) = aDigits[infop->charset]; - if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ - else { *(bufpt++) = '+'; } - if( exp>=100 ){ - *(bufpt++) = (exp/100)+'0'; /* 100's digit */ - exp %= 100; - } - *(bufpt++) = exp/10+'0'; /* 10's digit */ - *(bufpt++) = exp%10+'0'; /* 1's digit */ + flag_dp = (precision>0) | flag_alternateform | flag_altform2; + /* The sign in front of the number */ + if( prefix ){ + *(bufpt++) = prefix; + } + /* Digits prior to the decimal point */ + if( e2<0 ){ + *(bufpt++) = '0'; + }else{ + for(; e2>=0; e2--){ + *(bufpt++) = et_getdigit(&realvalue,&nsd); } } + /* The decimal point */ + if( flag_dp ){ + *(bufpt++) = '.'; + } + /* "0" digits after the decimal point but before the first + ** significant digit of the number */ + for(e2++; e2<0 && precision>0; precision--, e2++){ + *(bufpt++) = '0'; + } + /* Significant digits after the decimal point */ + while( (precision--)>0 ){ + *(bufpt++) = et_getdigit(&realvalue,&nsd); + } + /* Remove trailing zeros and the "." if no digits follow the "." */ + if( flag_rtz && flag_dp ){ + while( bufpt>buf && bufpt[-1]=='0' ) *(--bufpt) = 0; + if( bufpt>buf && bufpt[-1]=='.' ){ + if( flag_altform2 ){ + *(bufpt++) = '0'; + }else{ + *(--bufpt) = 0; + } + } + } + /* Add the "eNNN" suffix */ + if( flag_exp || (xtype==etEXP && exp) ){ + *(bufpt++) = aDigits[infop->charset]; + if( exp<0 ){ + *(bufpt++) = '-'; exp = -exp; + }else{ + *(bufpt++) = '+'; + } + if( exp>=100 ){ + *(bufpt++) = (exp/100)+'0'; /* 100's digit */ + exp %= 100; + } + *(bufpt++) = exp/10+'0'; /* 10's digit */ + *(bufpt++) = exp%10+'0'; /* 1's digit */ + } + *bufpt = 0; + /* The converted number is in buf[] and zero terminated. Output it. ** Note that the number is in the usual order, not reversed as with ** integer conversions. */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 37113b90d8..630cb22019 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -174,7 +174,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){ ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. */ if( fg & MEM_Real ){ - sqlite3_snprintf(NBFS, z, "%.15g", pMem->r); + sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r); }else{ assert( fg & MEM_Int ); sqlite3_snprintf(NBFS, z, "%lld", pMem->i); diff --git a/test/misc1.test b/test/misc1.test index 6de73dff92..c233cdd3cf 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc1.test,v 1.35 2005/07/16 13:33:21 drh Exp $ +# $Id: misc1.test,v 1.36 2005/08/13 12:59:16 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -316,13 +316,13 @@ do_test misc1-10.7 { } {0 {}} do_test misc1-10.8 { execsql {SELECT x1 FROM manycol WHERE x0=100} -} {102} +} {102.0} do_test misc1-10.9 { catchsql "UPDATE manycol SET x1=x1+1 $::where AND rowid>0" } {0 {}} do_test misc1-10.10 { execsql {SELECT x1 FROM manycol WHERE x0=100} -} {103} +} {103.0} # Make sure the initialization works even if a database is opened while # another process has the database locked. @@ -562,7 +562,7 @@ do_test misc1-17.1 { COMMIT; SELECT TestString FROM RealTable ORDER BY 1; } -} {2 3} +} {2.0 3.0} } finish_test diff --git a/test/printf.test b/test/printf.test index 68ef1e6370..bd57751d9d 100644 --- a/test/printf.test +++ b/test/printf.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite_*_printf() interface. # -# $Id: printf.test,v 1.15 2005/08/13 03:07:47 drh Exp $ +# $Id: printf.test,v 1.16 2005/08/13 12:59:16 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -180,5 +180,30 @@ do_test printf-10.3 { sqlite3_mprintf_double {%d %d %f} 1 1 1e300 } {1 1 1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.000000} +# The non-standard '!' flag on a 'g' conversion forces a decimal point +# and at least one digit on either side of the decimal point. +# +do_test printf-11.1 { + sqlite3_mprintf_double {%d %d %!g} 1 1 1 +} {1 1 1.0} +do_test printf-11.2 { + sqlite3_mprintf_double {%d %d %!g} 1 1 123 +} {1 1 123.0} +do_test printf-11.3 { + sqlite3_mprintf_double {%d %d %!g} 1 1 12.3 +} {1 1 12.3} +do_test printf-11.4 { + sqlite3_mprintf_double {%d %d %!g} 1 1 0.123 +} {1 1 0.123} +do_test printf-11.5 { + sqlite3_mprintf_double {%d %d %!.15g} 1 1 1 +} {1 1 1.0} +do_test printf-11.6 { + sqlite3_mprintf_double {%d %d %!.15g} 1 1 1e10 +} {1 1 10000000000.0} +do_test printf-11.7 { + sqlite3_mprintf_double {%d %d %!.15g} 1 1 1e300 +} {1 1 1.0e+300} + finish_test diff --git a/test/sort.test b/test/sort.test index af8430fe11..87d36fdb72 100644 --- a/test/sort.test +++ b/test/sort.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # -# $Id: sort.test,v 1.20 2005/07/21 03:15:01 drh Exp $ +# $Id: sort.test,v 1.21 2005/08/13 12:59:16 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -106,27 +106,27 @@ do_test sort-2.1.1 { UPDATE t1 SET v='x-2b' where v=='x-0.123'; SELECT v FROM t1 ORDER BY v; } -} {x-123 x-2.15 x-2b x-3.141592653 x-4221 x0.0013442 x1.6 x11} +} {x-123.0 x-2.15 x-2b x-3.141592653 x-4221.0 x0.0013442 x1.6 x11} do_test sort-2.1.2 { execsql { SELECT v FROM t1 ORDER BY substr(v,2,999); } -} {x-123 x-2.15 x-2b x-3.141592653 x-4221 x0.0013442 x1.6 x11} +} {x-123.0 x-2.15 x-2b x-3.141592653 x-4221.0 x0.0013442 x1.6 x11} do_test sort-2.1.3 { execsql { SELECT v FROM t1 ORDER BY substr(v,2,999)+0.0; } -} {x-4221 x-123 x-3.141592653 x-2.15 x-2b x0.0013442 x1.6 x11} +} {x-4221.0 x-123.0 x-3.141592653 x-2.15 x-2b x0.0013442 x1.6 x11} do_test sort-2.1.4 { execsql { SELECT v FROM t1 ORDER BY substr(v,2,999) DESC; } -} {x11 x1.6 x0.0013442 x-4221 x-3.141592653 x-2b x-2.15 x-123} +} {x11 x1.6 x0.0013442 x-4221.0 x-3.141592653 x-2b x-2.15 x-123.0} do_test sort-2.1.5 { execsql { SELECT v FROM t1 ORDER BY substr(v,2,999)+0.0 DESC; } -} {x11 x1.6 x0.0013442 x-2b x-2.15 x-3.141592653 x-123 x-4221} +} {x11 x1.6 x0.0013442 x-2b x-2.15 x-3.141592653 x-123.0 x-4221.0} # This is a bug fix for 2.2.4. # Strings are normally mapped to upper-case for a caseless comparison. @@ -196,17 +196,17 @@ do_test sort-4.6 { execsql { SELECT v FROM t1 ORDER BY 1; } -} {x-123 x-2.15 x-2b x-3.141592653 x-4.0e9 x-4221 x0.0013442 x01234567890123456789 x1.6 x11 x2.7 x5.0e10} +} {x-123.0 x-2.15 x-2b x-3.141592653 x-4.0e9 x-4221.0 x0.0013442 x01234567890123456789 x1.6 x11 x2.7 x5.0e10} do_test sort-4.7 { execsql { SELECT v FROM t1 ORDER BY 1 DESC; } -} {x5.0e10 x2.7 x11 x1.6 x01234567890123456789 x0.0013442 x-4221 x-4.0e9 x-3.141592653 x-2b x-2.15 x-123} +} {x5.0e10 x2.7 x11 x1.6 x01234567890123456789 x0.0013442 x-4221.0 x-4.0e9 x-3.141592653 x-2b x-2.15 x-123.0} do_test sort-4.8 { execsql { SELECT substr(v,2,99) FROM t1 ORDER BY 1; } -} {-123 -2.15 -2b -3.141592653 -4.0e9 -4221 0.0013442 01234567890123456789 1.6 11 2.7 5.0e10} +} {-123.0 -2.15 -2b -3.141592653 -4.0e9 -4221.0 0.0013442 01234567890123456789 1.6 11 2.7 5.0e10} #do_test sort-4.9 { # execsql { # SELECT substr(v,2,99)+0.0 FROM t1 ORDER BY 1;