SQLite

Check-in [a1b57288]
Login

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: a1b57288d7076cb9e26ac429f01e9264240d6af26243a195b2065cf667bb8bb6
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
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/func.c.

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);
  }







|







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
506




507
508
509
510
511
512
513
          iRound = -precision;
        }else if( xtype==etGENERIC ){
          if( precision==0 ) precision = 1;
          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';







|
>
>
>
>







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





1015

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
int sqlite3Atoi(const char *z){
  int x = 0;
  sqlite3GetInt32(z, &x);
  return x;
}

/*





** Return true if the first N characters of string z[] are '9'

*/
static SQLITE_NOINLINE int allNines(const char *z, int N){
  int i;
  assert( N>0 );
  for(i=0; i<N; i++){
    if( z[i]!='9' ) return 0;
  }
  return 1;
}

/*
** Decode a floating-point value into an approximate decimal
** representation.
**
** If iRound<=0 then round to -iRound significant digits to the







>
>
>
>
>
|
>

|

|
|
|
<
|







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
1056






1057
1058
1059
1060
1061
1062
1063
**   (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.






*/
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;







|
>
>
>
>
>
>







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
1171
1172
1173
1174
1175
1176
1177
1178
1179
      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' && p->n>iRound+5
                        && allNines(&z[iRound+1],p->n-iRound-3))
    ){
      int j = iRound-1;
      while( 1 /*exit-by-break*/ ){
        z[j]++;
        if( z[j]<='9' ) break;
        z[j] = '0';
        if( j==0 ){







|
<







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 ){