Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Slightly faster and more precise floating-point to decimal conversion. See forum thread d1387c3979c7f557 for discussion. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
6dea6f4738fc7d003183e94f08bd9518 |
User & Date: | drh 2023-02-24 11:54:40 |
Context
2023-02-24
| ||
13:25 | Add the "number_of_cores" TCL command to the testfixture. (check-in: 16ee5a7b user: drh tags: trunk) | |
12:55 | Merge enhancements from trunk into the anytime-config branch. (check-in: 04b2fdf3 user: drh tags: anytime-config) | |
11:54 | Slightly faster and more precise floating-point to decimal conversion. See forum thread d1387c3979c7f557 for discussion. (check-in: 6dea6f47 user: drh tags: trunk) | |
01:08 | Fix an incorrect optimization that was attempted as part of check-in [18de3a8e6b431a07]. (Closed-Leaf check-in: f32055e8 user: drh tags: fp-conversion) | |
2023-02-23
| ||
14:43 | Fix harmless compiler warnings and a code indentation error. (check-in: de6c5c6b user: drh tags: trunk) | |
Changes
Changes to src/printf.c.
︙ | ︙ | |||
138 139 140 141 142 143 144 145 146 147 148 149 150 151 | d = digit; digit += '0'; *val = (*val - d)*10.0; return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p); | > > > > > > > > > > > > > > | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | d = digit; digit += '0'; *val = (*val - d)*10.0; return (char)digit; } #endif /* SQLITE_OMIT_FLOATING_POINT */ #ifndef SQLITE_OMIT_FLOATING_POINT /* ** "*val" is a u64. *msd is a divisor used to extract the ** most significant digit of *val. Extract that most significant ** digit and return it. */ static char et_getdigit_int(u64 *val, u64 *msd){ u64 x = (*val)/(*msd); *val -= x*(*msd); if( *msd>=10 ) *msd /= 10; return '0' + (char)(x & 15); } #endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** Set the StrAccum object to an error mode. */ void sqlite3StrAccumSetError(StrAccum *p, u8 eError){ assert( eError==SQLITE_NOMEM || eError==SQLITE_TOOBIG ); p->accError = eError; if( p->mxAlloc ) sqlite3_str_reset(p); |
︙ | ︙ | |||
230 231 232 233 234 235 236 237 238 239 240 241 242 243 | etByte done; /* Loop termination flag */ etByte cThousand; /* Thousands separator for %d and %u */ etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ char *zExtra = 0; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ int nsd; /* Number of significant digits returned */ | > > | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | etByte done; /* Loop termination flag */ etByte cThousand; /* Thousands separator for %d and %u */ etByte xtype = etINVALID; /* Conversion paradigm */ u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ sqlite_uint64 longvalue; /* Value for integer types */ LONGDOUBLE_TYPE realvalue; /* Value for real types */ sqlite_uint64 msd; /* Divisor to get most-significant-digit ** of longvalue */ const et_info *infop; /* Pointer to the appropriate info structure */ char *zOut; /* Rendering buffer */ int nOut; /* Size of the rendering buffer */ char *zExtra = 0; /* Malloced memory used by some conversion */ #ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ int nsd; /* Number of significant digits returned */ |
︙ | ︙ | |||
536 537 538 539 540 541 542 543 544 | #endif if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ prefix = flag_prefix; } if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); | > > > > > > > > > > > > > > > | | | | | | | | | | | | < < | | | | | > > | | | | | | | | | | | | | | | > > > | > > | < < < < > > < > > > > > | > > > > | > | 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 | #endif if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; }else{ prefix = flag_prefix; } exp = 0; if( xtype==etGENERIC && precision>0 ) precision--; testcase( precision>0xfff ); if( realvalue<1.0e+16 && realvalue==(LONGDOUBLE_TYPE)(longvalue = (u64)realvalue) ){ /* Number is a pure integer that can be represented as u64 */ for(msd=1; msd*10<=longvalue; msd *= 10, exp++){} if( exp>precision && xtype!=etFLOAT ){ u64 rnd = msd/2; int kk = precision; while( kk-- > 0 ){ rnd /= 10; } longvalue += rnd; } }else{ msd = 0; longvalue = 0; /* To prevent a compiler warning */ idx = precision & 0xfff; rounder = arRound[idx%10]; while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; } if( xtype==etFLOAT ){ double rx = (double)realvalue; sqlite3_uint64 u; int ex; memcpy(&u, &rx, sizeof(u)); ex = -1023 + (int)((u>>52)&0x7ff); if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16; realvalue += rounder; } if( sqlite3IsNaN((double)realvalue) ){ bufpt = "NaN"; length = 3; break; } /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ if( ALWAYS(realvalue>0.0) ){ LONGDOUBLE_TYPE scale = 1.0; while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;} while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; } while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; } realvalue /= scale; while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; } while( realvalue<1.0 ){ realvalue *= 10.0; exp--; } if( exp>350 ){ bufpt = buf; buf[0] = prefix; memcpy(buf+(prefix!=0),"Inf",4); length = 3+(prefix!=0); break; } if( xtype!=etFLOAT ){ realvalue += rounder; if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } } } } /* ** If the field type is etGENERIC, then convert to either etEXP ** or etFLOAT, as appropriate. */ if( xtype==etGENERIC ){ flag_rtz = !flag_alternateform; if( exp<-4 || exp>precision ){ xtype = etEXP; }else{ precision = precision - exp; xtype = etFLOAT; } }else{ flag_rtz = flag_altform2; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = exp; } nsd = 16 + flag_altform2*10; bufpt = buf; { i64 szBufNeeded; /* Size of a temporary buffer needed */ szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15; if( szBufNeeded > etBUFSIZE ){ bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded); if( bufpt==0 ) return; } } zOut = bufpt; flag_dp = (precision>0 ?1: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 if( msd>0 ){ for(; e2>=0; e2--){ *(bufpt++) = et_getdigit_int(&longvalue,&msd); } }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--, e2++){ assert( precision>0 ); *(bufpt++) = '0'; } /* Significant digits after the decimal point */ if( msd>0 ){ while( (precision--)>0 ){ *(bufpt++) = et_getdigit_int(&longvalue,&msd); } }else{ 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[-1]=='0' ) *(--bufpt) = 0; assert( bufpt>zOut ); if( bufpt[-1]=='.' ){ if( flag_altform2 ){ |
︙ | ︙ |
Changes to test/printf.test.
︙ | ︙ | |||
3781 3782 3783 3784 3785 3786 3787 3788 3789 | # 2020-05-23 # ticket 23439ea582241138 # do_execsql_test printf-16.1 { SELECT printf('%.*g',2147483647,0.01); } {0.01} finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 | # 2020-05-23 # ticket 23439ea582241138 # do_execsql_test printf-16.1 { SELECT printf('%.*g',2147483647,0.01); } {0.01} # 2023-02-23 https://sqlite.org/forum/forumpost/d1387c3979c7f557 # Loss of precision when doing floating-point to decimal # conversions on values that have no factional part. # do_execsql_test printf-17.1 { SELECT format('%!.20g', 13.0); } 13.0 do_execsql_test printf-17.2 { SELECT format('%.3e', 199990000.0); } 2.000e+08 do_execsql_test printf-17.3 { SELECT format('%.3f', 199990000.0); } 199990000.000 do_execsql_test printf-17.4 { SELECT format('%.3g', 199990000.0); } 2e+08 do_execsql_test printf-17.5 { SELECT format('%.4e', 199990000.0); } 1.9999e+08 do_execsql_test printf-17.6 { SELECT format('%.4f', 199990000.0); } 199990000.0000 do_execsql_test printf-17.7 { SELECT format('%.4g', 199990000.0); } 2e+08 do_execsql_test printf-17.8 { SELECT format('%.5e', 199990000.0); } 1.99990e+08 do_execsql_test printf-17.9 { SELECT format('%.5f', 199990000.0); } 199990000.00000 do_execsql_test printf-17.10 { SELECT format('%.5g', 199990000.0); } 1.9999e+08 do_execsql_test printf-17.11 { SELECT format('%.30f',1.0000000000000000076e-50); } 0.000000000000000000000000000000 finish_test |