SQLite

Check-in [3dec4b35]
Login

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

Overview
Comment: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
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | round-up
Files: files | file ages | folders
SHA3-256: 3dec4b35ecd68a4dace7ea17f046231e25dd79d70f4702b82461cf98fd6f850e
User & Date: drh 2024-06-10 18:30:44
Original Comment: 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.
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)
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
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
514
515
516
517
        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+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';







>




















>
>
>
>
>
|
<
<
<
<







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.

1048
1049
1050
1051
1052
1053
1054
1055
1056
1057

1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
** 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 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;







|
|

>
|



<
<
|
|
<
<







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062


1063
1064


1065
1066
1067
1068
1069
1070
1071
** 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;