* [Tarantool-patches] [PATCH 0/2] update decNumber for SQL @ 2020-06-05 15:41 Chris Sosnin 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString Chris Sosnin 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number Chris Sosnin 0 siblings, 2 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-05 15:41 UTC (permalink / raw) To: tarantool-patches, sergepetrenko, v.shpilevoy branch: https://github.com/tarantool/decNumber/tree/ksosnin/utilities-for-sql issue: https://github.com/tarantool/tarantool/issues/4415 Chris Sosnin (2): Allow leading and trailing whitespaces in FromString Add IsWhole method for checking the fractional part of a number decNumber.c | 74 ++++++++++++++++++++++++++++++++++++++++++----------- decNumber.h | 1 + 2 files changed, 60 insertions(+), 15 deletions(-) -- 2.21.1 (Apple Git-122.3) ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString 2020-06-05 15:41 [Tarantool-patches] [PATCH 0/2] update decNumber for SQL Chris Sosnin @ 2020-06-05 15:41 ` Chris Sosnin 2020-06-06 13:48 ` Serge Petrenko 2020-06-11 17:06 ` Vladislav Shpilevoy 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number Chris Sosnin 1 sibling, 2 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-05 15:41 UTC (permalink / raw) To: tarantool-patches, sergepetrenko, v.shpilevoy This is needed for SQL, since these whitespaces are allowed in conversions from string. Needed for tarantool/tarantool#4415 --- decNumber.c | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/decNumber.c b/decNumber.c index 85deb13..7c53bc3 100644 --- a/decNumber.c +++ b/decNumber.c @@ -555,9 +555,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], Unit *allocres=NULL; // -> allocated result, iff allocated Int d=0; // count of digits found in decimal part const char *dotchar=NULL; // where dot was found - const char *cfirst=chars; // -> first character of decimal part + const char *cfirst=NULL; // -> first character of decimal part const char *last=NULL; // -> last digit of decimal part - const char *c; // work + const char *c, *p; // work Unit *up; // .. #if DECDPUN>1 Int cut, out; // .. @@ -571,6 +571,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], #endif do { // status & malloc protection + for (; *chars==' '; ++chars); // skip leading whitespaces + cfirst=chars; + for (c=chars;; c++) { // -> input character if (*c>='0' && *c<='9') { // test for Arabic digit last=c; @@ -590,13 +593,14 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], cfirst++; continue;} } + for (p=c; *p==' '; ++p); // *c is not a digit, or a valid +, -, or '.' break; } // c if (last==NULL) { // no digits yet status=DEC_Conversion_syntax;// assume the worst - if (*c=='\0') break; // and no more to come... + if (*p=='\0') break; // and no more to come... #if DECSUBSET // if subset then infinities and NaNs are not allowed if (!set->extended) break; // hopeless @@ -626,7 +630,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], // now either nothing, or nnnn payload, expected // -> start of integer and skip leading 0s [including plain 0] for (cfirst=c; *cfirst=='0';) cfirst++; - if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s + for (p=cfirst; *p==' '; ++p); + if (*p=='\0') { // "NaN" or "sNaN", maybe with all 0s status=0; // it's good break; // .. } @@ -635,7 +640,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], if (*c<'0' || *c>'9') break; // test for Arabic digit last=c; } - if (*c!='\0') break; // not all digits + for (p=c; *p==' '; ++p); + if (*p!='\0') break; // not all digits if (d>set->digits-1) { // [NB: payload in a decNumber can be full length unless // clamped, in which case can only be digits-1] @@ -647,7 +653,7 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], bits=dn->bits; // for copy-back } // last==NULL - else if (*c!='\0') { // more to process... + else if (p==c && *p!='\0') { // more to process... // had some digits; exponent is only valid sequence now Flag nege; // 1=negative exponent const char *firstexp; // -> first significant exponent digit @@ -659,16 +665,18 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], c++; // to (possible) sign if (*c=='-') {nege=1; c++;} else if (*c=='+') c++; - if (*c=='\0') break; - - for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros + for (p=c; *p==' '; ++p); + if (*p=='\0') break; + // strip insignificant zeros + for (; *c=='0' && *(c+1)!='\0' && *(c+1)!=' ';) c++; firstexp=c; // save exponent digit place for (; ;c++) { if (*c<'0' || *c>'9') break; // not a digit exponent=X10(exponent)+(Int)*c-(Int)'0'; } // c // if not now on a '\0', *c must not be a digit - if (*c!='\0') break; + for (p=c; *p==' '; ++p); + if (*p!='\0') break; // (this next test must be after the syntax checks) // if it was too long the exponent may have wrapped, so check @@ -681,6 +689,11 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], status=0; // is OK } // stuff after digits + else if (*p!='\0') { // whitespaces in the middle + status=DEC_Conversion_syntax; + break; + } + // Here when whole string has been inspected; syntax is good // cfirst->first digit (never dot), last->last digit (ditto) @@ -7739,12 +7752,13 @@ static decNumber *decDecap(decNumber *dn, Int drop) { /* if (decBiStr(test, "mike", "MIKE")) ... */ /* ------------------------------------------------------------------ */ static Flag decBiStr(const char *targ, const char *str1, const char *str2) { - for (;;targ++, str1++, str2++) { + const char *end=strchr(targ, ' '); + if (end==NULL) + end=targ+strlen(targ); + for (;targ<end; targ++, str1++, str2++) { if (*targ!=*str1 && *targ!=*str2) return 0; - // *targ has a match in one (or both, if terminator) - if (*targ=='\0') break; - } // forever - return 1; + } // for + return *str1=='\0'; } // decBiStr /* ------------------------------------------------------------------ */ -- 2.21.1 (Apple Git-122.3) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString Chris Sosnin @ 2020-06-06 13:48 ` Serge Petrenko 2020-06-07 12:38 ` Chris Sosnin 2020-06-11 17:06 ` Vladislav Shpilevoy 1 sibling, 1 reply; 12+ messages in thread From: Serge Petrenko @ 2020-06-06 13:48 UTC (permalink / raw) To: Chris Sosnin; +Cc: tarantool-patches, v.shpilevoy 05.06.2020 18:41, Chris Sosnin пишет: > This is needed for SQL, since these whitespaces are allowed in > conversions from string. > > Needed for tarantool/tarantool#4415 Hi! Thanks for the patch! See one comment below. > --- > decNumber.c | 44 +++++++++++++++++++++++++++++--------------- > 1 file changed, 29 insertions(+), 15 deletions(-) > > diff --git a/decNumber.c b/decNumber.c > index 85deb13..7c53bc3 100644 > --- a/decNumber.c > +++ b/decNumber.c > @@ -555,9 +555,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > Unit *allocres=NULL; // -> allocated result, iff allocated > Int d=0; // count of digits found in decimal part > const char *dotchar=NULL; // where dot was found > - const char *cfirst=chars; // -> first character of decimal part > + const char *cfirst=NULL; // -> first character of decimal part > const char *last=NULL; // -> last digit of decimal part > - const char *c; // work > + const char *c, *p; // work > Unit *up; // .. > #if DECDPUN>1 > Int cut, out; // .. > @@ -571,6 +571,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > #endif > > do { // status & malloc protection > + for (; *chars==' '; ++chars); // skip leading whitespaces > + cfirst=chars; > + > for (c=chars;; c++) { // -> input character > if (*c>='0' && *c<='9') { // test for Arabic digit > last=c; > @@ -590,13 +593,14 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > cfirst++; > continue;} > } > + for (p=c; *p==' '; ++p); Looks like this `for` loop should go below. > // *c is not a digit, or a valid +, -, or '.' > break; > } // c > Here, ^ (This guy's formatting is confusing as hell, I know) > if (last==NULL) { // no digits yet > status=DEC_Conversion_syntax;// assume the worst > - if (*c=='\0') break; // and no more to come... > + if (*p=='\0') break; // and no more to come... > #if DECSUBSET > // if subset then infinities and NaNs are not allowed > if (!set->extended) break; // hopeless > @@ -626,7 +630,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > // now either nothing, or nnnn payload, expected > // -> start of integer and skip leading 0s [including plain 0] > for (cfirst=c; *cfirst=='0';) cfirst++; > - if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s > + for (p=cfirst; *p==' '; ++p); > + if (*p=='\0') { // "NaN" or "sNaN", maybe with all 0s > status=0; // it's good > break; // .. > } > @@ -635,7 +640,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > if (*c<'0' || *c>'9') break; // test for Arabic digit > last=c; > } > - if (*c!='\0') break; // not all digits > + for (p=c; *p==' '; ++p); > + if (*p!='\0') break; // not all digits > if (d>set->digits-1) { > // [NB: payload in a decNumber can be full length unless > // clamped, in which case can only be digits-1] > @@ -647,7 +653,7 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > bits=dn->bits; // for copy-back > } // last==NULL > > - else if (*c!='\0') { // more to process... > + else if (p==c && *p!='\0') { // more to process... > // had some digits; exponent is only valid sequence now > Flag nege; // 1=negative exponent > const char *firstexp; // -> first significant exponent digit > @@ -659,16 +665,18 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > c++; // to (possible) sign > if (*c=='-') {nege=1; c++;} > else if (*c=='+') c++; > - if (*c=='\0') break; > - > - for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros > + for (p=c; *p==' '; ++p); > + if (*p=='\0') break; > + // strip insignificant zeros > + for (; *c=='0' && *(c+1)!='\0' && *(c+1)!=' ';) c++; > firstexp=c; // save exponent digit place > for (; ;c++) { > if (*c<'0' || *c>'9') break; // not a digit > exponent=X10(exponent)+(Int)*c-(Int)'0'; > } // c > // if not now on a '\0', *c must not be a digit > - if (*c!='\0') break; > + for (p=c; *p==' '; ++p); > + if (*p!='\0') break; > > // (this next test must be after the syntax checks) > // if it was too long the exponent may have wrapped, so check > @@ -681,6 +689,11 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], > status=0; // is OK > } // stuff after digits > > + else if (*p!='\0') { // whitespaces in the middle > + status=DEC_Conversion_syntax; > + break; > + } > + > // Here when whole string has been inspected; syntax is good > // cfirst->first digit (never dot), last->last digit (ditto) > > @@ -7739,12 +7752,13 @@ static decNumber *decDecap(decNumber *dn, Int drop) { > /* if (decBiStr(test, "mike", "MIKE")) ... */ > /* ------------------------------------------------------------------ */ > static Flag decBiStr(const char *targ, const char *str1, const char *str2) { > - for (;;targ++, str1++, str2++) { > + const char *end=strchr(targ, ' '); > + if (end==NULL) > + end=targ+strlen(targ); > + for (;targ<end; targ++, str1++, str2++) { > if (*targ!=*str1 && *targ!=*str2) return 0; > - // *targ has a match in one (or both, if terminator) > - if (*targ=='\0') break; > - } // forever > - return 1; > + } // for > + return *str1=='\0'; > } // decBiStr > > /* ------------------------------------------------------------------ */ -- Serge Petrenko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString 2020-06-06 13:48 ` Serge Petrenko @ 2020-06-07 12:38 ` Chris Sosnin 0 siblings, 0 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-07 12:38 UTC (permalink / raw) To: Serge Petrenko; +Cc: tarantool-patches, Vladislav Shpilevoy Hi! Thank you for the review! > On 6 Jun 2020, at 16:48, Serge Petrenko <sergepetrenko@tarantool.org> wrote: > > > 05.06.2020 18:41, Chris Sosnin пишет: >> This is needed for SQL, since these whitespaces are allowed in >> conversions from string. >> >> Needed for tarantool/tarantool#4415 > > Hi! Thanks for the patch! > > See one comment below. > >> --- >> decNumber.c | 44 +++++++++++++++++++++++++++++--------------- >> 1 file changed, 29 insertions(+), 15 deletions(-) >> >> diff --git a/decNumber.c b/decNumber.c >> index 85deb13..7c53bc3 100644 >> --- a/decNumber.c >> +++ b/decNumber.c >> @@ -555,9 +555,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> Unit *allocres=NULL; // -> allocated result, iff allocated >> Int d=0; // count of digits found in decimal part >> const char *dotchar=NULL; // where dot was found >> - const char *cfirst=chars; // -> first character of decimal part >> + const char *cfirst=NULL; // -> first character of decimal part >> const char *last=NULL; // -> last digit of decimal part >> - const char *c; // work >> + const char *c, *p; // work >> Unit *up; // .. >> #if DECDPUN>1 >> Int cut, out; // .. >> @@ -571,6 +571,9 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> #endif >> do { // status & malloc protection >> + for (; *chars==' '; ++chars); // skip leading whitespaces >> + cfirst=chars; >> + >> for (c=chars;; c++) { // -> input character >> if (*c>='0' && *c<='9') { // test for Arabic digit >> last=c; >> @@ -590,13 +593,14 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> cfirst++; >> continue;} >> } >> + for (p=c; *p==' '; ++p); > Looks like this `for` loop should go below. >> // *c is not a digit, or a valid +, -, or '.' >> break; >> } // c >> > > Here, ^ (This guy's formatting is confusing as hell, I know) You are right, thank you for the catch! I applied the change on the branch. > >> if (last==NULL) { // no digits yet >> status=DEC_Conversion_syntax;// assume the worst >> - if (*c=='\0') break; // and no more to come... >> + if (*p=='\0') break; // and no more to come... >> #if DECSUBSET >> // if subset then infinities and NaNs are not allowed >> if (!set->extended) break; // hopeless >> @@ -626,7 +630,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> // now either nothing, or nnnn payload, expected >> // -> start of integer and skip leading 0s [including plain 0] >> for (cfirst=c; *cfirst=='0';) cfirst++; >> - if (*cfirst=='\0') { // "NaN" or "sNaN", maybe with all 0s >> + for (p=cfirst; *p==' '; ++p); >> + if (*p=='\0') { // "NaN" or "sNaN", maybe with all 0s >> status=0; // it's good >> break; // .. >> } >> @@ -635,7 +640,8 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> if (*c<'0' || *c>'9') break; // test for Arabic digit >> last=c; >> } >> - if (*c!='\0') break; // not all digits >> + for (p=c; *p==' '; ++p); >> + if (*p!='\0') break; // not all digits >> if (d>set->digits-1) { >> // [NB: payload in a decNumber can be full length unless >> // clamped, in which case can only be digits-1] >> @@ -647,7 +653,7 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> bits=dn->bits; // for copy-back >> } // last==NULL >> - else if (*c!='\0') { // more to process... >> + else if (p==c && *p!='\0') { // more to process... >> // had some digits; exponent is only valid sequence now >> Flag nege; // 1=negative exponent >> const char *firstexp; // -> first significant exponent digit >> @@ -659,16 +665,18 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> c++; // to (possible) sign >> if (*c=='-') {nege=1; c++;} >> else if (*c=='+') c++; >> - if (*c=='\0') break; >> - >> - for (; *c=='0' && *(c+1)!='\0';) c++; // strip insignificant zeros >> + for (p=c; *p==' '; ++p); >> + if (*p=='\0') break; >> + // strip insignificant zeros >> + for (; *c=='0' && *(c+1)!='\0' && *(c+1)!=' ';) c++; >> firstexp=c; // save exponent digit place >> for (; ;c++) { >> if (*c<'0' || *c>'9') break; // not a digit >> exponent=X10(exponent)+(Int)*c-(Int)'0'; >> } // c >> // if not now on a '\0', *c must not be a digit >> - if (*c!='\0') break; >> + for (p=c; *p==' '; ++p); >> + if (*p!='\0') break; >> // (this next test must be after the syntax checks) >> // if it was too long the exponent may have wrapped, so check >> @@ -681,6 +689,11 @@ decNumber * decNumberFromString(decNumber *dn, const char chars[], >> status=0; // is OK >> } // stuff after digits >> + else if (*p!='\0') { // whitespaces in the middle >> + status=DEC_Conversion_syntax; >> + break; >> + } >> + >> // Here when whole string has been inspected; syntax is good >> // cfirst->first digit (never dot), last->last digit (ditto) >> @@ -7739,12 +7752,13 @@ static decNumber *decDecap(decNumber *dn, Int drop) { >> /* if (decBiStr(test, "mike", "MIKE")) ... */ >> /* ------------------------------------------------------------------ */ >> static Flag decBiStr(const char *targ, const char *str1, const char *str2) { >> - for (;;targ++, str1++, str2++) { >> + const char *end=strchr(targ, ' '); >> + if (end==NULL) >> + end=targ+strlen(targ); >> + for (;targ<end; targ++, str1++, str2++) { >> if (*targ!=*str1 && *targ!=*str2) return 0; >> - // *targ has a match in one (or both, if terminator) >> - if (*targ=='\0') break; >> - } // forever >> - return 1; >> + } // for >> + return *str1=='\0'; >> } // decBiStr >> /* ------------------------------------------------------------------ */ > > -- > Serge Petrenko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString Chris Sosnin 2020-06-06 13:48 ` Serge Petrenko @ 2020-06-11 17:06 ` Vladislav Shpilevoy 2020-06-11 20:14 ` Chris Sosnin 1 sibling, 1 reply; 12+ messages in thread From: Vladislav Shpilevoy @ 2020-06-11 17:06 UTC (permalink / raw) To: Chris Sosnin, tarantool-patches, sergepetrenko Hi! Thanks for the patch! I am afraid this may be a dead end. You didn't check for tabs, new lines, \r, and whatever else can be treated as a whitespace. Moreover, for some other code it may be necessary not to skip whitespaces. Why can't you trim whitespace symbols in SQL code? sql_atoi64(), for example, trims them, before calling strtoll()/strtoull(). To trim right spaces you could make this function return a position where did it stop, so as to ensure that all the rest is whitespaces, in SQL code. That also would be consistent with strtoll()/strtoull(). ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString 2020-06-11 17:06 ` Vladislav Shpilevoy @ 2020-06-11 20:14 ` Chris Sosnin 0 siblings, 0 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-11 20:14 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tarantool-patches Hi! Thank you for the review! > On 11 Jun 2020, at 20:06, Vladislav Shpilevoy <v.shpilevoy@tarantool.org> wrote: > > Hi! Thanks for the patch! > > I am afraid this may be a dead end. You didn't check for tabs, new lines, > \r, and whatever else can be treated as a whitespace. Moreover, for some other > code it may be necessary not to skip whitespaces. Why can't you trim whitespace > symbols in SQL code? sql_atoi64(), for example, trims them, before calling > strtoll()/strtoull(). I made this change here to unify the behavior, but perhaps this makes sense only in SQL? In this case I can make a wrapper similar to sql_atoi64() you mentioned. And if I understand correctly, I should use isspace instead of char comparison. > > To trim right spaces you could make this function return a position where > did it stop, so as to ensure that all the rest is whitespaces, in SQL code. > That also would be consistent with strtoll()/strtoull(). I like this idea, will work on it in v2. ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-05 15:41 [Tarantool-patches] [PATCH 0/2] update decNumber for SQL Chris Sosnin 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString Chris Sosnin @ 2020-06-05 15:41 ` Chris Sosnin 2020-06-06 14:17 ` Serge Petrenko 2020-06-11 17:06 ` Vladislav Shpilevoy 1 sibling, 2 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-05 15:41 UTC (permalink / raw) To: tarantool-patches, sergepetrenko, v.shpilevoy Currently there is no efficient way to do this. Needed for tarantool/tarantool#4415 --- decNumber.c | 30 ++++++++++++++++++++++++++++++ decNumber.h | 1 + 2 files changed, 31 insertions(+) diff --git a/decNumber.c b/decNumber.c index 7c53bc3..f4ad927 100644 --- a/decNumber.c +++ b/decNumber.c @@ -501,6 +501,36 @@ uLong decNumberToUInt64(const decNumber *dn, decContext *set) { return 0; } // decNumberToUInt64 +Flag decNumberIsWhole(const decNumber *dn) { + const Unit *up=dn->lsu; + if (dn->exponent>=0) { + return 1; + } + else { + Int count=-dn->exponent; + // spin up whole units until reach the Unit with the unit digit + for (; count>=DECDPUN; up++) { + if (*up!=0) return 0; + count-=DECDPUN; + } + if (count==0) return 1; // [a multiple of DECDPUN] + else { // [not multiple of DECDPUN] + Int rem, theInt=0; // work + // slice off fraction digits and check for non-zero + #if DECDPUN<=4 + theInt=QUOT10(*up, count); + rem=*up-theInt*powers[count]; + #else + rem=*up%powers[count]; // slice off discards + theInt=*up/powers[count]; + #endif + if (rem!=0) return 0; + up++; + } + } + return 1; + } // decNumberIsWhole + /* ------------------------------------------------------------------ */ /* to-scientific-string -- conversion to numeric string */ /* to-engineering-string -- conversion to numeric string */ diff --git a/decNumber.h b/decNumber.h index 85a3f3f..71ab27f 100644 --- a/decNumber.h +++ b/decNumber.h @@ -169,6 +169,7 @@ decNumber * decNumberTrim(decNumber *); const char * decNumberVersion(void); decNumber * decNumberZero(decNumber *); + uint8_t decNumberIsWhole(const decNumber *dn); /* Functions for testing decNumbers (normality depends on context) */ int32_t decNumberIsNormal(const decNumber *, decContext *); -- 2.21.1 (Apple Git-122.3) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number Chris Sosnin @ 2020-06-06 14:17 ` Serge Petrenko 2020-06-07 12:40 ` Chris Sosnin 2020-06-11 17:06 ` Vladislav Shpilevoy 1 sibling, 1 reply; 12+ messages in thread From: Serge Petrenko @ 2020-06-06 14:17 UTC (permalink / raw) To: Chris Sosnin; +Cc: tarantool-patches, v.shpilevoy 05.06.2020 18:41, Chris Sosnin пишет: > Currently there is no efficient way to do this. > > Needed for tarantool/tarantool#4415 Thanks for the patch! > --- > decNumber.c | 30 ++++++++++++++++++++++++++++++ > decNumber.h | 1 + > 2 files changed, 31 insertions(+) > > diff --git a/decNumber.c b/decNumber.c > index 7c53bc3..f4ad927 100644 > --- a/decNumber.c > +++ b/decNumber.c > @@ -501,6 +501,36 @@ uLong decNumberToUInt64(const decNumber *dn, decContext *set) { > return 0; > } // decNumberToUInt64 > > +Flag decNumberIsWhole(const decNumber *dn) { > + const Unit *up=dn->lsu; > + if (dn->exponent>=0) { > + return 1; > + } > + else { > + Int count=-dn->exponent; > + // spin up whole units until reach the Unit with the unit digit > + for (; count>=DECDPUN; up++) { > + if (*up!=0) return 0; > + count-=DECDPUN; > + } > + if (count==0) return 1; // [a multiple of DECDPUN] > + else { // [not multiple of DECDPUN] > + Int rem, theInt=0; // work > + // slice off fraction digits and check for non-zero > + #if DECDPUN<=4 > + theInt=QUOT10(*up, count); > + rem=*up-theInt*powers[count]; > + #else > + rem=*up%powers[count]; // slice off discards > + theInt=*up/powers[count]; > + #endif > + if (rem!=0) return 0; > + up++; > + } > + } > + return 1; > + } // decNumberIsWhole > + Consider this diff: diff --git a/decNumber.c b/decNumber.c index f4ad927..acc3fb1 100644 --- a/decNumber.c +++ b/decNumber.c @@ -515,17 +515,14 @@ Flag decNumberIsWhole(const decNumber *dn) { } if (count==0) return 1; // [a multiple of DECDPUN] else { // [not multiple of DECDPUN] - Int rem, theInt=0; // work + Int rem; // work // slice off fraction digits and check for non-zero #if DECDPUN<=4 - theInt=QUOT10(*up, count); - rem=*up-theInt*powers[count]; + rem=*up-QUOT10(*up, count)*powers[count]; #else rem=*up%powers[count]; // slice off discards - theInt=*up/powers[count]; #endif if (rem!=0) return 0; - up++; } } return 1; > /* ------------------------------------------------------------------ */ > /* to-scientific-string -- conversion to numeric string */ > /* to-engineering-string -- conversion to numeric string */ > diff --git a/decNumber.h b/decNumber.h > index 85a3f3f..71ab27f 100644 > --- a/decNumber.h > +++ b/decNumber.h > @@ -169,6 +169,7 @@ > decNumber * decNumberTrim(decNumber *); > const char * decNumberVersion(void); > decNumber * decNumberZero(decNumber *); > + uint8_t decNumberIsWhole(const decNumber *dn); > > /* Functions for testing decNumbers (normality depends on context) */ > int32_t decNumberIsNormal(const decNumber *, decContext *); -- Serge Petrenko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-06 14:17 ` Serge Petrenko @ 2020-06-07 12:40 ` Chris Sosnin 2020-06-08 8:59 ` Serge Petrenko 0 siblings, 1 reply; 12+ messages in thread From: Chris Sosnin @ 2020-06-07 12:40 UTC (permalink / raw) To: Serge Petrenko; +Cc: tarantool-patches, Vladislav Shpilevoy Thank you for the review! > On 6 Jun 2020, at 17:17, Serge Petrenko <sergepetrenko@tarantool.org> wrote: > > 05.06.2020 18:41, Chris Sosnin пишет: >> Currently there is no efficient way to do this. >> >> Needed for tarantool/tarantool#4415 > Thanks for the patch! >> --- >> decNumber.c | 30 ++++++++++++++++++++++++++++++ >> decNumber.h | 1 + >> 2 files changed, 31 insertions(+) >> >> diff --git a/decNumber.c b/decNumber.c >> index 7c53bc3..f4ad927 100644 >> --- a/decNumber.c >> +++ b/decNumber.c >> @@ -501,6 +501,36 @@ uLong decNumberToUInt64(const decNumber *dn, decContext *set) { >> return 0; >> } // decNumberToUInt64 >> +Flag decNumberIsWhole(const decNumber *dn) { >> + const Unit *up=dn->lsu; >> + if (dn->exponent>=0) { >> + return 1; >> + } >> + else { >> + Int count=-dn->exponent; >> + // spin up whole units until reach the Unit with the unit digit >> + for (; count>=DECDPUN; up++) { >> + if (*up!=0) return 0; >> + count-=DECDPUN; >> + } >> + if (count==0) return 1; // [a multiple of DECDPUN] >> + else { // [not multiple of DECDPUN] >> + Int rem, theInt=0; // work >> + // slice off fraction digits and check for non-zero >> + #if DECDPUN<=4 >> + theInt=QUOT10(*up, count); >> + rem=*up-theInt*powers[count]; >> + #else >> + rem=*up%powers[count]; // slice off discards >> + theInt=*up/powers[count]; >> + #endif >> + if (rem!=0) return 0; >> + up++; >> + } >> + } >> + return 1; >> + } // decNumberIsWhole >> + > > Consider this diff: > > diff --git a/decNumber.c b/decNumber.c > index f4ad927..acc3fb1 100644 > --- a/decNumber.c > +++ b/decNumber.c > @@ -515,17 +515,14 @@ Flag decNumberIsWhole(const decNumber *dn) { > } > if (count==0) return 1; // [a multiple of DECDPUN] > else { // [not multiple of DECDPUN] > - Int rem, theInt=0; // work > + Int rem; // work > // slice off fraction digits and check for non-zero > #if DECDPUN<=4 > - theInt=QUOT10(*up, count); > - rem=*up-theInt*powers[count]; > + rem=*up-QUOT10(*up, count)*powers[count]; > #else > rem=*up%powers[count]; // slice off discards > - theInt=*up/powers[count]; > #endif > if (rem!=0) return 0; > - up++; > } > } > return 1; I agree, looks much better, thanks! Applied on the branch. > >> /* ------------------------------------------------------------------ */ >> /* to-scientific-string -- conversion to numeric string */ >> /* to-engineering-string -- conversion to numeric string */ >> diff --git a/decNumber.h b/decNumber.h >> index 85a3f3f..71ab27f 100644 >> --- a/decNumber.h >> +++ b/decNumber.h >> @@ -169,6 +169,7 @@ >> decNumber * decNumberTrim(decNumber *); >> const char * decNumberVersion(void); >> decNumber * decNumberZero(decNumber *); >> + uint8_t decNumberIsWhole(const decNumber *dn); >> /* Functions for testing decNumbers (normality depends on context) */ >> int32_t decNumberIsNormal(const decNumber *, decContext *); > > -- > Serge Petrenko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-07 12:40 ` Chris Sosnin @ 2020-06-08 8:59 ` Serge Petrenko 0 siblings, 0 replies; 12+ messages in thread From: Serge Petrenko @ 2020-06-08 8:59 UTC (permalink / raw) To: Chris Sosnin; +Cc: tarantool-patches, Vladislav Shpilevoy 07.06.2020 15:40, Chris Sosnin пишет: > Thank you for the review! > >> On 6 Jun 2020, at 17:17, Serge Petrenko <sergepetrenko@tarantool.org> wrote: >> >> 05.06.2020 18:41, Chris Sosnin пишет: >>> Currently there is no efficient way to do this. >>> >>> Needed for tarantool/tarantool#4415 >> Thanks for the patch! >>> --- >>> decNumber.c | 30 ++++++++++++++++++++++++++++++ >>> decNumber.h | 1 + >>> 2 files changed, 31 insertions(+) >>> >>> diff --git a/decNumber.c b/decNumber.c >>> index 7c53bc3..f4ad927 100644 >>> --- a/decNumber.c >>> +++ b/decNumber.c >>> @@ -501,6 +501,36 @@ uLong decNumberToUInt64(const decNumber *dn, decContext *set) { >>> return 0; >>> } // decNumberToUInt64 >>> +Flag decNumberIsWhole(const decNumber *dn) { >>> + const Unit *up=dn->lsu; >>> + if (dn->exponent>=0) { >>> + return 1; >>> + } >>> + else { >>> + Int count=-dn->exponent; >>> + // spin up whole units until reach the Unit with the unit digit >>> + for (; count>=DECDPUN; up++) { >>> + if (*up!=0) return 0; >>> + count-=DECDPUN; >>> + } >>> + if (count==0) return 1; // [a multiple of DECDPUN] >>> + else { // [not multiple of DECDPUN] >>> + Int rem, theInt=0; // work >>> + // slice off fraction digits and check for non-zero >>> + #if DECDPUN<=4 >>> + theInt=QUOT10(*up, count); >>> + rem=*up-theInt*powers[count]; >>> + #else >>> + rem=*up%powers[count]; // slice off discards >>> + theInt=*up/powers[count]; >>> + #endif >>> + if (rem!=0) return 0; >>> + up++; >>> + } >>> + } >>> + return 1; >>> + } // decNumberIsWhole >>> + >> Consider this diff: >> >> diff --git a/decNumber.c b/decNumber.c >> index f4ad927..acc3fb1 100644 >> --- a/decNumber.c >> +++ b/decNumber.c >> @@ -515,17 +515,14 @@ Flag decNumberIsWhole(const decNumber *dn) { >> } >> if (count==0) return 1; // [a multiple of DECDPUN] >> else { // [not multiple of DECDPUN] >> - Int rem, theInt=0; // work >> + Int rem; // work >> // slice off fraction digits and check for non-zero >> #if DECDPUN<=4 >> - theInt=QUOT10(*up, count); >> - rem=*up-theInt*powers[count]; >> + rem=*up-QUOT10(*up, count)*powers[count]; >> #else >> rem=*up%powers[count]; // slice off discards >> - theInt=*up/powers[count]; >> #endif >> if (rem!=0) return 0; >> - up++; >> } >> } >> return 1; > I agree, looks much better, thanks! > Applied on the branch. Thanks for the fixes! Both patches LGTM. > >>> /* ------------------------------------------------------------------ */ >>> /* to-scientific-string -- conversion to numeric string */ >>> /* to-engineering-string -- conversion to numeric string */ >>> diff --git a/decNumber.h b/decNumber.h >>> index 85a3f3f..71ab27f 100644 >>> --- a/decNumber.h >>> +++ b/decNumber.h >>> @@ -169,6 +169,7 @@ >>> decNumber * decNumberTrim(decNumber *); >>> const char * decNumberVersion(void); >>> decNumber * decNumberZero(decNumber *); >>> + uint8_t decNumberIsWhole(const decNumber *dn); >>> /* Functions for testing decNumbers (normality depends on context) */ >>> int32_t decNumberIsNormal(const decNumber *, decContext *); >> -- >> Serge Petrenko -- Serge Petrenko ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number Chris Sosnin 2020-06-06 14:17 ` Serge Petrenko @ 2020-06-11 17:06 ` Vladislav Shpilevoy 2020-06-11 20:30 ` Chris Sosnin 1 sibling, 1 reply; 12+ messages in thread From: Vladislav Shpilevoy @ 2020-06-11 17:06 UTC (permalink / raw) To: Chris Sosnin, tarantool-patches, sergepetrenko I guess you rather need name IsInt. 'Whole' has a different meaning. Why do you need it, btw? Why decNumberToInt64() and decNumberToUInt64() are not enough? The only usecase for this new function I can imagine is an attempt to shrink a decimal value into a normal integer. Which are either int64_t or uint64_t. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number 2020-06-11 17:06 ` Vladislav Shpilevoy @ 2020-06-11 20:30 ` Chris Sosnin 0 siblings, 0 replies; 12+ messages in thread From: Chris Sosnin @ 2020-06-11 20:30 UTC (permalink / raw) To: Vladislav Shpilevoy; +Cc: tarantool-patches Thank you for the review! > On 11 Jun 2020, at 20:06, Vladislav Shpilevoy <v.shpilevoy@tarantool.org> wrote: > > I guess you rather need name IsInt. 'Whole' has a different > meaning. You can say “whole number” — a number without decimal part. But IsInt sounds better, I agree. > > Why do you need it, btw? Why decNumberToInt64() and decNumberToUInt64() > are not enough? The only usecase for this new function I can > imagine is an attempt to shrink a decimal value into a normal integer. > Which are either int64_t or uint64_t. In case of doubles sqlVdbeIntValue returns 0 if an argument has no decimal part (and doesn’t overflow) and not 0 otherwise, but it always modifies a pointer to an integer, because some functions may still use the result of conversion. So I tried to make the behavior the same. decimal_to_* functions always trim the value and don’t perform the check cause of decimal_to_integer call, decNumber ones require context (these also don’t really check for zero-decimal part — instead comparing exponent with 0, making 1.000 a bad argument), so we need new wrappers which will do almost the same thing but with an extra check. ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2020-06-11 20:30 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-06-05 15:41 [Tarantool-patches] [PATCH 0/2] update decNumber for SQL Chris Sosnin 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 1/2] Allow leading and trailing whitespaces in FromString Chris Sosnin 2020-06-06 13:48 ` Serge Petrenko 2020-06-07 12:38 ` Chris Sosnin 2020-06-11 17:06 ` Vladislav Shpilevoy 2020-06-11 20:14 ` Chris Sosnin 2020-06-05 15:41 ` [Tarantool-patches] [PATCH 2/2] Add IsWhole method for checking the fractional part of a number Chris Sosnin 2020-06-06 14:17 ` Serge Petrenko 2020-06-07 12:40 ` Chris Sosnin 2020-06-08 8:59 ` Serge Petrenko 2020-06-11 17:06 ` Vladislav Shpilevoy 2020-06-11 20:30 ` Chris Sosnin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox