1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Refactor BCMath bundledlib and extension (#10774)

* ext/bcmath: coding style: use indentation

And add braces to block statements, as the current code was pretty much unreadable with how inconsistent it was.

* ext/bcmath: Remove some useless header inclusions

* ext/bcmath: Use standard C99 bool type instead of char

* ext/bcmath: Include specific headers instead of config.h

* Restructure definitions to reduce header inclusions

* Use size_t as a more appropriate type

* Remove unused variable full_scale

* Refactor bc_raisemod() to get rid of Zend dependencies

This separates the concerns of throwing exceptions back into the PHP_FUNCTION instead of being the responsibility of the library

* Refactor bc_raise() to get rid of Zend dependencies

This separates the concerns of throwing exceptions back into the PHP_FUNCTION instead of being the responsibility of the library

* Refactor bc_divmod() and bc_modulo() to return bool

Return false on division by 0 attempt instead of -1 and true on success instead of 0

* Refactor bc_divide() to return bool

Return false on division by 0 attempt instead of -1 and true on success instead of 0
This commit is contained in:
George Peter Banyard
2023-07-24 16:42:34 +01:00
committed by GitHub
parent 0f20527768
commit 68247c02d5
26 changed files with 1370 additions and 1415 deletions

View File

@@ -32,6 +32,9 @@
ZEND_DECLARE_MODULE_GLOBALS(bcmath)
static PHP_GINIT_FUNCTION(bcmath);
static PHP_GSHUTDOWN_FUNCTION(bcmath);
static PHP_MINIT_FUNCTION(bcmath);
static PHP_MSHUTDOWN_FUNCTION(bcmath);
static PHP_MINFO_FUNCTION(bcmath);
zend_module_entry bcmath_module_entry = {
STANDARD_MODULE_HEADER,
@@ -341,15 +344,13 @@ PHP_FUNCTION(bcdiv)
goto cleanup;
}
switch (bc_divide(first, second, &result, scale)) {
case 0: /* OK */
RETVAL_STR(bc_num2str_ex(result, scale));
break;
case -1: /* division by zero */
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
break;
if (!bc_divide(first, second, &result, scale)) {
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
goto cleanup;
}
RETVAL_STR(bc_num2str_ex(result, scale));
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
@@ -397,15 +398,13 @@ PHP_FUNCTION(bcmod)
goto cleanup;
}
switch (bc_modulo(first, second, &result, scale)) {
case 0:
RETVAL_STR(bc_num2str_ex(result, scale));
break;
case -1:
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
break;
if (!bc_modulo(first, second, &result, scale)) {
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
goto cleanup;
}
RETVAL_STR(bc_num2str_ex(result, scale));
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
@@ -417,16 +416,16 @@ PHP_FUNCTION(bcmod)
/* {{{ Returns the value of an arbitrary precision number raised to the power of another reduced by a modulus */
PHP_FUNCTION(bcpowmod)
{
zend_string *left, *right, *modulus;
zend_string *base_str, *exponent_str, *modulus_str;
zend_long scale_param;
bool scale_param_is_null = 1;
bc_num first, second, mod, result;
bc_num bc_base, bc_expo, bc_modulus, result;
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_STR(left)
Z_PARAM_STR(right)
Z_PARAM_STR(modulus)
Z_PARAM_STR(base_str)
Z_PARAM_STR(exponent_str)
Z_PARAM_STR(modulus_str)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
ZEND_PARSE_PARAMETERS_END();
@@ -440,34 +439,53 @@ PHP_FUNCTION(bcpowmod)
scale = (int) scale_param;
}
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&mod);
bc_init_num(&bc_base);
bc_init_num(&bc_expo);
bc_init_num(&bc_modulus);
bc_init_num(&result);
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
if (php_str2num(&bc_base, ZSTR_VAL(base_str)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
if (php_str2num(&bc_expo, ZSTR_VAL(exponent_str)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
if (php_str2num(&mod, ZSTR_VAL(modulus)) == FAILURE) {
if (php_str2num(&bc_modulus, ZSTR_VAL(modulus_str)) == FAILURE) {
zend_argument_value_error(3, "is not well-formed");
goto cleanup;
}
if (bc_raisemod(first, second, mod, &result, scale) == SUCCESS) {
RETVAL_STR(bc_num2str_ex(result, scale));
raise_mod_status status = bc_raisemod(bc_base, bc_expo, bc_modulus, &result, scale);
switch (status) {
case BASE_HAS_FRACTIONAL:
zend_argument_value_error(1, "cannot have a fractional part");
goto cleanup;
case EXPO_HAS_FRACTIONAL:
zend_argument_value_error(2, "cannot have a fractional part");
goto cleanup;
case EXPO_IS_NEGATIVE:
zend_argument_value_error(2, "must be greater than or equal to 0");
goto cleanup;
case MOD_HAS_FRACTIONAL:
zend_argument_value_error(3, "cannot have a fractional part");
goto cleanup;
case MOD_IS_ZERO:
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
goto cleanup;
case OK:
RETVAL_STR(bc_num2str_ex(result, scale));
break;
EMPTY_SWITCH_DEFAULT_CASE();
}
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&mod);
bc_free_num(&bc_base);
bc_free_num(&bc_expo);
bc_free_num(&bc_modulus);
bc_free_num(&result);
};
}
@@ -476,15 +494,15 @@ PHP_FUNCTION(bcpowmod)
/* {{{ Returns the value of an arbitrary precision number raised to the power of another */
PHP_FUNCTION(bcpow)
{
zend_string *left, *right;
zend_string *base_str, *exponent_str;
zend_long scale_param;
bool scale_param_is_null = 1;
bc_num first, second, result;
bc_num first, bc_exponent, result;
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
Z_PARAM_STR(right)
Z_PARAM_STR(base_str)
Z_PARAM_STR(exponent_str)
Z_PARAM_OPTIONAL
Z_PARAM_LONG_OR_NULL(scale_param, scale_param_is_null)
ZEND_PARSE_PARAMETERS_END();
@@ -499,26 +517,37 @@ PHP_FUNCTION(bcpow)
}
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&bc_exponent);
bc_init_num(&result);
if (php_str2num(&first, ZSTR_VAL(left)) == FAILURE) {
if (php_str2num(&first, ZSTR_VAL(base_str)) == FAILURE) {
zend_argument_value_error(1, "is not well-formed");
goto cleanup;
}
if (php_str2num(&second, ZSTR_VAL(right)) == FAILURE) {
if (php_str2num(&bc_exponent, ZSTR_VAL(exponent_str)) == FAILURE) {
zend_argument_value_error(2, "is not well-formed");
goto cleanup;
}
bc_raise (first, second, &result, scale);
/* Check the exponent for scale digits and convert to a long. */
if (bc_exponent->n_scale != 0) {
zend_argument_value_error(2, "cannot have a fractional part");
goto cleanup;
}
long exponent = bc_num2long(bc_exponent);
if (exponent == 0 && (bc_exponent->n_len > 1 || bc_exponent->n_value[0] != 0)) {
zend_argument_value_error(2, "is too large");
goto cleanup;
}
bc_raise(first, exponent, &result, scale);
RETVAL_STR(bc_num2str_ex(result, scale));
cleanup: {
bc_free_num(&first);
bc_free_num(&second);
bc_free_num(&bc_exponent);
bc_free_num(&result);
};
}

View File

@@ -29,55 +29,49 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include <string.h>
/* Here is the full add routine that takes care of negative numbers.
N1 is added to N2 and the result placed into RESULT. SCALE_MIN
is the minimum scale for the result. */
void bc_add (bc_num n1, bc_num n2, bc_num *result, int scale_min)
void bc_add (bc_num n1, bc_num n2, bc_num *result, size_t scale_min)
{
bc_num sum = NULL;
int cmp_res;
int res_scale;
bc_num sum = NULL;
int cmp_res;
size_t res_scale;
if (n1->n_sign == n2->n_sign)
{
sum = _bc_do_add (n1, n2, scale_min);
sum->n_sign = n1->n_sign;
}
else
{
/* subtraction must be done. */
cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */
switch (cmp_res)
{
case -1:
/* n1 is less than n2, subtract n1 from n2. */
sum = _bc_do_sub (n2, n1, scale_min);
sum->n_sign = n2->n_sign;
break;
case 0:
/* They are equal! return zero with the correct scale! */
res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
sum = bc_new_num (1, res_scale);
memset (sum->n_value, 0, res_scale+1);
break;
case 1:
/* n2 is less than n1, subtract n2 from n1. */
sum = _bc_do_sub (n1, n2, scale_min);
sum->n_sign = n1->n_sign;
if (n1->n_sign == n2->n_sign) {
sum = _bc_do_add (n1, n2, scale_min);
sum->n_sign = n1->n_sign;
} else {
/* subtraction must be done. */
/* Compare magnitudes. */
cmp_res = _bc_do_compare(n1, n2, false, false);
switch (cmp_res) {
case -1:
/* n1 is less than n2, subtract n1 from n2. */
sum = _bc_do_sub (n2, n1, scale_min);
sum->n_sign = n2->n_sign;
break;
case 0:
/* They are equal! return zero with the correct scale! */
res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
sum = bc_new_num (1, res_scale);
memset (sum->n_value, 0, res_scale+1);
break;
case 1:
/* n2 is less than n1, subtract n2 from n1. */
sum = _bc_do_sub (n1, n2, scale_min);
sum->n_sign = n1->n_sign;
}
}
}
/* Clean up and return. */
bc_free_num (result);
*result = sum;
/* Clean up and return. */
bc_free_num (result);
*result = sum;
}

View File

@@ -32,32 +32,33 @@
#ifndef _BCMATH_H_
#define _BCMATH_H_
#include <stddef.h>
typedef enum {PLUS, MINUS} sign;
typedef struct bc_struct *bc_num;
typedef struct bc_struct
{
sign n_sign;
int n_len; /* The number of digits before the decimal point. */
int n_scale; /* The number of digits after the decimal point. */
int n_refs; /* The number of pointers to this number. */
char *n_ptr; /* The pointer to the actual storage.
If NULL, n_value points to the inside of
another number (bc_multiply...) and should
not be "freed." */
char *n_value; /* The number. Not zero char terminated.
May not point to the same place as n_ptr as
in the case of leading zeros generated. */
} bc_struct;
typedef struct bc_struct {
sign n_sign;
size_t n_len; /* The number of digits before the decimal point. */
size_t n_scale; /* The number of digits after the decimal point. */
int n_refs; /* The number of pointers to this number. */
char *n_ptr; /* The pointer to the actual storage.
If NULL, n_value points to the inside of another number
(bc_multiply...) and should not be "freed." */
char *n_value; /* The number. Not zero char terminated.
May not point to the same place as n_ptr as
in the case of leading zeros generated. */
} bc_struct;
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "zend.h"
#include <stdbool.h>
#include "php.h" /* Needed for safe_pemalloc() in init.c */
#include "../../php_bcmath.h"
#include "zend_string.h"
#include "../../php_bcmath.h" /* Needed for BCG() macro */
/* The base used in storing the numbers in n_value above.
Currently this MUST be 10. */
@@ -77,11 +78,6 @@ typedef struct bc_struct
#define MIN(a, b) ((a)>(b)?(b):(a))
#define ODD(a) ((a)&1)
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef LONG_MAX
#define LONG_MAX 0x7ffffff
#endif
@@ -91,17 +87,17 @@ typedef struct bc_struct
void bc_init_numbers(void);
bc_num _bc_new_num_ex(int length, int scale, int persistent);
bc_num _bc_new_num_ex(size_t length, size_t scale, bool persistent);
void _bc_free_num_ex(bc_num *num, int persistent);
void _bc_free_num_ex(bc_num *num, bool persistent);
bc_num bc_copy_num(bc_num num);
void bc_init_num(bc_num *num);
int bc_str2num(bc_num *num, char *str, int scale);
bool bc_str2num(bc_num *num, char *str, size_t scale);
zend_string *bc_num2str_ex(bc_num num, int scale);
zend_string *bc_num2str_ex(bc_num num, size_t scale);
void bc_int2num(bc_num *num, int val);
@@ -109,33 +105,44 @@ long bc_num2long(bc_num num);
int bc_compare(bc_num n1, bc_num n2);
char bc_is_zero(bc_num num);
bool bc_is_zero(bc_num num);
char bc_is_zero_for_scale(bc_num num, int scale);
bool bc_is_zero_for_scale(bc_num num, size_t scale);
bool bc_is_near_zero(bc_num num, int scale);
bool bc_is_near_zero(bc_num num, size_t scale);
bool bc_is_neg(bc_num num);
void bc_add(bc_num n1, bc_num n2, bc_num *result, int scale_min);
void bc_add(bc_num n1, bc_num n2, bc_num *result, size_t scale_min);
void bc_sub(bc_num n1, bc_num n2, bc_num *result, int scale_min);
void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min);
void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, int scale);
void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale);
int bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale);
bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale);
int bc_modulo(bc_num num1, bc_num num2, bc_num *resul, int scale);
bool bc_modulo(bc_num num1, bc_num num2, bc_num *resul, size_t scale);
int bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, int scale);
bool bc_divmod(bc_num num1, bc_num num2, bc_num *quo, bc_num *rem, size_t scale);
zend_result bc_raisemod(bc_num base, bc_num expo, bc_num mo, bc_num *result, int scale);
typedef enum {
OK,
BASE_HAS_FRACTIONAL,
EXPO_HAS_FRACTIONAL,
EXPO_IS_NEGATIVE,
MOD_HAS_FRACTIONAL,
MOD_IS_ZERO
} raise_mod_status;
void bc_raise(bc_num num1, bc_num num2, bc_num *resul, int scale);
raise_mod_status bc_raisemod(bc_num base, bc_num exponent, bc_num mod, bc_num *result, size_t scale);
bool bc_sqrt(bc_num *num, int scale);
void bc_raise(bc_num base, long exponent, bc_num *resul, size_t scale);
void bc_out_num(bc_num num, int o_base, void (* out_char)(char), int leading_zero);
void bc_raise_bc_exponent(bc_num base, bc_num exponent, bc_num *resul, size_t scale);
bool bc_sqrt(bc_num *num, size_t scale);
void bc_out_num(bc_num num, int o_base, void (* out_char)(char), bool leading_zero);
/* Prototypes needed for external utility routines. */
#define bc_new_num(length, scale) _bc_new_num_ex((length), (scale), 0)

View File

@@ -29,12 +29,8 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include "bcmath.h"
#include "private.h"
@@ -45,110 +41,103 @@
int _bc_do_compare(bc_num n1, bc_num n2, bool use_sign, bool ignore_last)
{
char *n1ptr, *n2ptr;
int count;
char *n1ptr, *n2ptr;
/* First, compare signs. */
if (use_sign && n1->n_sign != n2->n_sign)
{
if (n1->n_sign == PLUS)
return (1); /* Positive N1 > Negative N2 */
else
return (-1); /* Negative N1 < Positive N1 */
}
/* First, compare signs. */
if (use_sign && n1->n_sign != n2->n_sign) {
if (n1->n_sign == PLUS) {
return (1); /* Positive N1 > Negative N2 */
} else {
return (-1); /* Negative N1 < Positive N1 */
}
}
/* Now compare the magnitude. */
if (n1->n_len != n2->n_len)
{
if (n1->n_len > n2->n_len)
{
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS)
return (1);
else
return (-1);
/* Now compare the magnitude. */
if (n1->n_len != n2->n_len) {
if (n1->n_len > n2->n_len) {
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (1);
} else {
return (-1);
}
} else {
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (-1);
} else {
return (1);
}
}
}
else
{
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS)
return (-1);
else
return (1);
}
}
/* If we get here, they have the same number of integer digits.
check the integer part and the equal length part of the fraction. */
count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
n1ptr = n1->n_value;
n2ptr = n2->n_value;
/* If we get here, they have the same number of integer digits.
check the integer part and the equal length part of the fraction. */
size_t count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
n1ptr = n1->n_value;
n2ptr = n2->n_value;
while ((count > 0) && (*n1ptr == *n2ptr))
{
n1ptr++;
n2ptr++;
count--;
}
if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
return (0);
if (count != 0)
{
if (*n1ptr > *n2ptr)
{
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS)
return (1);
else
return (-1);
while ((count > 0) && (*n1ptr == *n2ptr)) {
n1ptr++;
n2ptr++;
count--;
}
else
{
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS)
return (-1);
else
return (1);
}
}
/* They are equal up to the last part of the equal part of the fraction. */
if (n1->n_scale != n2->n_scale)
{
if (n1->n_scale > n2->n_scale)
{
for (count = n1->n_scale-n2->n_scale; count>0; count--)
if (*n1ptr++ != 0)
{
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS)
return (1);
else
return (-1);
}
if (ignore_last && count == 1 && n1->n_scale == n2->n_scale) {
return (0);
}
else
{
for (count = n2->n_scale-n1->n_scale; count>0; count--)
if (*n2ptr++ != 0)
{
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS)
return (-1);
else
return (1);
}
if (count != 0) {
if (*n1ptr > *n2ptr) {
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (1);
} else {
return (-1);
}
} else {
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (-1);
} else {
return (1);
}
}
}
}
/* They must be equal! */
return (0);
/* They are equal up to the last part of the equal part of the fraction. */
if (n1->n_scale != n2->n_scale) {
if (n1->n_scale > n2->n_scale) {
for (count = n1->n_scale-n2->n_scale; count>0; count--) {
if (*n1ptr++ != 0) {
/* Magnitude of n1 > n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (1);
} else {
return (-1);
}
}
}
} else {
for (count = n2->n_scale-n1->n_scale; count>0; count--) {
if (*n2ptr++ != 0) {
/* Magnitude of n1 < n2. */
if (!use_sign || n1->n_sign == PLUS) {
return (-1);
} else {
return (1);
}
}
}
}
}
/* They must be equal! */
return (0);
}
/* This is the "user callable" routine to compare numbers N1 and N2. */
int bc_compare(bc_num n1, bc_num n2)
{
return _bc_do_compare (n1, n2, true, false);
return _bc_do_compare(n1, n2, true, false);
}

View File

@@ -3,8 +3,3 @@
#else
#include <php_config.h>
#endif
#include "php.h"
#include <string.h>
#include "zend.h"
#include "zend_alloc.h"

View File

@@ -29,34 +29,32 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
/* pn prints the number NUM in base 10. */
static void out_char (char c)
{
putchar(c);
putchar(c);
}
void pn (bc_num num)
void pn(bc_num num)
{
bc_out_num(num, 10, out_char, 0);
out_char ('\n');
bc_out_num(num, 10, out_char, 0);
out_char ('\n');
}
/* pv prints a character array as if it was a string of bcd digits. */
void pv (char *name, unsigned char *num, int len)
void pv (char *name, unsigned char *num, size_t len)
{
int i;
printf ("%s=", name);
for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
printf ("\n");
printf("%s=", name);
for (size_t i = 0; i < len; i++){
printf ("%c",BCD_CHAR(num[i]));
}
printf("\n");
}

View File

@@ -29,13 +29,11 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stdbool.h>
#include <stddef.h>
#include "zend_alloc.h"
/* Some utility routines for the divide: First a one digit multiply.
@@ -43,222 +41,218 @@
placed into RESULT. It is written so that NUM and RESULT can be
the same pointers. */
static void _one_mult (unsigned char *num, int size, int digit, unsigned char *result)
static void _one_mult(unsigned char *num, size_t size, int digit, unsigned char *result)
{
int carry, value;
unsigned char *nptr, *rptr;
int carry, value;
unsigned char *nptr, *rptr;
if (digit == 0)
memset (result, 0, size);
else
{
if (digit == 1)
memcpy (result, num, size);
else
{
/* Initialize */
nptr = (unsigned char *) (num+size-1);
rptr = (unsigned char *) (result+size-1);
carry = 0;
if (digit == 0) {
memset(result, 0, size);
} else {
if (digit == 1) {
memcpy(result, num, size);
} else {
/* Initialize */
nptr = (unsigned char *) (num+size-1);
rptr = (unsigned char *) (result+size-1);
carry = 0;
while (size-- > 0)
{
value = *nptr-- * digit + carry;
*rptr-- = value % BASE;
carry = value / BASE;
}
while (size-- > 0) {
value = *nptr-- * digit + carry;
*rptr-- = value % BASE;
carry = value / BASE;
}
if (carry != 0) *rptr = carry;
if (carry != 0) {
*rptr = carry;
}
}
}
}
}
/* The full division routine. This computes N1 / N2. It returns
0 if the division is ok and the result is in QUOT. The number of
digits after the decimal point is SCALE. It returns -1 if division
true if the division is ok and the result is in QUOT. The number of
digits after the decimal point is SCALE. It returns false if division
by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
int bc_divide (bc_num n1, bc_num n2, bc_num *quot, int scale)
bool bc_divide(bc_num n1, bc_num n2, bc_num *quot, int scale)
{
bc_num qval;
unsigned char *num1, *num2;
unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
int scale1, val;
unsigned int len1, len2, scale2, qdigits, extra, count;
unsigned int qdig, qguess, borrow, carry;
unsigned char *mval;
char zero;
unsigned int norm;
bc_num qval;
unsigned char *num1, *num2;
unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
int scale1, val;
unsigned int len1, len2, scale2, qdigits, extra, count;
unsigned int qdig, qguess, borrow, carry;
unsigned char *mval;
bool zero;
unsigned int norm;
/* Test for divide by zero. */
if (bc_is_zero (n2)) return -1;
/* Test for divide by 1. If it is we must truncate. */
if (n2->n_scale == 0)
{
if (n2->n_len == 1 && *n2->n_value == 1)
{
qval = bc_new_num (n1->n_len, scale);
qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
memset (&qval->n_value[n1->n_len],0,scale);
memcpy (qval->n_value, n1->n_value,
n1->n_len + MIN(n1->n_scale,scale));
bc_free_num (quot);
*quot = qval;
}
}
/* Set up the divide. Move the decimal point on n1 by n2's scale.
Remember, zeros on the end of num2 are wasted effort for dividing. */
scale2 = n2->n_scale;
n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
len1 = n1->n_len + scale2;
scale1 = n1->n_scale - scale2;
if (scale1 < scale)
extra = scale - scale1;
else
extra = 0;
num1 = (unsigned char *) safe_emalloc (1, n1->n_len+n1->n_scale, extra+2);
memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
len2 = n2->n_len + scale2;
num2 = (unsigned char *) safe_emalloc (1, len2, 1);
memcpy (num2, n2->n_value, len2);
*(num2+len2) = 0;
n2ptr = num2;
while (*n2ptr == 0)
{
n2ptr++;
len2--;
}
/* Calculate the number of quotient digits. */
if (len2 > len1+scale)
{
qdigits = scale+1;
zero = TRUE;
}
else
{
zero = FALSE;
if (len2>len1)
qdigits = scale+1; /* One for the zero integer part. */
else
qdigits = len1-len2+scale+1;
}
/* Allocate and zero the storage for the quotient. */
qval = bc_new_num (qdigits-scale,scale);
memset (qval->n_value, 0, qdigits);
/* Allocate storage for the temporary storage mval. */
mval = (unsigned char *) safe_emalloc (1, len2, 1);
/* Now for the full divide algorithm. */
if (!zero)
{
/* Normalize */
norm = 10 / ((int)*n2ptr + 1);
if (norm != 1)
{
_one_mult (num1, len1+scale1+extra+1, norm, num1);
_one_mult (n2ptr, len2, norm, n2ptr);
/* Test for divide by zero. */
if (bc_is_zero(n2)) {
return false;
}
/* Initialize divide loop. */
qdig = 0;
if (len2 > len1)
qptr = (unsigned char *) qval->n_value+len2-len1;
else
qptr = (unsigned char *) qval->n_value;
/* Loop */
while (qdig <= len1+scale-len2)
{
/* Calculate the quotient digit guess. */
if (*n2ptr == num1[qdig])
qguess = 9;
else
qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
/* Test qguess. */
if (n2ptr[1]*qguess >
(num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ num1[qdig+2])
{
qguess--;
/* And again. */
if (n2ptr[1]*qguess >
(num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
+ num1[qdig+2])
qguess--;
}
/* Multiply and subtract. */
borrow = 0;
if (qguess != 0)
{
*mval = 0;
_one_mult (n2ptr, len2, qguess, mval+1);
ptr1 = (unsigned char *) num1+qdig+len2;
ptr2 = (unsigned char *) mval+len2;
for (count = 0; count < len2+1; count++)
{
val = (int) *ptr1 - (int) *ptr2-- - borrow;
if (val < 0)
{
val += 10;
borrow = 1;
}
else
borrow = 0;
*ptr1-- = val;
/* Test for divide by 1. If it is we must truncate. */
if (n2->n_scale == 0) {
if (n2->n_len == 1 && *n2->n_value == 1) {
qval = bc_new_num (n1->n_len, scale);
qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
memset (&qval->n_value[n1->n_len],0,scale);
memcpy (qval->n_value, n1->n_value, n1->n_len + MIN(n1->n_scale,scale));
bc_free_num (quot);
*quot = qval;
}
}
/* Test for negative result. */
if (borrow == 1)
{
qguess--;
ptr1 = (unsigned char *) num1+qdig+len2;
ptr2 = (unsigned char *) n2ptr+len2-1;
carry = 0;
for (count = 0; count < len2; count++)
{
val = (int) *ptr1 + (int) *ptr2-- + carry;
if (val > 9)
{
val -= 10;
carry = 1;
}
else
carry = 0;
*ptr1-- = val;
}
if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
}
/* We now know the quotient digit. */
*qptr++ = qguess;
qdig++;
}
}
/* Clean up and return the number. */
qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
if (bc_is_zero (qval)) qval->n_sign = PLUS;
_bc_rm_leading_zeros (qval);
bc_free_num (quot);
*quot = qval;
/* Set up the divide. Move the decimal point on n1 by n2's scale.
Remember, zeros on the end of num2 are wasted effort for dividing. */
scale2 = n2->n_scale;
n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
while ((scale2 > 0) && (*n2ptr-- == 0)) {
scale2--;
}
/* Clean up temporary storage. */
efree (mval);
efree (num1);
efree (num2);
len1 = n1->n_len + scale2;
scale1 = n1->n_scale - scale2;
if (scale1 < scale) {
extra = scale - scale1;
} else {
extra = 0;
}
num1 = (unsigned char *) safe_emalloc (1, n1->n_len+n1->n_scale, extra+2);
memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
return 0; /* Everything is OK. */
len2 = n2->n_len + scale2;
num2 = (unsigned char *) safe_emalloc (1, len2, 1);
memcpy (num2, n2->n_value, len2);
*(num2+len2) = 0;
n2ptr = num2;
while (*n2ptr == 0) {
n2ptr++;
len2--;
}
/* Calculate the number of quotient digits. */
if (len2 > len1+scale) {
qdigits = scale+1;
zero = true;
} else {
zero = false;
if (len2 > len1) {
/* One for the zero integer part. */
qdigits = scale+1;
} else {
qdigits = len1-len2+scale+1;
}
}
/* Allocate and zero the storage for the quotient. */
qval = bc_new_num (qdigits-scale,scale);
memset (qval->n_value, 0, qdigits);
/* Allocate storage for the temporary storage mval. */
mval = (unsigned char *) safe_emalloc(1, len2, 1);
/* Now for the full divide algorithm. */
if (!zero) {
/* Normalize */
norm = 10 / ((int)*n2ptr + 1);
if (norm != 1) {
_one_mult (num1, len1+scale1+extra+1, norm, num1);
_one_mult (n2ptr, len2, norm, n2ptr);
}
/* Initialize divide loop. */
qdig = 0;
if (len2 > len1) {
qptr = (unsigned char *) qval->n_value+len2-len1;
} else {
qptr = (unsigned char *) qval->n_value;
}
/* Loop */
while (qdig <= len1+scale-len2) {
/* Calculate the quotient digit guess. */
if (*n2ptr == num1[qdig]) {
qguess = 9;
} else {
qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
}
/* Test qguess. */
if (
n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]
) {
qguess--;
/* And again. */
if (
n2ptr[1]*qguess > (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + num1[qdig+2]
) {
qguess--;
}
}
/* Multiply and subtract. */
borrow = 0;
if (qguess != 0) {
*mval = 0;
_one_mult (n2ptr, len2, qguess, mval+1);
ptr1 = (unsigned char *) num1+qdig+len2;
ptr2 = (unsigned char *) mval+len2;
for (count = 0; count < len2+1; count++) {
val = (int) *ptr1 - (int) *ptr2-- - borrow;
if (val < 0) {
val += 10;
borrow = 1;
} else {
borrow = 0;
}
*ptr1-- = val;
}
}
/* Test for negative result. */
if (borrow == 1) {
qguess--;
ptr1 = (unsigned char *) num1+qdig+len2;
ptr2 = (unsigned char *) n2ptr+len2-1;
carry = 0;
for (count = 0; count < len2; count++) {
val = (int) *ptr1 + (int) *ptr2-- + carry;
if (val > 9) {
val -= 10;
carry = 1;
} else {
carry = 0;
}
*ptr1-- = val;
}
if (carry == 1) {
*ptr1 = (*ptr1 + 1) % 10;
}
}
/* We now know the quotient digit. */
*qptr++ = qguess;
qdig++;
}
}
/* Clean up and return the number. */
qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
if (bc_is_zero(qval)) {
qval->n_sign = PLUS;
}
_bc_rm_leading_zeros(qval);
bc_free_num(quot);
*quot = qval;
/* Clean up temporary storage. */
efree(mval);
efree(num1);
efree(num2);
/* Everything is OK. */
return true;
}

View File

@@ -29,55 +29,55 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stdbool.h>
#include <stddef.h>
/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and
NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT
is NULL then that store will be omitted.
false is returned if divisor is 0.
true otherwise for success.
*/
int bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale)
bool bc_divmod(bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, size_t scale)
{
bc_num quotient = NULL;
bc_num temp;
int rscale;
bc_num quotient = NULL;
bc_num temp;
size_t rscale;
/* Check for correct numbers. */
if (bc_is_zero (num2)) return -1;
/* Cannot divide/mod by 0. */
if (bc_is_zero(num2)) {
return false;
}
/* Calculate final scale. */
rscale = MAX (num1->n_scale, num2->n_scale+scale);
bc_init_num(&temp);
/* Calculate final scale. */
rscale = MAX (num1->n_scale, num2->n_scale+scale);
bc_init_num(&temp);
/* Calculate it. */
bc_divide (num1, num2, &temp, 0);
if (quot)
quotient = bc_copy_num (temp);
bc_multiply (temp, num2, &temp, rscale);
bc_sub (num1, temp, rem, rscale);
bc_free_num (&temp);
/* Calculate it. */
bc_divide (num1, num2, &temp, 0);
if (quot) {
quotient = bc_copy_num(temp);
}
bc_multiply (temp, num2, &temp, rscale);
bc_sub (num1, temp, rem, rscale);
bc_free_num (&temp);
if (quot)
{
bc_free_num (quot);
*quot = quotient;
}
if (quot) {
bc_free_num (quot);
*quot = quotient;
}
return 0; /* Everything is OK. */
return true;
}
/* Modulo for numbers. This computes NUM1 % NUM2 and puts the
result in RESULT. */
int bc_modulo (bc_num num1, bc_num num2, bc_num *result, int scale)
bool bc_modulo(bc_num num1, bc_num num2, bc_num *result, size_t scale)
{
return bc_divmod (num1, num2, NULL, result, scale);
return bc_divmod(num1, num2, NULL, result, scale);
}

View File

@@ -29,100 +29,99 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
/* Perform addition: N1 is added to N2 and the value is
returned. The signs of N1 and N2 are ignored.
SCALE_MIN is to set the minimum scale of the result. */
bc_num _bc_do_add(bc_num n1, bc_num n2, int scale_min)
bc_num _bc_do_add(bc_num n1, bc_num n2, size_t scale_min)
{
bc_num sum;
int sum_scale, sum_digits;
char *n1ptr, *n2ptr, *sumptr;
int carry, n1bytes, n2bytes;
int count;
bc_num sum;
size_t sum_scale, sum_digits;
char *n1ptr, *n2ptr, *sumptr;
size_t n1bytes, n2bytes;
bool carry;
/* Prepare sum. */
sum_scale = MAX (n1->n_scale, n2->n_scale);
sum_digits = MAX (n1->n_len, n2->n_len) + 1;
sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
/* Prepare sum. */
sum_scale = MAX (n1->n_scale, n2->n_scale);
sum_digits = MAX (n1->n_len, n2->n_len) + 1;
sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
/* Zero extra digits made by scale_min. */
if (scale_min > sum_scale)
{
sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
for (count = scale_min - sum_scale; count > 0; count--)
*sumptr++ = 0;
}
/* Start with the fraction part. Initialize the pointers. */
n1bytes = n1->n_scale;
n2bytes = n2->n_scale;
n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
/* Add the fraction part. First copy the longer fraction.*/
if (n1bytes != n2bytes)
{
if (n1bytes > n2bytes)
while (n1bytes>n2bytes)
{ *sumptr-- = *n1ptr--; n1bytes--;}
else
while (n2bytes>n1bytes)
{ *sumptr-- = *n2ptr--; n2bytes--;}
}
/* Now add the remaining fraction part and equal size integer parts. */
n1bytes += n1->n_len;
n2bytes += n2->n_len;
carry = 0;
while ((n1bytes > 0) && (n2bytes > 0))
{
*sumptr = *n1ptr-- + *n2ptr-- + carry;
if (*sumptr > (BASE-1))
{
carry = 1;
*sumptr -= BASE;
/* Zero extra digits made by scale_min. */
if (scale_min > sum_scale) {
sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
for (int count = scale_min - sum_scale; count > 0; count--) {
*sumptr++ = 0;
}
}
else
/* Start with the fraction part. Initialize the pointers. */
n1bytes = n1->n_scale;
n2bytes = n2->n_scale;
n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
/* Add the fraction part. First copy the longer fraction.*/
if (n1bytes != n2bytes) {
if (n1bytes > n2bytes) {
while (n1bytes>n2bytes) {
*sumptr-- = *n1ptr--;
n1bytes--;
}
} else {
while (n2bytes>n1bytes) {
*sumptr-- = *n2ptr--;
n2bytes--;
}
}
}
/* Now add the remaining fraction part and equal size integer parts. */
n1bytes += n1->n_len;
n2bytes += n2->n_len;
carry = 0;
sumptr--;
n1bytes--;
n2bytes--;
}
while ((n1bytes > 0) && (n2bytes > 0)) {
*sumptr = *n1ptr-- + *n2ptr-- + carry;
if (*sumptr > (BASE-1)) {
carry = 1;
*sumptr -= BASE;
} else {
carry = 0;
}
sumptr--;
n1bytes--;
n2bytes--;
}
/* Now add carry the longer integer part. */
if (n1bytes == 0)
{ n1bytes = n2bytes; n1ptr = n2ptr; }
while (n1bytes-- > 0)
{
*sumptr = *n1ptr-- + carry;
if (*sumptr > (BASE-1))
{
carry = 1;
*sumptr -= BASE;
}
else
carry = 0;
sumptr--;
}
/* Now add carry the longer integer part. */
if (n1bytes == 0) {
n1bytes = n2bytes;
n1ptr = n2ptr;
}
while (n1bytes-- > 0) {
*sumptr = *n1ptr-- + carry;
if (*sumptr > (BASE-1)) {
carry = true;
*sumptr -= BASE;
} else {
carry = false;
}
sumptr--;
}
/* Set final carry. */
if (carry == 1)
*sumptr += 1;
/* Set final carry. */
if (carry) {
*sumptr += 1;
}
/* Adjust sum and return. */
_bc_rm_leading_zeros (sum);
return sum;
/* Adjust sum and return. */
_bc_rm_leading_zeros (sum);
return sum;
}
@@ -130,95 +129,84 @@ bc_num _bc_do_add(bc_num n1, bc_num n2, int scale_min)
returned. The signs of N1 and N2 are ignored. Also, N1 is
assumed to be larger than N2. SCALE_MIN is the minimum scale
of the result. */
bc_num _bc_do_sub(bc_num n1, bc_num n2, int scale_min)
bc_num _bc_do_sub(bc_num n1, bc_num n2, size_t scale_min)
{
bc_num diff;
int diff_scale, diff_len;
int min_scale, min_len;
char *n1ptr, *n2ptr, *diffptr;
int borrow, count, val;
bc_num diff;
int diff_scale, diff_len;
size_t min_scale, min_len;
char *n1ptr, *n2ptr, *diffptr;
int borrow, count, val;
/* Allocate temporary storage. */
diff_len = MAX (n1->n_len, n2->n_len);
diff_scale = MAX (n1->n_scale, n2->n_scale);
min_len = MIN (n1->n_len, n2->n_len);
min_scale = MIN (n1->n_scale, n2->n_scale);
diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
/* Allocate temporary storage. */
diff_len = MAX(n1->n_len, n2->n_len);
diff_scale = MAX(n1->n_scale, n2->n_scale);
min_len = MIN(n1->n_len, n2->n_len);
min_scale = MIN(n1->n_scale, n2->n_scale);
diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
/* Zero extra digits made by scale_min. */
if (scale_min > diff_scale)
{
diffptr = (char *) (diff->n_value + diff_len + diff_scale);
for (count = scale_min - diff_scale; count > 0; count--)
*diffptr++ = 0;
}
/* Initialize the subtract. */
n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
/* Subtract the numbers. */
borrow = 0;
/* Take care of the longer scaled number. */
if (n1->n_scale != min_scale)
{
/* n1 has the longer scale */
for (count = n1->n_scale - min_scale; count > 0; count--)
*diffptr-- = *n1ptr--;
}
else
{
/* n2 has the longer scale */
for (count = n2->n_scale - min_scale; count > 0; count--)
{
val = - *n2ptr-- - borrow;
if (val < 0)
{
val += BASE;
borrow = 1;
}
else
borrow = 0;
*diffptr-- = val;
/* Zero extra digits made by scale_min. */
if (scale_min > diff_scale) {
diffptr = (char *) (diff->n_value + diff_len + diff_scale);
for (count = scale_min - diff_scale; count > 0; count--) {
*diffptr++ = 0;
}
}
}
/* Now do the equal length scale and integer parts. */
/* Initialize the subtract. */
n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
for (count = 0; count < min_len + min_scale; count++)
{
val = *n1ptr-- - *n2ptr-- - borrow;
if (val < 0)
{
val += BASE;
borrow = 1;
}
else
/* Subtract the numbers. */
borrow = 0;
*diffptr-- = val;
}
/* If n1 has more digits then n2, we now do that subtract. */
if (diff_len != min_len)
{
for (count = diff_len - min_len; count > 0; count--)
{
val = *n1ptr-- - borrow;
if (val < 0)
{
val += BASE;
borrow = 1;
}
else
borrow = 0;
*diffptr-- = val;
/* Take care of the longer scaled number. */
if (n1->n_scale != min_scale) {
/* n1 has the longer scale */
for (count = n1->n_scale - min_scale; count > 0; count--) {
*diffptr-- = *n1ptr--;
}
} else {
/* n2 has the longer scale */
for (count = n2->n_scale - min_scale; count > 0; count--) {
val = - *n2ptr-- - borrow;
if (val < 0) {
val += BASE;
borrow = 1;
} else {
borrow = 0;
}
*diffptr-- = val;
}
}
}
/* Clean up and return. */
_bc_rm_leading_zeros (diff);
return diff;
/* Now do the equal length scale and integer parts. */
for (count = 0; count < min_len + min_scale; count++) {
val = *n1ptr-- - *n2ptr-- - borrow;
if (val < 0) {
val += BASE;
borrow = 1;
} else {
borrow = 0;
}
*diffptr-- = val;
}
/* If n1 has more digits then n2, we now do that subtract. */
if (diff_len != min_len) {
for (count = diff_len - min_len; count > 0; count--) {
val = *n1ptr-- - borrow;
if (val < 0) {
val += BASE;
borrow = 1;
} else {
borrow = 0;
}
*diffptr-- = val;
}
}
/* Clean up and return. */
_bc_rm_leading_zeros (diff);
return diff;
}

View File

@@ -29,47 +29,45 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stdbool.h>
#include <stddef.h>
#include "zend_alloc.h"
/* new_num allocates a number and sets fields to known values. */
bc_num _bc_new_num_ex (int length, int scale, int persistent)
bc_num _bc_new_num_ex(size_t length, size_t scale, bool persistent)
{
bc_num temp;
/* PHP Change: malloc() -> pemalloc(), removed free_list code */
temp = (bc_num) safe_pemalloc (1, sizeof(bc_struct)+length, scale, persistent);
temp->n_sign = PLUS;
temp->n_len = length;
temp->n_scale = scale;
temp->n_refs = 1;
/* PHP Change: malloc() -> pemalloc() */
temp->n_ptr = (char *) safe_pemalloc (1, length, scale, persistent);
temp->n_value = temp->n_ptr;
memset (temp->n_ptr, 0, length+scale);
return temp;
bc_num temp;
/* PHP Change: malloc() -> pemalloc(), removed free_list code */
temp = (bc_num) safe_pemalloc (1, sizeof(bc_struct)+length, scale, persistent);
temp->n_sign = PLUS;
temp->n_len = length;
temp->n_scale = scale;
temp->n_refs = 1;
/* PHP Change: malloc() -> pemalloc() */
temp->n_ptr = (char *) safe_pemalloc (1, length, scale, persistent);
temp->n_value = temp->n_ptr;
memset (temp->n_ptr, 0, length+scale);
return temp;
}
/* "Frees" a bc_num NUM. Actually decreases reference count and only
frees the storage if reference count is zero. */
void _bc_free_num_ex(bc_num *num, int persistent)
void _bc_free_num_ex(bc_num *num, bool persistent)
{
if (*num == NULL) return;
(*num)->n_refs--;
if ((*num)->n_refs == 0) {
if ((*num)->n_ptr)
/* PHP Change: free() -> pefree(), removed free_list code */
pefree ((*num)->n_ptr, persistent);
pefree(*num, persistent);
}
*num = NULL;
if (*num == NULL) {
return;
}
(*num)->n_refs--;
if ((*num)->n_refs == 0) {
if ((*num)->n_ptr) {
/* PHP Change: free() -> pefree(), removed free_list code */
pefree ((*num)->n_ptr, persistent);
}
pefree(*num, persistent);
}
*num = NULL;
}
@@ -77,26 +75,24 @@ void _bc_free_num_ex(bc_num *num, int persistent)
void bc_init_numbers(void)
{
BCG(_zero_) = _bc_new_num_ex (1,0,1);
BCG(_one_) = _bc_new_num_ex (1,0,1);
BCG(_one_)->n_value[0] = 1;
BCG(_two_) = _bc_new_num_ex (1,0,1);
BCG(_two_)->n_value[0] = 2;
BCG(_zero_) = _bc_new_num_ex (1,0,1);
BCG(_one_) = _bc_new_num_ex (1,0,1);
BCG(_one_)->n_value[0] = 1;
BCG(_two_) = _bc_new_num_ex (1,0,1);
BCG(_two_)->n_value[0] = 2;
}
/* Make a copy of a number! Just increments the reference count! */
/* Make a copy of a number! Just increments the reference count! */
bc_num bc_copy_num(bc_num num)
{
num->n_refs++;
return num;
num->n_refs++;
return num;
}
/* Initialize a number NUM by making it a copy of zero. */
void bc_init_num(bc_num *num)
{
*num = bc_copy_num (BCG(_zero_));
*num = bc_copy_num(BCG(_zero_));
}

View File

@@ -29,46 +29,45 @@
*************************************************************************/
#include <config.h>
#include "bcmath.h"
/* Convert an integer VAL to a bc number NUM. */
void bc_int2num(bc_num *num, int val)
{
char buffer[30];
char *bptr, *vptr;
int ix = 1;
char neg = 0;
char buffer[30];
char *bptr, *vptr;
int ix = 1;
char neg = 0;
/* Sign. */
if (val < 0)
{
neg = 1;
val = -val;
}
/* Sign. */
if (val < 0) {
neg = 1;
val = -val;
}
/* Get things going. */
bptr = buffer;
*bptr++ = val % BASE;
val = val / BASE;
/* Get things going. */
bptr = buffer;
*bptr++ = val % BASE;
val = val / BASE;
/* Extract remaining digits. */
while (val != 0)
{
*bptr++ = val % BASE;
val = val / BASE;
ix++; /* Count the digits. */
}
/* Extract remaining digits. */
while (val != 0) {
*bptr++ = val % BASE;
val = val / BASE;
ix++; /* Count the digits. */
}
/* Make the number. */
bc_free_num (num);
*num = bc_new_num (ix, 0);
if (neg) (*num)->n_sign = MINUS;
/* Make the number. */
bc_free_num (num);
*num = bc_new_num (ix, 0);
if (neg) {
(*num)->n_sign = MINUS;
}
/* Assign the digits. */
vptr = (*num)->n_value;
while (ix-- > 0)
*vptr++ = *--bptr;
/* Assign the digits. */
vptr = (*num)->n_value;
while (ix-- > 0) {
*vptr++ = *--bptr;
}
}

View File

@@ -30,30 +30,32 @@
*************************************************************************/
#include <stdbool.h>
#include <stddef.h>
#include "bcmath.h"
/* In some places we need to check if the number NUM is almost zero.
Specifically, all but the last digit is 0 and the last digit is 1.
Last digit is defined by scale. */
bool bc_is_near_zero(bc_num num, int scale)
bool bc_is_near_zero(bc_num num, size_t scale)
{
int count;
char *nptr;
/* Error checking */
if (scale > num->n_scale) {
scale = num->n_scale;
}
/* Error checking */
if (scale > num->n_scale)
scale = num->n_scale;
/* Initialize */
size_t count = num->n_len + scale;
const char *nptr = num->n_value;
/* Initialize */
count = num->n_len + scale;
nptr = num->n_value;
/* The check */
while ((count > 0) && (*nptr++ == 0)) {
count--;
}
/* The check */
while ((count > 0) && (*nptr++ == 0)) count--;
if (count != 0 && (count != 1 || *--nptr != 1))
return false;
else
return true;
if (count != 0 && (count != 1 || *--nptr != 1)) {
return false;
} else {
return true;
}
}

View File

@@ -35,5 +35,5 @@
/* In some places we need to check if the number is negative. */
bool bc_is_neg(bc_num num)
{
return num->n_sign == MINUS;
return num->n_sign == MINUS;
}

View File

@@ -29,8 +29,8 @@
*************************************************************************/
#include <config.h>
#include "bcmath.h"
#include <stddef.h>
/* Convert a number NUM to a long. The function returns only the integer
part of the number. For numbers that are too large to represent as
@@ -39,30 +39,30 @@
long bc_num2long(bc_num num)
{
long val;
char *nptr;
int index;
long val;
char *nptr;
/* Extract the int value, ignore the fraction. */
val = 0;
nptr = num->n_value;
for (index = num->n_len; index > 0; index--) {
char n = *nptr++;
/* Extract the int value, ignore the fraction. */
val = 0;
nptr = num->n_value;
for (size_t index = num->n_len; index > 0; index--) {
char n = *nptr++;
if (val > LONG_MAX/BASE) {
return 0;
}
val *= BASE;
if (val > LONG_MAX/BASE) {
return 0;
}
val *= BASE;
if (val > LONG_MAX - n) {
return 0;
}
val += n;
}
if (val > LONG_MAX - n) {
return 0;
}
val += n;
}
/* Return the value. */
if (num->n_sign == PLUS)
return (val);
else
return (-val);
/* Return the value. */
if (num->n_sign == PLUS) {
return (val);
} else {
return (-val);
}
}

View File

@@ -29,29 +29,26 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include "zend_string.h"
/* Convert a numbers to a string. Base 10 only.*/
zend_string *bc_num2str_ex(bc_num num, int scale)
zend_string *bc_num2str_ex(bc_num num, size_t scale)
{
zend_string *str;
char *sptr;
char *nptr;
int index, signch;
/* Number of sign chars. */
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, MIN(num->n_scale, scale));
/* Allocate the string memory. */
signch = num->n_sign != PLUS && !bc_is_zero_for_scale(num, MIN(num->n_scale, scale)); /* Number of sign chars. */
if (scale > 0)
if (scale > 0) {
str = zend_string_alloc(num->n_len + scale + signch + 1, 0);
else
} else {
str = zend_string_alloc(num->n_len + signch, 0);
}
/* The negative sign if needed. */
sptr = ZSTR_VAL(str);
@@ -59,17 +56,19 @@ zend_string *bc_num2str_ex(bc_num num, int scale)
/* Load the whole number. */
nptr = num->n_value;
for (index=num->n_len; index>0; index--)
for (index=num->n_len; index>0; index--) {
*sptr++ = BCD_CHAR(*nptr++);
}
/* Now the fraction. */
if (scale > 0)
{
if (scale > 0) {
*sptr++ = '.';
for (index=0; index<scale && index<num->n_scale; index++)
for (index=0; index<scale && index<num->n_scale; index++) {
*sptr++ = BCD_CHAR(*nptr++);
for (index = num->n_scale; index<scale; index++)
}
for (index = num->n_scale; index<scale; index++) {
*sptr++ = BCD_CHAR(0);
}
}
/* Terminate the string and return it! */

View File

@@ -29,13 +29,9 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stdbool.h>
#include "zend_alloc.h"
/* The following routines provide output for bcd numbers package
@@ -58,137 +54,135 @@ static const char ref_str[] = "0123456789ABCDEF";
void bc_out_long (long val, size_t size, bool space, void (*out_char)(char) )
{
char digits[40];
size_t len, ix;
char digits[40];
size_t len, ix;
if (space) (*out_char) (' ');
snprintf(digits, sizeof(digits), "%ld", val);
len = strlen (digits);
while (size > len)
{
(*out_char) ('0');
size--;
}
for (ix=0; ix < len; ix++)
(*out_char) (digits[ix]);
if (space) (*out_char) (' ');
snprintf(digits, sizeof(digits), "%ld", val);
len = strlen(digits);
while (size > len) {
(*out_char) ('0');
size--;
}
for (ix=0; ix < len; ix++) {
(*out_char) (digits[ix]);
}
}
/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR
as the routine to do the actual output of the characters. */
void bc_out_num (bc_num num, int o_base, void (*out_char)(char), int leading_zero)
void bc_out_num (bc_num num, int o_base, void (*out_char)(char), bool leading_zero)
{
char *nptr;
int index, fdigit;
bool pre_space;
stk_rec *digits, *temp;
bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
char *nptr;
int index, fdigit;
bool pre_space;
stk_rec *digits, *temp;
bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
/* The negative sign if needed. */
if (num->n_sign == MINUS) (*out_char) ('-');
/* The negative sign if needed. */
if (num->n_sign == MINUS) (*out_char) ('-');
/* Output the number. */
if (bc_is_zero (num))
(*out_char) ('0');
else
if (o_base == 10)
{
/* The number is in base 10, do it the fast way. */
nptr = num->n_value;
if (num->n_len > 1 || *nptr != 0)
for (index=num->n_len; index>0; index--)
(*out_char) (BCD_CHAR(*nptr++));
else
nptr++;
/* Output the number. */
if (bc_is_zero (num)) {
(*out_char) ('0');
} else {
if (o_base == 10) {
/* The number is in base 10, do it the fast way. */
nptr = num->n_value;
if (num->n_len > 1 || *nptr != 0) {
for (index=num->n_len; index>0; index--) {
(*out_char) (BCD_CHAR(*nptr++));
}
} else {
nptr++;
}
if (leading_zero && bc_is_zero (num))
(*out_char) ('0');
if (leading_zero && bc_is_zero(num)) {
(*out_char) ('0');
}
/* Now the fraction. */
if (num->n_scale > 0)
{
(*out_char) ('.');
for (index=0; index<num->n_scale; index++)
(*out_char) (BCD_CHAR(*nptr++));
}
}
else
{
/* special case ... */
if (leading_zero && bc_is_zero (num))
(*out_char) ('0');
/* Now the fraction. */
if (num->n_scale > 0) {
(*out_char) ('.');
for (index=0; index<num->n_scale; index++) {
(*out_char) (BCD_CHAR(*nptr++));
}
}
} else {
/* special case ... */
if (leading_zero && bc_is_zero (num)) {
(*out_char) ('0');
}
/* The number is some other base. */
digits = NULL;
bc_init_num (&int_part);
bc_divide (num, BCG(_one_), &int_part, 0);
bc_init_num (&frac_part);
bc_init_num (&cur_dig);
bc_init_num (&base);
bc_sub (num, int_part, &frac_part, 0);
/* Make the INT_PART and FRAC_PART positive. */
int_part->n_sign = PLUS;
frac_part->n_sign = PLUS;
bc_int2num (&base, o_base);
bc_init_num (&max_o_digit);
bc_int2num (&max_o_digit, o_base-1);
/* The number is some other base. */
digits = NULL;
bc_init_num (&int_part);
bc_divide (num, BCG(_one_), &int_part, 0);
bc_init_num (&frac_part);
bc_init_num (&cur_dig);
bc_init_num (&base);
bc_sub (num, int_part, &frac_part, 0);
/* Make the INT_PART and FRAC_PART positive. */
int_part->n_sign = PLUS;
frac_part->n_sign = PLUS;
bc_int2num (&base, o_base);
bc_init_num (&max_o_digit);
bc_int2num (&max_o_digit, o_base-1);
/* Get the digits of the integer part and push them on a stack. */
while (!bc_is_zero(int_part)) {
bc_modulo (int_part, base, &cur_dig, 0);
/* PHP Change: malloc() -> emalloc() */
temp = (stk_rec *) emalloc (sizeof(stk_rec));
temp->digit = bc_num2long (cur_dig);
temp->next = digits;
digits = temp;
bc_divide (int_part, base, &int_part, 0);
}
/* Get the digits of the integer part and push them on a stack. */
while (!bc_is_zero (int_part))
{
bc_modulo (int_part, base, &cur_dig, 0);
/* PHP Change: malloc() -> emalloc() */
temp = (stk_rec *) emalloc (sizeof(stk_rec));
temp->digit = bc_num2long (cur_dig);
temp->next = digits;
digits = temp;
bc_divide (int_part, base, &int_part, 0);
}
/* Print the digits on the stack. */
if (digits != NULL) {
/* Output the digits. */
while (digits != NULL) {
temp = digits;
digits = digits->next;
if (o_base <= 16) {
(*out_char) (ref_str[ (int) temp->digit]);
} else {
bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
}
efree(temp);
}
}
/* Print the digits on the stack. */
if (digits != NULL)
{
/* Output the digits. */
while (digits != NULL)
{
temp = digits;
digits = digits->next;
if (o_base <= 16)
(*out_char) (ref_str[ (int) temp->digit]);
else
bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
efree (temp);
}
}
/* Get and print the digits of the fraction part. */
if (num->n_scale > 0) {
(*out_char) ('.');
pre_space = false;
t_num = bc_copy_num (BCG(_one_));
while (t_num->n_len <= num->n_scale) {
bc_multiply (frac_part, base, &frac_part, num->n_scale);
fdigit = bc_num2long (frac_part);
bc_int2num (&int_part, fdigit);
bc_sub (frac_part, int_part, &frac_part, 0);
if (o_base <= 16) {
(*out_char) (ref_str[fdigit]);
} else {
bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
pre_space = true;
}
bc_multiply (t_num, base, &t_num, 0);
}
bc_free_num (&t_num);
}
/* Get and print the digits of the fraction part. */
if (num->n_scale > 0)
{
(*out_char) ('.');
pre_space = false;
t_num = bc_copy_num (BCG(_one_));
while (t_num->n_len <= num->n_scale) {
bc_multiply (frac_part, base, &frac_part, num->n_scale);
fdigit = bc_num2long (frac_part);
bc_int2num (&int_part, fdigit);
bc_sub (frac_part, int_part, &frac_part, 0);
if (o_base <= 16)
(*out_char) (ref_str[fdigit]);
else {
bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
pre_space = true;
}
bc_multiply (t_num, base, &t_num, 0);
}
bc_free_num (&t_num);
}
/* Clean up. */
bc_free_num (&int_part);
bc_free_num (&frac_part);
bc_free_num (&base);
bc_free_num (&cur_dig);
bc_free_num (&max_o_digit);
}
/* Clean up. */
bc_free_num (&int_part);
bc_free_num (&frac_part);
bc_free_num (&base);
bc_free_num (&cur_dig);
bc_free_num (&max_o_digit);
}
}
}

View File

@@ -32,9 +32,10 @@
/* "Private" routines to bcmath. */
#include <stdbool.h>
#include <stddef.h>
/* routines */
int _bc_do_compare (bc_num n1, bc_num n2, bool use_sign, bool ignore_last);
bc_num _bc_do_add (bc_num n1, bc_num n2, int scale_min);
bc_num _bc_do_sub (bc_num n1, bc_num n2, int scale_min);
bc_num _bc_do_add (bc_num n1, bc_num n2, size_t scale_min);
bc_num _bc_do_sub (bc_num n1, bc_num n2, size_t scale_min);
void _bc_rm_leading_zeros (bc_num num);

View File

@@ -29,100 +29,91 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
/* Raise NUM1 to the NUM2 power. The result is placed in RESULT.
Maximum exponent is LONG_MAX. If a NUM2 is not an integer,
only the integer part is used. */
void
bc_raise (bc_num num1, bc_num num2, bc_num *result, int scale)
void bc_raise(bc_num num1, long exponent, bc_num *result, size_t scale)
{
bc_num temp, power;
long exponent;
int rscale;
int pwrscale;
int calcscale;
char neg;
bc_num temp, power;
size_t rscale;
size_t pwrscale;
size_t calcscale;
bool is_neg;
/* Check the exponent for scale digits and convert to a long. */
if (num2->n_scale != 0) {
/* 2nd argument from PHP_FUNCTION(bcpow) */
zend_argument_value_error(2, "cannot have a fractional part");
return;
}
exponent = bc_num2long (num2);
if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) {
/* 2nd argument from PHP_FUNCTION(bcpow) */
zend_argument_value_error(2, "is too large");
/* Special case if exponent is a zero. */
if (exponent == 0) {
bc_free_num (result);
*result = bc_copy_num (BCG(_one_));
return;
}
/* Special case if exponent is a zero. */
if (exponent == 0)
{
bc_free_num (result);
*result = bc_copy_num (BCG(_one_));
return;
}
/* Other initializations. */
if (exponent < 0) {
is_neg = true;
exponent = -exponent;
rscale = scale;
} else {
is_neg = false;
rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
}
/* Other initializations. */
if (exponent < 0)
{
neg = TRUE;
exponent = -exponent;
rscale = scale;
}
else
{
neg = FALSE;
rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
}
/* Set initial value of temp. */
power = bc_copy_num (num1);
pwrscale = num1->n_scale;
while ((exponent & 1) == 0) {
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale);
exponent = exponent >> 1;
}
temp = bc_copy_num (power);
calcscale = pwrscale;
exponent = exponent >> 1;
/* Set initial value of temp. */
power = bc_copy_num (num1);
pwrscale = num1->n_scale;
while ((exponent & 1) == 0)
{
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale);
exponent = exponent >> 1;
}
temp = bc_copy_num (power);
calcscale = pwrscale;
exponent = exponent >> 1;
/* Do the calculation. */
while (exponent > 0) {
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale);
if ((exponent & 1) == 1) {
calcscale = pwrscale + calcscale;
bc_multiply (temp, power, &temp, calcscale);
}
exponent = exponent >> 1;
}
/* Do the calculation. */
while (exponent > 0)
{
pwrscale = 2*pwrscale;
bc_multiply (power, power, &power, pwrscale);
if ((exponent & 1) == 1) {
calcscale = pwrscale + calcscale;
bc_multiply (temp, power, &temp, calcscale);
}
exponent = exponent >> 1;
}
/* Assign the value. */
if (neg)
{
bc_divide (BCG(_one_), temp, result, rscale);
bc_free_num (&temp);
}
else
{
bc_free_num (result);
*result = temp;
if ((*result)->n_scale > rscale)
(*result)->n_scale = rscale;
}
bc_free_num (&power);
/* Assign the value. */
if (is_neg) {
bc_divide (BCG(_one_), temp, result, rscale);
bc_free_num (&temp);
} else {
bc_free_num (result);
*result = temp;
if ((*result)->n_scale > rscale) {
(*result)->n_scale = rscale;
}
}
bc_free_num (&power);
}
/* This is used internally by BCMath */
void bc_raise_bc_exponent(bc_num base, bc_num expo, bc_num *result, size_t scale)
{
/* Exponent must not have fractional part */
assert(expo->n_scale == 0);
long exponent = bc_num2long(expo);
/* Exponent must be properly convertable to long */
if (exponent == 0 && (expo->n_len > 1 || expo->n_value[0] != 0)) {
assert(false && "Exponent is not well formed in internal call");
//assert(exponent != 0 || (expo->n_len == 0 && expo->n_value[0] == 0));
}
//assert(exponent != 0 || (expo->n_len == 0 && expo->n_value[0] == 0));
bc_raise(base, exponent, result, scale);
}

View File

@@ -29,85 +29,65 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include "zend_exceptions.h"
#include <stddef.h>
/* Raise BASE to the EXPO power, reduced modulo MOD. The result is placed in RESULT. */
zend_result bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
raise_mod_status bc_raisemod(bc_num base, bc_num expo, bc_num mod, bc_num *result, size_t scale)
{
bc_num power, exponent, modulus, parity, temp;
int rscale;
bc_num power, exponent, modulus, parity, temp;
size_t rscale;
/* Check the base for scale digits. */
if (base->n_scale != 0) {
/* 1st argument from PHP_FUNCTION(bcpowmod) */
zend_argument_value_error(1, "cannot have a fractional part");
return FAILURE;
}
return BASE_HAS_FRACTIONAL;
}
/* Check the exponent for scale digits. */
if (expo->n_scale != 0) {
/* 2nd argument from PHP_FUNCTION(bcpowmod) */
zend_argument_value_error(2, "cannot have a fractional part");
return FAILURE;
}
return EXPO_HAS_FRACTIONAL;
}
if (bc_is_neg(expo)) {
zend_argument_value_error(2, "must be greater than or equal to 0");
return FAILURE;
return EXPO_IS_NEGATIVE;
}
/* Check the modulus for scale digits. */
if (mod->n_scale != 0) {
/* 3rd argument from PHP_FUNCTION(bcpowmod) */
zend_argument_value_error(3, "cannot have a fractional part");
return FAILURE;
}
/* Modulus cannot be 0 */
return MOD_HAS_FRACTIONAL;
}
/* Modulus cannot be 0 */
if (bc_is_zero(mod)) {
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
return FAILURE;
return MOD_IS_ZERO;
}
/* Set initial values. */
power = bc_copy_num (base);
exponent = bc_copy_num (expo);
modulus = bc_copy_num (mod);
temp = bc_copy_num (BCG(_one_));
bc_init_num(&parity);
/* Set initial values. */
power = bc_copy_num (base);
exponent = bc_copy_num (expo);
modulus = bc_copy_num (mod);
temp = bc_copy_num (BCG(_one_));
bc_init_num(&parity);
/* Do the calculation. */
rscale = MAX(scale, power->n_scale);
if ( !bc_compare(modulus, BCG(_one_)) )
{
bc_free_num (&temp);
temp = bc_new_num (1, scale);
}
else
{
while ( !bc_is_zero(exponent) )
{
(void) bc_divmod (exponent, BCG(_two_), &exponent, &parity, 0);
if ( !bc_is_zero(parity) )
{
bc_multiply (temp, power, &temp, rscale);
(void) bc_modulo (temp, modulus, &temp, scale);
}
bc_multiply (power, power, &power, rscale);
(void) bc_modulo (power, modulus, &power, scale);
/* Do the calculation. */
rscale = MAX(scale, power->n_scale);
if ( !bc_compare(modulus, BCG(_one_)) ) {
bc_free_num (&temp);
temp = bc_new_num (1, scale);
} else {
while ( !bc_is_zero(exponent) ) {
(void) bc_divmod (exponent, BCG(_two_), &exponent, &parity, 0);
if ( !bc_is_zero(parity) ) {
bc_multiply (temp, power, &temp, rscale);
(void) bc_modulo (temp, modulus, &temp, scale);
}
bc_multiply (power, power, &power, rscale);
(void) bc_modulo (power, modulus, &power, scale);
}
}
}
/* Assign the value. */
bc_free_num (&power);
bc_free_num (&exponent);
bc_free_num (&modulus);
bc_free_num (result);
bc_free_num (&parity);
*result = temp;
return SUCCESS; /* Everything is OK. */
/* Assign the value. */
bc_free_num (&power);
bc_free_num (&exponent);
bc_free_num (&modulus);
bc_free_num (result);
bc_free_num (&parity);
*result = temp;
return OK;
}

View File

@@ -29,10 +29,12 @@
*************************************************************************/
#include <config.h>
#include <assert.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
#include "private.h" /* For _bc_rm_leading_zeros() */
#include "zend_alloc.h"
/* Recursive vs non-recursive multiply crossover ranges. */
#if defined(MULDIGITS)
@@ -46,49 +48,49 @@ int mul_base_digits = MUL_BASE_DIGITS;
/* Multiply utility routines */
static bc_num new_sub_num(int length, int scale, char *value)
static bc_num new_sub_num(size_t length, size_t scale, char *value)
{
bc_num temp;
bc_num temp;
temp = (bc_num) emalloc (sizeof(bc_struct));
temp = (bc_num) emalloc (sizeof(bc_struct));
temp->n_sign = PLUS;
temp->n_len = length;
temp->n_scale = scale;
temp->n_refs = 1;
temp->n_ptr = NULL;
temp->n_value = value;
return temp;
temp->n_sign = PLUS;
temp->n_len = length;
temp->n_scale = scale;
temp->n_refs = 1;
temp->n_ptr = NULL;
temp->n_value = value;
return temp;
}
static void
_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
int full_scale)
static void _bc_simp_mul(bc_num n1, size_t n1len, bc_num n2, int n2len, bc_num *prod)
{
char *n1ptr, *n2ptr, *pvptr;
char *n1end, *n2end; /* To the end of n1 and n2. */
int indx, sum, prodlen;
char *n1ptr, *n2ptr, *pvptr;
char *n1end, *n2end; /* To the end of n1 and n2. */
int indx, sum, prodlen;
prodlen = n1len+n2len+1;
prodlen = n1len+n2len+1;
*prod = bc_new_num (prodlen, 0);
*prod = bc_new_num (prodlen, 0);
n1end = (char *) (n1->n_value + n1len - 1);
n2end = (char *) (n2->n_value + n2len - 1);
pvptr = (char *) ((*prod)->n_value + prodlen - 1);
sum = 0;
n1end = (char *) (n1->n_value + n1len - 1);
n2end = (char *) (n2->n_value + n2len - 1);
pvptr = (char *) ((*prod)->n_value + prodlen - 1);
sum = 0;
/* Here is the loop... */
for (indx = 0; indx < prodlen-1; indx++)
{
n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
n2ptr = (char *) (n2end - MIN(indx, n2len-1));
while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
sum += *n1ptr-- * *n2ptr++;
*pvptr-- = sum % BASE;
sum = sum / BASE;
}
*pvptr = sum;
/* Here is the loop... */
for (indx = 0; indx < prodlen-1; indx++) {
n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
n2ptr = (char *) (n2end - MIN(indx, n2len-1));
while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) {
sum += *n1ptr * *n2ptr;
n1ptr--;
n2ptr++;
}
*pvptr-- = sum % BASE;
sum = sum / BASE;
}
*pvptr = sum;
}
@@ -96,62 +98,62 @@ _bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
multiply algorithm. Note: if sub is called, accum must
be larger that what is being subtracted. Also, accum and val
must have n_scale = 0. (e.g. they must look like integers. *) */
static void
_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
static void _bc_shift_addsub (bc_num accum, bc_num val, int shift, bool sub)
{
signed char *accp, *valp;
int count, carry;
signed char *accp, *valp;
unsigned int carry = 0;
size_t count = val->n_len;
count = val->n_len;
if (val->n_value[0] == 0)
count--;
assert (accum->n_len+accum->n_scale >= shift+count);
if (val->n_value[0] == 0) {
count--;
}
assert(accum->n_len+accum->n_scale >= shift+count);
/* Set up pointers and others */
accp = (signed char *)(accum->n_value +
accum->n_len + accum->n_scale - shift - 1);
valp = (signed char *)(val->n_value + val->n_len - 1);
carry = 0;
/* Set up pointers and others */
accp = (signed char *)(accum->n_value + accum->n_len + accum->n_scale - shift - 1);
valp = (signed char *)(val->n_value + val->n_len - 1);
if (sub) {
/* Subtraction, carry is really borrow. */
while (count--) {
*accp -= *valp-- + carry;
if (*accp < 0) {
carry = 1;
*accp-- += BASE;
} else {
carry = 0;
accp--;
}
}
while (carry) {
*accp -= carry;
if (*accp < 0)
*accp-- += BASE;
else
carry = 0;
}
} else {
/* Addition */
while (count--) {
*accp += *valp-- + carry;
if (*accp > (BASE-1)) {
carry = 1;
*accp-- -= BASE;
} else {
carry = 0;
accp--;
}
}
while (carry) {
*accp += carry;
if (*accp > (BASE-1))
*accp-- -= BASE;
else
carry = 0;
}
}
if (sub) {
/* Subtraction, carry is really borrow. */
while (count--) {
*accp -= *valp-- + carry;
if (*accp < 0) {
carry = 1;
*accp-- += BASE;
} else {
carry = 0;
accp--;
}
}
while (carry) {
*accp -= carry;
if (*accp < 0) {
*accp-- += BASE;
} else {
carry = 0;
}
}
} else {
/* Addition */
while (count--) {
*accp += *valp-- + carry;
if (*accp > (BASE-1)) {
carry = 1;
*accp-- -= BASE;
} else {
carry = 0;
accp--;
}
}
while (carry) {
*accp += carry;
if (*accp > (BASE-1)) {
*accp-- -= BASE;
} else {
carry = 0;
}
}
}
}
/* Recursive divide and conquer multiply algorithm.
@@ -162,126 +164,128 @@ _bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
B is the base of storage, number of digits in u1,u0 close to equal.
*/
static void
_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
int full_scale)
static void _bc_rec_mul(bc_num u, size_t ulen, bc_num v, size_t vlen, bc_num *prod)
{
bc_num u0, u1, v0, v1;
bc_num m1, m2, m3, d1, d2;
int n, prodlen, m1zero;
int d1len, d2len;
bc_num u0, u1, v0, v1;
bc_num m1, m2, m3, d1, d2;
int n, prodlen, m1zero;
int d1len, d2len;
/* Base case? */
if ((ulen+vlen) < mul_base_digits
|| ulen < MUL_SMALL_DIGITS
|| vlen < MUL_SMALL_DIGITS ) {
_bc_simp_mul (u, ulen, v, vlen, prod, full_scale);
return;
}
/* Base case? */
if ((ulen+vlen) < mul_base_digits
|| ulen < MUL_SMALL_DIGITS
|| vlen < MUL_SMALL_DIGITS
) {
_bc_simp_mul (u, ulen, v, vlen, prod);
return;
}
/* Calculate n -- the u and v split point in digits. */
n = (MAX(ulen, vlen)+1) / 2;
/* Calculate n -- the u and v split point in digits. */
n = (MAX(ulen, vlen)+1) / 2;
/* Split u and v. */
if (ulen < n) {
u1 = bc_copy_num (BCG(_zero_));
u0 = new_sub_num (ulen,0, u->n_value);
} else {
u1 = new_sub_num (ulen-n, 0, u->n_value);
u0 = new_sub_num (n, 0, u->n_value+ulen-n);
}
if (vlen < n) {
v1 = bc_copy_num (BCG(_zero_));
v0 = new_sub_num (vlen,0, v->n_value);
} else {
v1 = new_sub_num (vlen-n, 0, v->n_value);
v0 = new_sub_num (n, 0, v->n_value+vlen-n);
}
_bc_rm_leading_zeros (u1);
_bc_rm_leading_zeros (u0);
_bc_rm_leading_zeros (v1);
_bc_rm_leading_zeros (v0);
/* Split u and v. */
if (ulen < n) {
u1 = bc_copy_num (BCG(_zero_));
u0 = new_sub_num (ulen,0, u->n_value);
} else {
u1 = new_sub_num (ulen-n, 0, u->n_value);
u0 = new_sub_num (n, 0, u->n_value+ulen-n);
}
if (vlen < n) {
v1 = bc_copy_num (BCG(_zero_));
v0 = new_sub_num (vlen,0, v->n_value);
} else {
v1 = new_sub_num (vlen-n, 0, v->n_value);
v0 = new_sub_num (n, 0, v->n_value+vlen-n);
}
_bc_rm_leading_zeros (u1);
_bc_rm_leading_zeros (u0);
_bc_rm_leading_zeros (v1);
_bc_rm_leading_zeros (v0);
m1zero = bc_is_zero(u1) || bc_is_zero(v1);
m1zero = bc_is_zero(u1) || bc_is_zero(v1);
/* Calculate sub results ... */
/* Calculate sub results ... */
bc_init_num(&d1);
bc_init_num(&d2);
bc_sub (u1, u0, &d1, 0);
d1len = d1->n_len;
bc_sub (v0, v1, &d2, 0);
d2len = d2->n_len;
bc_init_num(&d1);
bc_init_num(&d2);
bc_sub (u1, u0, &d1, 0);
d1len = d1->n_len;
bc_sub (v0, v1, &d2, 0);
d2len = d2->n_len;
/* Do recursive multiplies and shifted adds. */
if (m1zero)
m1 = bc_copy_num (BCG(_zero_));
else
_bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0);
/* Do recursive multiplies and shifted adds. */
if (m1zero) {
m1 = bc_copy_num (BCG(_zero_));
} else {
_bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1);
}
if (bc_is_zero(d1) || bc_is_zero(d2))
m2 = bc_copy_num (BCG(_zero_));
else
_bc_rec_mul (d1, d1len, d2, d2len, &m2, 0);
if (bc_is_zero(d1) || bc_is_zero(d2)) {
m2 = bc_copy_num (BCG(_zero_));
} else {
_bc_rec_mul (d1, d1len, d2, d2len, &m2);
}
if (bc_is_zero(u0) || bc_is_zero(v0))
m3 = bc_copy_num (BCG(_zero_));
else
_bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0);
if (bc_is_zero(u0) || bc_is_zero(v0)) {
m3 = bc_copy_num (BCG(_zero_));
} else {
_bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3);
}
/* Initialize product */
prodlen = ulen+vlen+1;
*prod = bc_new_num(prodlen, 0);
/* Initialize product */
prodlen = ulen+vlen+1;
*prod = bc_new_num(prodlen, 0);
if (!m1zero) {
_bc_shift_addsub (*prod, m1, 2*n, 0);
_bc_shift_addsub (*prod, m1, n, 0);
}
_bc_shift_addsub (*prod, m3, n, 0);
_bc_shift_addsub (*prod, m3, 0, 0);
_bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
if (!m1zero) {
_bc_shift_addsub (*prod, m1, 2*n, 0);
_bc_shift_addsub (*prod, m1, n, 0);
}
_bc_shift_addsub (*prod, m3, n, 0);
_bc_shift_addsub (*prod, m3, 0, 0);
_bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
/* Now clean up! */
bc_free_num (&u1);
bc_free_num (&u0);
bc_free_num (&v1);
bc_free_num (&m1);
bc_free_num (&v0);
bc_free_num (&m2);
bc_free_num (&m3);
bc_free_num (&d1);
bc_free_num (&d2);
/* Now clean up! */
bc_free_num (&u1);
bc_free_num (&u0);
bc_free_num (&v1);
bc_free_num (&m1);
bc_free_num (&v0);
bc_free_num (&m2);
bc_free_num (&m3);
bc_free_num (&d1);
bc_free_num (&d2);
}
/* The multiply routine. N2 times N1 is put int PROD with the scale of
the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
*/
void
bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale)
void bc_multiply(bc_num n1, bc_num n2, bc_num *prod, size_t scale)
{
bc_num pval;
int len1, len2;
int full_scale, prod_scale;
bc_num pval;
size_t len1, len2;
size_t full_scale, prod_scale;
/* Initialize things. */
len1 = n1->n_len + n1->n_scale;
len2 = n2->n_len + n2->n_scale;
full_scale = n1->n_scale + n2->n_scale;
prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
/* Initialize things. */
len1 = n1->n_len + n1->n_scale;
len2 = n2->n_len + n2->n_scale;
full_scale = n1->n_scale + n2->n_scale;
prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
/* Do the multiply */
_bc_rec_mul (n1, len1, n2, len2, &pval, full_scale);
/* Do the multiply */
_bc_rec_mul (n1, len1, n2, len2, &pval);
/* Assign to prod and clean up the number. */
pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
pval->n_value = pval->n_ptr;
pval->n_len = len2 + len1 + 1 - full_scale;
pval->n_scale = prod_scale;
_bc_rm_leading_zeros (pval);
if (bc_is_zero (pval))
pval->n_sign = PLUS;
bc_free_num (prod);
*prod = pval;
/* Assign to prod and clean up the number. */
pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
pval->n_value = pval->n_ptr;
pval->n_len = len2 + len1 + 1 - full_scale;
pval->n_scale = prod_scale;
_bc_rm_leading_zeros(pval);
if (bc_is_zero(pval)) {
pval->n_sign = PLUS;
}
bc_free_num(prod);
*prod = pval;
}

View File

@@ -29,7 +29,6 @@
*************************************************************************/
#include <config.h>
#include "bcmath.h"
#include "private.h"
@@ -39,9 +38,9 @@
void _bc_rm_leading_zeros(bc_num num)
{
/* We can move n_value to point to the first non zero digit! */
while (*num->n_value == 0 && num->n_len > 1) {
num->n_value++;
num->n_len--;
}
/* We can move n_value to point to the first non zero digit! */
while (*num->n_value == 0 && num->n_len > 1) {
num->n_value++;
num->n_len--;
}
}

View File

@@ -29,89 +29,87 @@
*************************************************************************/
#include <config.h>
#include <stdbool.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include <stdbool.h>
/* Take the square root NUM and return it in NUM with SCALE digits
after the decimal place. */
bool bc_sqrt(bc_num *num, int scale)
bool bc_sqrt(bc_num *num, size_t scale)
{
int rscale, cmp_res;
int cscale;
bc_num guess, guess1, point5, diff;
/* Initial checks. */
cmp_res = bc_compare (*num, BCG(_zero_));
if (cmp_res < 0) {
return false; /* error */
} else {
if (cmp_res == 0) {
bc_free_num (num);
*num = bc_copy_num (BCG(_zero_));
return true;
/* Initial checks. */
int cmp_res = bc_compare (*num, BCG(_zero_));
if (cmp_res < 0) {
return false; /* error */
} else {
if (cmp_res == 0) {
bc_free_num (num);
*num = bc_copy_num (BCG(_zero_));
return true;
}
}
cmp_res = bc_compare (*num, BCG(_one_));
if (cmp_res == 0) {
bc_free_num (num);
*num = bc_copy_num (BCG(_one_));
return true;
}
}
cmp_res = bc_compare (*num, BCG(_one_));
if (cmp_res == 0)
{
bc_free_num (num);
*num = bc_copy_num (BCG(_one_));
return true;
}
/* Initialize the variables. */
rscale = MAX (scale, (*num)->n_scale);
bc_init_num(&guess1);
bc_init_num(&diff);
point5 = bc_new_num (1,1);
point5->n_value[1] = 5;
/* Initialize the variables. */
size_t rscale;
size_t cscale;
bc_num guess, guess1, point5, diff;
rscale = MAX (scale, (*num)->n_scale);
bc_init_num(&guess1);
bc_init_num(&diff);
point5 = bc_new_num (1,1);
point5->n_value[1] = 5;
/* Calculate the initial guess. */
if (cmp_res < 0) {
/* The number is between 0 and 1. Guess should start at 1. */
guess = bc_copy_num (BCG(_one_));
cscale = (*num)->n_scale;
} else {
/* The number is greater than 1. Guess should start at 10^(exp/2). */
bc_init_num(&guess);
bc_int2num (&guess,10);
/* Calculate the initial guess. */
if (cmp_res < 0) {
/* The number is between 0 and 1. Guess should start at 1. */
guess = bc_copy_num (BCG(_one_));
cscale = (*num)->n_scale;
} else {
/* The number is greater than 1. Guess should start at 10^(exp/2). */
bc_init_num(&guess);
bc_int2num (&guess,10);
bc_int2num (&guess1,(*num)->n_len);
bc_multiply (guess1, point5, &guess1, 0);
guess1->n_scale = 0;
bc_raise (guess, guess1, &guess, 0);
bc_free_num (&guess1);
cscale = 3;
}
bc_int2num (&guess1,(*num)->n_len);
bc_multiply (guess1, point5, &guess1, 0);
guess1->n_scale = 0;
bc_raise_bc_exponent(guess, guess1, &guess, 0);
bc_free_num (&guess1);
cscale = 3;
}
/* Find the square root using Newton's algorithm. */
bool done = false;
while (!done) {
bc_free_num (&guess1);
guess1 = bc_copy_num (guess);
bc_divide (*num, guess, &guess, cscale);
bc_add (guess, guess1, &guess, 0);
bc_multiply (guess, point5, &guess, cscale);
bc_sub (guess, guess1, &diff, cscale+1);
if (bc_is_near_zero (diff, cscale)) {
if (cscale < rscale+1) {
cscale = MIN (cscale*3, rscale+1);
} else {
done = true;
}
}
}
/* Find the square root using Newton's algorithm. */
bool done = false;
while (!done) {
bc_free_num (&guess1);
guess1 = bc_copy_num (guess);
bc_divide (*num, guess, &guess, cscale);
bc_add (guess, guess1, &guess, 0);
bc_multiply (guess, point5, &guess, cscale);
bc_sub (guess, guess1, &diff, cscale+1);
if (bc_is_near_zero (diff, cscale)) {
if (cscale < rscale+1) {
cscale = MIN (cscale*3, rscale+1);
} else {
done = true;
}
}
}
/* Assign the number and clean up. */
bc_free_num (num);
bc_divide (guess,BCG(_one_),num,rscale);
bc_free_num (&guess);
bc_free_num (&guess1);
bc_free_num (&point5);
bc_free_num (&diff);
return true;
/* Assign the number and clean up. */
bc_free_num (num);
bc_divide (guess,BCG(_one_),num,rscale);
bc_free_num (&guess);
bc_free_num (&guess1);
bc_free_num (&point5);
bc_free_num (&diff);
return true;
}

View File

@@ -29,84 +29,95 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stdbool.h>
#include <stddef.h>
/* Convert strings to bc numbers. Base 10 only.*/
int
bc_str2num (bc_num *num, char *str, int scale)
bool bc_str2num (bc_num *num, char *str, size_t scale)
{
int digits, strscale;
char *ptr, *nptr;
char zero_int;
size_t digits, strscale;
char *ptr, *nptr;
bool zero_int = false;
/* Prepare num. */
bc_free_num (num);
/* Prepare num. */
bc_free_num (num);
/* Check for valid number and count digits. */
ptr = str;
digits = 0;
strscale = 0;
zero_int = FALSE;
if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */
while (*ptr == '0') ptr++; /* Skip leading zeros. */
while (*ptr >= '0' && *ptr <= '9') ptr++, digits++; /* digits */
if (*ptr == '.') ptr++; /* decimal point */
while (*ptr >= '0' && *ptr <= '9') ptr++, strscale++; /* digits */
if ((*ptr != '\0') || (digits+strscale == 0))
{
*num = bc_copy_num (BCG(_zero_));
return *ptr == '\0';
}
/* Check for valid number and count digits. */
ptr = str;
digits = 0;
strscale = 0;
/* Adjust numbers and allocate storage and initialize fields. */
strscale = MIN(strscale, scale);
if (digits == 0)
{
zero_int = TRUE;
digits = 1;
}
*num = bc_new_num (digits, strscale);
if ( (*ptr == '+') || (*ptr == '-')) {
/* Skip Sign */
ptr++;
}
/* Skip leading zeros. */
while (*ptr == '0') {
ptr++;
}
/* digits before the decimal point */
while (*ptr >= '0' && *ptr <= '9') {
ptr++;
digits++;
}
/* decimal point */
if (*ptr == '.') {
ptr++;
}
/* digits after the decimal point */
while (*ptr >= '0' && *ptr <= '9') {
ptr++;
strscale++;
}
if ((*ptr != '\0') || (digits+strscale == 0)) {
*num = bc_copy_num (BCG(_zero_));
return *ptr == '\0';
}
/* Build the whole number. */
ptr = str;
if (*ptr == '-')
{
(*num)->n_sign = MINUS;
ptr++;
}
else
{
(*num)->n_sign = PLUS;
if (*ptr == '+') ptr++;
}
while (*ptr == '0') ptr++; /* Skip leading zeros. */
nptr = (*num)->n_value;
if (zero_int)
{
*nptr++ = 0;
digits = 0;
}
for (;digits > 0; digits--)
*nptr++ = CH_VAL(*ptr++);
/* Adjust numbers and allocate storage and initialize fields. */
strscale = MIN(strscale, scale);
if (digits == 0) {
zero_int = true;
digits = 1;
}
*num = bc_new_num (digits, strscale);
/* Build the whole number. */
ptr = str;
if (*ptr == '-') {
(*num)->n_sign = MINUS;
ptr++;
} else {
(*num)->n_sign = PLUS;
if (*ptr == '+') ptr++;
}
/* Skip leading zeros. */
while (*ptr == '0') {
ptr++;
}
nptr = (*num)->n_value;
if (zero_int) {
*nptr++ = 0;
digits = 0;
}
for (;digits > 0; digits--) {
*nptr++ = CH_VAL(*ptr++);
}
/* Build the fractional part. */
if (strscale > 0)
{
ptr++; /* skip the decimal point! */
for (;strscale > 0; strscale--)
*nptr++ = CH_VAL(*ptr++);
}
/* Build the fractional part. */
if (strscale > 0) {
/* skip the decimal point! */
ptr++;
for (;strscale > 0; strscale--) {
*nptr++ = CH_VAL(*ptr++);
}
}
if (bc_is_zero (*num))
(*num)->n_sign = PLUS;
if (bc_is_zero (*num)) {
(*num)->n_sign = PLUS;
}
return 1;
return true;
}

View File

@@ -29,52 +29,49 @@
*************************************************************************/
#include <config.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include <stdbool.h>
/* Here is the full subtract routine that takes care of negative numbers.
N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN
is the minimum scale for the result. */
void bc_sub(bc_num n1, bc_num n2, bc_num *result, int scale_min)
void bc_sub(bc_num n1, bc_num n2, bc_num *result, size_t scale_min)
{
bc_num diff = NULL;
int cmp_res;
int res_scale;
bc_num diff = NULL;
int cmp_res;
if (n1->n_sign != n2->n_sign)
{
diff = _bc_do_add (n1, n2, scale_min);
diff->n_sign = n1->n_sign;
}
else
{
/* subtraction must be done. */
/* Compare magnitudes. */
cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);
switch (cmp_res)
{
case -1:
/* n1 is less than n2, subtract n1 from n2. */
diff = _bc_do_sub (n2, n1, scale_min);
diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
break;
case 0:
/* They are equal! return zero! */
res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
diff = bc_new_num (1, res_scale);
memset (diff->n_value, 0, res_scale+1);
break;
case 1:
/* n2 is less than n1, subtract n2 from n1. */
diff = _bc_do_sub (n1, n2, scale_min);
diff->n_sign = n1->n_sign;
break;
if (n1->n_sign != n2->n_sign) {
diff = _bc_do_add (n1, n2, scale_min);
diff->n_sign = n1->n_sign;
} else {
/* subtraction must be done. */
/* Compare magnitudes. */
cmp_res = _bc_do_compare(n1, n2, false, false);
switch (cmp_res) {
case -1:
/* n1 is less than n2, subtract n1 from n2. */
diff = _bc_do_sub (n2, n1, scale_min);
diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
break;
case 0: {
/* They are equal! return zero! */
size_t res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
diff = bc_new_num (1, res_scale);
memset (diff->n_value, 0, res_scale+1);
break;
}
case 1:
/* n2 is less than n1, subtract n2 from n1. */
diff = _bc_do_sub (n1, n2, scale_min);
diff->n_sign = n1->n_sign;
break;
}
}
}
/* Clean up and return. */
bc_free_num (result);
*result = diff;
/* Clean up and return. */
bc_free_num (result);
*result = diff;
}

View File

@@ -29,40 +29,33 @@
*************************************************************************/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include "bcmath.h"
#include "private.h"
#include <stddef.h>
#include <stdbool.h>
/* In some places we need to check if the number NUM is zero. */
char
bc_is_zero_for_scale (bc_num num, int scale)
bool bc_is_zero_for_scale (bc_num num, size_t scale)
{
int count;
char *nptr;
size_t count;
char *nptr;
/* Quick check. */
if (num == BCG(_zero_)) return TRUE;
/* Quick check. */
if (num == BCG(_zero_)) {
return true;
}
/* Initialize */
count = num->n_len + scale;
nptr = num->n_value;
/* Initialize */
count = num->n_len + scale;
nptr = num->n_value;
/* The check */
while ((count > 0) && (*nptr++ == 0)) count--;
/* The check */
while ((count > 0) && (*nptr++ == 0)) count--;
if (count != 0)
return FALSE;
else
return TRUE;
return count == 0;
}
char
bc_is_zero (bc_num num)
bool bc_is_zero(bc_num num)
{
return bc_is_zero_for_scale(num, num->n_scale);
return bc_is_zero_for_scale(num, num->n_scale);
}

View File

@@ -18,6 +18,7 @@
#define PHP_BCMATH_H
#include "libbcmath/src/bcmath.h"
#include "zend_API.h"
extern zend_module_entry bcmath_module_entry;
#define phpext_bcmath_ptr &bcmath_module_entry
@@ -25,10 +26,6 @@ extern zend_module_entry bcmath_module_entry;
#include "php_version.h"
#define PHP_BCMATH_VERSION PHP_VERSION
PHP_MINIT_FUNCTION(bcmath);
PHP_MSHUTDOWN_FUNCTION(bcmath);
PHP_MINFO_FUNCTION(bcmath);
ZEND_BEGIN_MODULE_GLOBALS(bcmath)
bc_num _zero_;
bc_num _one_;