Skip to content

Commit

Permalink
cob_decimal_pow : fix typo and add #1020 ticket fix
Browse files Browse the repository at this point in the history
run_fundametal.at : add #1020 ticket test
  • Loading branch information
denishug committed Jan 26, 2025
1 parent 6ce83a5 commit 14e8b5f
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 99 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@

2025-26-01 Denis Hugonnard-Roche <[email protected]>

* intrinsic.c: Correct #1020 ticket

2024-26-09 Denis Hugonnard-Roche <[email protected]>

* intrinsic.c: Correct C++ comment style to C style
Expand Down
8 changes: 6 additions & 2 deletions libcob/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@

2024-09-26 Denis Hugonnard-Roce <[email protected]>
2025-01-26 Denis Hugonnard-Roche <[email protected]>

* intrinsic.c (cob_decimal_pow) fix #1020 ticket

2024-09-26 Denis Hugonnard-Roche <[email protected]>

* intrinsic.c (cob_decimal_pow) Correct c++ comment style to C
comment style

2024-09-25 Denis Hugonnard-Roce <[email protected]>
2024-09-25 Denis Hugonnard-Roche <[email protected]>

* intrinsic.c (cob_decimal_pow) fixed Bug #925,#925,#989

Expand Down
166 changes: 79 additions & 87 deletions libcob/intrinsic.c
Original file line number Diff line number Diff line change
Expand Up @@ -3154,9 +3154,6 @@ cob_switch_value (const int id)
void
cob_decimal_pow (cob_decimal *pd1, cob_decimal *pd2)
{
int sign_nbr;
int sign_exp;
int power_case;
int negat_result = 0 ;

if (unlikely(pd1->scale == COB_DECIMAL_NAN)) {
Expand All @@ -3167,106 +3164,122 @@ cob_decimal_pow (cob_decimal *pd1, cob_decimal *pd2)
return;
}

sign_nbr = mpz_sgn(pd1->value);
sign_exp = mpz_sgn(pd2->value);
cob_trim_decimal (pd2);
cob_trim_decimal (pd1);

power_case = sign_nbr * sign_exp;
const int sign_nbr = mpz_sgn (pd1->value);
const int sign_exp = mpz_sgn (pd2->value);
const int power_case = sign_nbr * sign_exp;

cob_trim_decimal(pd2);
cob_trim_decimal(pd1);

switch (power_case) {

case 1:
case -1:
if (pd2->scale != 0 && sign_nbr == -1) {
/* Case number < 0 and decimal exponent --> Error */
pd1->scale = COB_DECIMAL_NAN;
cob_set_exception(COB_EC_SIZE_EXPONENTIATION);
return;
}
goto Compute_Power;
if (!power_case) {
/* Exponent OR Number are = 0 */
if (sign_nbr == 0) {
if ( sign_exp == 1) {
/* case 0 ^ Positive number --> zero */
mpz_set_ui (pd1->value, 0UL);
pd1->scale = 0;

break;
}
else {
/* FIX #924 : 0 raised to negative number or 0 */
pd1->scale = COB_DECIMAL_NAN;
cob_set_exception (COB_EC_SIZE_EXPONENTIATION);
}
}
else {
/* Exponent is 0 and Nbr != 0 ---> 1 */
mpz_set_ui (pd1->value, 1UL);
pd1->scale = 0;
}

case 0:
goto Process_case_0;
break;
return;
}

if (pd2->scale != 0 && sign_nbr == -1) {
/* Case number < 0 and decimal exponent --> Error */
pd1->scale = COB_DECIMAL_NAN;
cob_set_exception (COB_EC_SIZE_EXPONENTIATION);
return;
}

Compute_Power:

cob_decimal_get_mpf (cob_mpft , pd1);

/* First Check result size */
/* Fix #925 : Avoid GMPLIB CRASH */

cob_decimal_get_mpf (cob_mpft , pd1);


mpf_set(cob_mpft3,cob_mpft) ;
if ( sign_nbr == -1) {
mpf_abs(cob_mpft3, cob_mpft3) ;
mpf_set (cob_mpft3,cob_mpft) ;
if (sign_nbr == -1) {
mpf_abs (cob_mpft3, cob_mpft3) ;
}
cob_mpf_log10(cob_mpft3, cob_mpft3) ;
cob_mpf_log10 (cob_mpft3, cob_mpft3) ;

cob_decimal_get_mpf (cob_mpft2, pd2) ;
mpf_mul(cob_mpft3, cob_mpft3, cob_mpft2) ;
mpf_abs(cob_mpft3, cob_mpft3) ;
mpf_mul (cob_mpft3, cob_mpft3, cob_mpft2) ;
mpf_abs (cob_mpft3, cob_mpft3) ;

if ( ! ( mpf_cmp_ui(cob_mpft3,COB_MAX_INTERMEDIATE_FLOATING_SIZE + 1 ) < 0 ) ) {
if ( ! (mpf_cmp_ui (cob_mpft3,COB_MAX_INTERMEDIATE_FLOATING_SIZE + 1) < 0) ) {
pd1->scale = COB_DECIMAL_NAN;
cob_set_exception(COB_EC_SIZE_EXPONENTIATION);
cob_set_exception (COB_EC_SIZE_EXPONENTIATION);

return ;
}

/* End Check */

if ( ! (pd2->scale)) {
if (!(pd2->scale)) {
/* Integer Power */

cob_uli_t n ;

/* Integer Power */
if (!mpz_cmp_ui(pd2->value, 1UL)) {
if (!mpz_cmp_ui (pd2->value, 1UL)) {
/* Power is 1 leave as is */
return;
}

if (mpz_sgn (pd2->value) == -1 ) {
if (sign_exp == -1) {
/* Negative power */
mpz_abs (pd2->value, pd2->value); /* to be corrected */
mpz_abs (pd2->value, pd2->value);

mpf_ui_div(cob_mpft, 1UL, cob_mpft) ;
mpf_ui_div (cob_mpft, 1UL, cob_mpft) ;
}

if (mpz_fits_ulong_p (pd2->value)) {
if (mpz_fits_ulong_p (pd2->value)) {
/* Positive power */
n = mpz_get_ui (pd2->value);
n = mpz_get_ui (pd2->value);

mpf_pow_ui (cob_mpft, cob_mpft, n);
mpf_pow_ui (cob_mpft, cob_mpft, n);

cob_decimal_set_mpf(pd1, cob_mpft);
cob_decimal_set_mpf (pd1, cob_mpft);

cob_trim_decimal(pd1);
cob_trim_decimal (pd1);

if (sign_exp == -1) {
/* Keep exponent value unchanged --> FIX #1020 */
mpz_mul_si (pd2->value, pd2->value, -1L) ;
}

return;
}
}

/*
* At this point we know that :
*
* 1) the result will not crash gmp
* 2) the absolute value of exponent is too large
* 1) the result will not crash gmp
* 2) Exponent is integer
* 3) the absolute value of exponent is too large
* to fits ulong
* --> Compute the result sign and Fallthrough to Taylor series compute
*
*/

if (sign_nbr == -1) {
/* Fix #989 */
if (mpz_odd_p(pd2->value)) {
if (mpz_odd_p (pd2->value)) {
negat_result = 1;
}

}
}
}

/*
Expand All @@ -3278,54 +3291,33 @@ cob_decimal_pow (cob_decimal *pd1, cob_decimal *pd2)
*/

/* Compute a ^ b */
mpz_abs(pd1->value, pd1->value);
mpz_abs(pd2->value, pd2->value);
mpz_abs (pd1->value, pd1->value);
mpz_abs (pd2->value, pd2->value);

cob_decimal_get_mpf(cob_mpft, pd1);
cob_decimal_get_mpf(cob_mpft2, pd2);
cob_decimal_get_mpf (cob_mpft, pd1);
cob_decimal_get_mpf (cob_mpft2, pd2);

cob_mpf_log(cob_mpft, cob_mpft);
mpf_mul(cob_mpft, cob_mpft, cob_mpft2);
cob_mpf_log (cob_mpft, cob_mpft);
mpf_mul (cob_mpft, cob_mpft, cob_mpft2);

cob_mpf_exp(cob_mpft2, cob_mpft);
cob_mpf_exp (cob_mpft2, cob_mpft);

/* if negative exponent compute 1 / (a^b) */
if (sign_exp == -1) {
mpf_set_ui(cob_mpft, 1UL);
mpf_div(cob_mpft2, cob_mpft, cob_mpft2);
mpf_set_ui (cob_mpft, 1UL);
mpf_div (cob_mpft2, cob_mpft, cob_mpft2);
/* Keep exponent value unchanged --> FIX #1020 */
mpz_mul_si (pd2->value, pd2->value, -1L) ;
}

cob_decimal_set_mpf(pd1, cob_mpft2);
cob_decimal_set_mpf (pd1, cob_mpft2);

if (negat_result) {
mpz_neg(pd1->value, pd1->value);
mpz_neg (pd1->value, pd1->value);
}

cob_trim_decimal(pd1);

return;

Process_case_0:
if (sign_nbr == 0) {
if ( sign_exp == 1) {
/* case 0 ^ Positive number --> zero */
mpz_set_ui(pd1->value, 0UL);
pd1->scale = 0;

}
else {
/* FIX #924 */
pd1->scale = COB_DECIMAL_NAN;
cob_set_exception(COB_EC_SIZE_EXPONENTIATION);
}
}
else {
/* Exponent is zero ---> 1 */
mpz_set_ui(pd1->value, 1UL);
pd1->scale = 0;
}
cob_trim_decimal (pd1);

return;
}

/* Indirect field get/put functions */
Expand Down
Loading

0 comments on commit 14e8b5f

Please sign in to comment.