From: drh Date: Mon, 22 Jun 2020 21:25:37 +0000 (+0000) Subject: Add the decimal_mul() function. X-Git-Tag: version-3.33.0~102^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=427af8dc3d52ea18ddeef7ff35d4a022c0522cca;p=thirdparty%2Fsqlite.git Add the decimal_mul() function. FossilOrigin-Name: 72eee04b67268ad38fd51ff32849f08c0a54cf1b481d5ecb11d77cc9c729ee03 --- diff --git a/ext/misc/decimal.c b/ext/misc/decimal.c index 078e91dc27..341b3c046d 100644 --- a/ext/misc/decimal.c +++ b/ext/misc/decimal.c @@ -298,7 +298,8 @@ cmp_done: } /* -** Remove leading zeros from the Decimal +** Remove leading zeros from before the decimal and +** trailing zeros after the decimal. */ static void decimal_normalize(Decimal *p){ int i; @@ -310,6 +311,10 @@ static void decimal_normalize(Decimal *p){ memmove(p->a, p->a+i, p->nDigit - i); p->nDigit -= i; } + while( p->nFrac && p->a[p->nDigit-1]==0 ){ + p->nFrac--; + p->nDigit--; + } } /* @@ -523,7 +528,58 @@ static void decimalSumFinalize(sqlite3_context *context){ decimal_result(context, p); decimal_clear(p); } - + +/* +** SQL Function: decimal_mul(X, Y) +** +** Return the product of X and Y. +*/ +static void decimalMulFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + Decimal *pA = decimal_new(context, argv[0], 0, 0); + Decimal *pB = decimal_new(context, argv[1], 0, 0); + signed char *acc = 0; + int i, j, k; + if( pA==0 || pA->oom || pA->isNull + || pB==0 || pB->oom || pB->isNull + ){ + goto mul_end; + } + acc = sqlite3_malloc64( pA->nDigit + pB->nDigit + 2 ); + if( acc==0 ){ + sqlite3_result_error_nomem(context); + goto mul_end; + } + memset(acc, 0, pA->nDigit + pB->nDigit + 2); + for(i=pA->nDigit-1; i>=0; i--){ + signed char f = pA->a[i]; + int carry = 0, x; + for(j=pB->nDigit-1, k=i+j+3; j>=0; j--, k--){ + int x = acc[k] + f*pB->a[j] + carry; + acc[k] = x%10; + carry = x/10; + } + x = acc[k] + carry; + acc[k] = x%10; + acc[k-1] += x/10; + } + sqlite3_free(pA->a); + pA->a = acc; + acc = 0; + pA->nDigit += pB->nDigit + 2; + pA->nFrac += pB->nFrac; + pA->sign ^= pB->sign; + decimal_normalize(pA); + decimal_result(context, pA); + +mul_end: + sqlite3_free(acc); + decimal_free(pA); + decimal_free(pB); +} #ifdef _WIN32 __declspec(dllexport) @@ -544,6 +600,7 @@ int sqlite3_decimal_init( { "decimal_cmp", 2, decimalCmpFunc }, { "decimal_add", 2, decimalAddFunc }, { "decimal_sub", 2, decimalSubFunc }, + { "decimal_mul", 2, decimalMulFunc }, }; int i; (void)pzErrMsg; /* Unused parameter */ diff --git a/manifest b/manifest index 94d1d31c6c..4c38728caa 100644 --- a/manifest +++ b/manifest @@ -1,20 +1,17 @@ B 7a876209a678a34c198b54ceef9e3c041f128a14dc73357f6a57cadadaa6cf7b -C An\sextension\sfor\sdoing\sdecimal\sarithmetic\son\sstrings. -D 2020-06-22T19:12:23.405 +C Add\sthe\sdecimal_mul()\sfunction. +D 2020-06-22T21:25:37.690 F Makefile.in 014ad669b4a5809752939c2dea83722992711b464aa56adebca80c5cc98cfdc2 F Makefile.msc 08c8bbedfa51e21b57153370edbfee86d35bbefb53e3773a3e086fe654facccb F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8 -F ext/misc/decimal.c ba7054d9719ceb034012e1744f6e9c1ca5fe2a00a2b83e34faf0c08a43204a64 +F ext/misc/decimal.c 334d8d34c124a8820d814dadbe1ac3daec63f504d5b322eb63671c317d3c6a3e F main.mk c99e452dd4edd0bea28547259421bd6cf24d41d928d24720737efc548958ca39 F src/build.c ba1bbe563a3dc02d5fed20537603181e5289c13ea30ae5e775f552e7557adbfa F src/shell.c.in 7fe12fb6452de32f92bb26ee50524ec31c9d08a1c46376ca00a4ecd27472a14d F src/test1.c fe56c4bcaa2685ca9aa25d817a0ee9345e189aff4a5a71a3d8ba946c7776feb8 -F test/decimal.test 5c486a6baa87fe0cd1c119ffa190bcc70a23e2dd6617baa201eab9e0b0ef2efd +F test/decimal.test c4af0264a0f30e896f617b489d69039932fe5127b02ac221d96f8af31db13826 F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8 -P 067291143a63db924ead4810defb4bc6f195557412f5d1c22299f30d2d9f2a79 -R 4df2ada42f27e695d7e98ee101d73989 -T *branch * decimal -T *sym-decimal * -T -sym-trunk * +P 4c3b85607feb53462ccc8b89bea699fdb132c402eae597afa33cc40a85c32329 +R d79a1d72394e5a5f6c93e9466f2c9aa1 U drh -Z ac0625ef3228b5eb95c4972028cf8994 +Z 3092a9d89a34e083e375231f8e857b54 diff --git a/manifest.uuid b/manifest.uuid index dd813196a9..997afdbdeb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4c3b85607feb53462ccc8b89bea699fdb132c402eae597afa33cc40a85c32329 \ No newline at end of file +72eee04b67268ad38fd51ff32849f08c0a54cf1b481d5ecb11d77cc9c729ee03 \ No newline at end of file diff --git a/test/decimal.test b/test/decimal.test index 1097d14db6..726f470bcc 100644 --- a/test/decimal.test +++ b/test/decimal.test @@ -115,4 +115,14 @@ do_execsql_test 4010 { FROM t3; } {1505500000000000000015055.00000000000000015055} +do_execsql_test 5000 { + WITH RECURSIVE c(x,y,z) AS ( + VALUES(0,'1','1') + UNION ALL + SELECT x+1, decimal_mul(y,'2'), decimal_mul(z,'0.5') + FROM c WHERE x<32 + ) + SELECT count(*) FROM c WHERE decimal_mul(y,z)='1'; +} {33} + finish_test