SQLite

Check-in Differences
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From 56af06fa12104a1f To 3dec4b35ecd68a4d

2024-06-11
14:36
Change constant expressions to pre-computed constants, because apparently MSVC on ARM requires that. Forum thread 4feb1685cced0a8e. (check-in: 6c103aee6f user: drh tags: trunk)
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: 3dec4b35ec 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: a1b57288d7 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: 4a790d3b28 user: drh tags: round-up)
12:43
Improved header comment on the sqlite3FpDecode() implementation. For the fpdecode() SQL function (available in debug builds only) limit the value of the third parameter (mxRound) to be positive. (check-in: 56af06fa12 user: drh tags: trunk)
2024-06-09
17:34
Disable the omit-noop-join optimization when there are 64 or more terms in the ORDER BY clause. (check-in: 40de393979 user: drh tags: trunk)

Changes to src/func.c.
457
458
459
460
461
462
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
  ** 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);
  }
  sqlite3_result_double(context, r);
}
#endif

/*
** Allocate nByte bytes of space using sqlite3Malloc(). If the







>
|





|







457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  ** 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{
    sqlite3 *db = sqlite3_context_db_handle(context);
    zBuf = sqlite3MPrintf(db,"%!.*f",n,r);
    if( zBuf==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
    sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
    sqlite3DbFreeNN(db, zBuf);
  }
  sqlite3_result_double(context, r);
}
#endif

/*
** Allocate nByte bytes of space using sqlite3Malloc(). If the
Changes to src/printf.c.
479
480
481
482
483
484
485

486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505





506
507
508
509
510
511
512
513
        break;
      case etFLOAT:
      case etEXP:
      case etGENERIC: {
        FpDecode s;
        int iRound;
        int j;


        if( bArgList ){
          realvalue = getDoubleArg(pArgList);
        }else{
          realvalue = va_arg(ap,double);
        }
        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( xtype==etFLOAT ){
          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';







>




















>
>
>
>
>
|







479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
        break;
      case etFLOAT:
      case etEXP:
      case etGENERIC: {
        FpDecode s;
        int iRound;
        int j;
        int mx;

        if( bArgList ){
          realvalue = getDoubleArg(pArgList);
        }else{
          realvalue = va_arg(ap,double);
        }
        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( xtype==etFLOAT ){
          iRound = -precision;
        }else if( xtype==etGENERIC ){
          if( precision==0 ) precision = 1;
          iRound = precision;
        }else{
          iRound = precision+1;
        }
        if( flag_altform2 ){
          mx = 26 + ((pAccum->printfFlags & SQLITE_PRINTF_INTERNAL)!=0);
        }else{
          mx = 16;
        }
        sqlite3FpDecode(&s, realvalue, iRound, mx);
        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.
1006
1007
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
1036
** string is not an integer, just return 0.
*/
int sqlite3Atoi(const char *z){
  int x = 0;
  sqlite3GetInt32(z, &x);
  return x;
}


















/*
** Decode a floating-point value into an approximate decimal
** representation.
**
** If iRound<=0 then round to -iRound significant digits to the
** the left of the decimal point, or to a maximum of mxRound total
** significant digits.
**
** If iRound>0 round to min(iRound,mxRound) significant digits total.
**
** mxRound must be positive.
**
** The significant digits of the decimal representation are
** stored in p->z[] which is a often (but not always) a pointer
** into the middle of p->zBuf[].  There are p->n significant digits.
** The p->z[] array is *not* zero-terminated.


















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







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1006
1007
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
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
** string is not an integer, just return 0.
*/
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
** the left of the decimal point, or to a maximum of mxRound total
** significant digits.
**
** If iRound>0 round to min(iRound,mxRound) significant digits total.
**
** mxRound must be positive.
**
** The significant digits of the decimal representation are
** stored in p->z[] which is a often (but not always) a pointer
** into the middle of p->zBuf[].  There are p->n significant digits.
** The p->z[] array is *not* zero-terminated.
**
** Rounding Behavior:
**
**   (1)  If the next digit is 3 or less, then truncate.  Do not round.
**
**   (2)  If the next digit is 5 or more, then round up.
**
**   (3)  Round up if the next digit is a 4 followed by three or
**        more 9 digits and all significant digits after the 4 are
**        9 and mxRound is 27.  Otherwise truncate.
**
** Rule (3) is used by the built-in round() function to do more aggressive
** rounding 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.
** And mxRound is only 27 if the internal sqlite3MPrintf() formatter is
** used and the "!" flag is included.
*/
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;
1136
1137
1138
1139
1140
1141
1142
1143
1144


1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159

1160
1161
1162
1163
1164
1165
1166
1167
      p->n++;
      p->iDP++;
    }
  }
  if( iRound>0 && (iRound<p->n || p->n>mxRound) ){
    char *z = &p->zBuf[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--;
        }
      }
    }

  }
  p->z = &p->zBuf[i+1];
  assert( i+p->n < sizeof(p->zBuf) );
  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







<
|
>
>







|







>
|







1171
1172
1173
1174
1175
1176
1177

1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
      p->n++;
      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 ){
          p->z[i--] = '1';
          iRound++;
          p->iDP++;
          break;
        }else{
          j--;
        }
      }
    }
    p->n = iRound;
 }
  p->z = &p->zBuf[i+1];
  assert( i+p->n < sizeof(p->zBuf) );
  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
Added test/round2.test.






















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 2024-06-10
#
# 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.
#
#***********************************************************************
# 
#  https://sqlite.org/forum/forumpost/c0753dfb2d5d7f75
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix round2

load_static_extension db stmtrand
do_execsql_test 1.1 {
  WITH RECURSIVE
    c(n) AS (VALUES(0) UNION ALL SELECT n+1 FROM c WHERE n<100000),
    r(a,b) AS MATERIALIZED (SELECT stmtrand()%100000, stmtrand()%100000 FROM c),
    f(x,y,n) AS (
       SELECT CAST(format('%d.%d5',a,b) AS real),
              CAST(format('%d.%d6',a,b) AS real),
               length(format('%d',b)) FROM r)
    SELECT x, n, round(x,n), round(y,n) FROM f
     WHERE round(x,n)<>round(y,n);

} {}
do_execsql_test 1.2 {
  SELECT round(0.15,1);
} 0.2
do_execsql_test 1.3 {
  SELECT round(0.14999999999999999,1);
} 0.2
do_execsql_test 1.4 {
  SELECT round(0.1499999999999999944488848768742172978818416595458984375,1);
} 0.2


finish_test