Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | More aggressive rounding behavior for the round() function only. Format() still uses the classic behavior, and the same behavior exhibited by printf() in glibc. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | round-up |
Files: | files | file ages | folders |
SHA3-256: |
a1b57288d7076cb9e26ac429f01e9264 |
User & Date: | drh 2024-06-10 18:10:35 |
Context
2024-06-10
| ||
18:30 | The aggressive rounding behavior is now only accessible using the internal sqlite3MPrintf() function. The round() SQL function uses that internal function so it can access the aggressive rounding. But ordinary extensions and the format() SQL function cannot. Update: Superseded by round-up-2 branch (Closed-Leaf check-in: 3dec4b35 user: drh tags: round-up) | |
18:10 | More aggressive rounding behavior for the round() function only. Format() still uses the classic behavior, and the same behavior exhibited by printf() in glibc. (check-in: a1b57288 user: drh tags: round-up) | |
14:31 | Change the rounding behavior of float point to decimal conversions such that if the next digit is 4 but the value is within one epsilon of the next digit being 5 and if the epsilon is small compared the number of digits to be rendered, then go ahead and round up anyhow, even though the correct behavior would be to round down. (check-in: 4a790d3b user: drh tags: round-up) | |
Changes
Changes to src/func.c.
︙ | ︙ | |||
457 458 459 460 461 462 463 | ** otherwise use printf. */ if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ /* The value has no fractional part so there is nothing to round */ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ | | | 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 | ** otherwise use printf. */ if( r<-4503599627370496.0 || r>+4503599627370496.0 ){ /* The value has no fractional part so there is nothing to round */ }else if( n==0 ){ r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5))); }else{ zBuf = sqlite3_mprintf("%#!.*f",n,r); if( zBuf==0 ){ sqlite3_result_error_nomem(context); return; } sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); sqlite3_free(zBuf); } |
︙ | ︙ |
Changes to src/printf.c.
︙ | ︙ | |||
499 500 501 502 503 504 505 | iRound = -precision; }else if( xtype==etGENERIC ){ if( precision==0 ) precision = 1; iRound = precision; }else{ iRound = precision+1; } | | > > > > | 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 | iRound = -precision; }else if( xtype==etGENERIC ){ if( precision==0 ) precision = 1; iRound = precision; }else{ iRound = precision+1; } sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26+flag_alternateform : 16); /* ^^^^^^^^^^^^^^^^^^^--- Undocumented behavior: ** When both '#' and '!' flags are present, the rounding behavior ** is changed. See "rule 3" in the sqlite3FpDecode docs. */ if( s.isSpecial ){ if( s.isSpecial==2 ){ bufpt = flag_zeropad ? "null" : "NaN"; length = sqlite3Strlen30(bufpt); break; }else if( flag_zeropad ){ s.z[0] = '9'; |
︙ | ︙ |
Changes to src/util.c.
︙ | ︙ | |||
1008 1009 1010 1011 1012 1013 1014 | int sqlite3Atoi(const char *z){ int x = 0; sqlite3GetInt32(z, &x); return x; } /* | > > > > > | > | | | | < | | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 | int sqlite3Atoi(const char *z){ int x = 0; sqlite3GetInt32(z, &x); return x; } /* ** z[] is the complete list of digits for a floating point conversion. ** The z[iRound] character is a 4. This routine checks to see if the ** iRound-1 character should be rounded up even though z[iRound] is not ** a 5. ** ** Return true if the 4 is followed by at least three 9s and all digits ** past the 4 are 9s out to the limit of precision. */ static SQLITE_NOINLINE int shouldRoundUp(const char *z, int n, int iRound){ int i; assert( z[iRound]=='4' ); for(i=iRound+1; i<n && z[i]=='9'; i++){} if( i<iRound+3 ) return 0; return i>15; } /* ** Decode a floating-point value into an approximate decimal ** representation. ** ** If iRound<=0 then round to -iRound significant digits to the |
︙ | ︙ | |||
1049 1050 1051 1052 1053 1054 1055 | ** (3) Round up if the next digit is a 4 followed by three or ** more 9 digits and all digits after the 4 up to the ** antipenultimate digit are 9. Otherwise truncate. ** ** Rule (3) is so that things like round(0.15,1) will come out as 0.2 ** even though the stored value for 0.15 is really ** 0.1499999999999999944488848768742172978818416595458984375 and ought | | > > > > > > | 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 | ** (3) Round up if the next digit is a 4 followed by three or ** more 9 digits and all digits after the 4 up to the ** antipenultimate digit are 9. Otherwise truncate. ** ** Rule (3) is so that things like round(0.15,1) will come out as 0.2 ** even though the stored value for 0.15 is really ** 0.1499999999999999944488848768742172978818416595458984375 and ought ** to round down to 0.1. Rule (3) is only applied if mxRound==27. ** ** This routine is normally only called from printf()/format(). In that ** case, mxRound is usually 16 but is increased to 26 with the "!" flag. ** Undocumented behavior: mxRound is 27 with the "#" and "!" flags. The ** round() function uses this undocumented flag combination to activate ** rounding rule (3). */ void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){ int i; u64 v; int e, exp = 0; p->isSpecial = 0; p->z = p->zBuf; |
︙ | ︙ | |||
1164 1165 1166 1167 1168 1169 1170 | p->iDP++; } } if( iRound>0 && (iRound<p->n || p->n>mxRound) ){ char *z = &p->zBuf[i+1]; if( iRound>mxRound ) iRound = mxRound; if( z[iRound]>='5' | | < | 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 | p->iDP++; } } if( iRound>0 && (iRound<p->n || p->n>mxRound) ){ char *z = &p->zBuf[i+1]; if( iRound>mxRound ) iRound = mxRound; if( z[iRound]>='5' || (z[iRound]=='4' && mxRound>=27 && shouldRoundUp(z, p->n, iRound)) ){ int j = iRound-1; while( 1 /*exit-by-break*/ ){ z[j]++; if( z[j]<='9' ) break; z[j] = '0'; if( j==0 ){ |
︙ | ︙ |