📄 number.c
字号:
/* Check for correct numbers. */ if (is_zero (num2)) return -1; /* Calculate final scale. */ rscale = MAX (num1->n_scale, num2->n_scale+scale); init_num (&temp); /* Calculate it. */ bc_divide (num1, num2, &temp, scale); bc_multiply (temp, num2, &temp, rscale); bc_sub (num1, temp, result); free_num (&temp); return 0; /* Everything is OK. */}/* 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. */voidbc_raise (num1, num2, result, scale) bc_num num1, num2, *result; int scale;{ bc_num temp, power; long exponent; int rscale; char neg; /* Check the exponent for scale digits and convert to a long. */ if (num2->n_scale != 0) rt_warn ("non-zero scale in exponent"); exponent = num2long (num2); if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) rt_error ("exponent too large in raise"); /* Special case if exponent is a zero. */ if (exponent == 0) { free_num (result); *result = copy_num (_one_); return; } /* 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)); } temp = copy_num (_one_); power = copy_num (num1); /* Do the calculation. */ while (exponent != 0) { if (exponent & 1 != 0) bc_multiply (temp, power, &temp, rscale); bc_multiply (power, power, &power, rscale); exponent = exponent >> 1; } /* Assign the value. */ if (neg) { bc_divide (_one_, temp, result, rscale); free_num (&temp); } else { free_num (result); *result = temp; } free_num (&power);}/* Take the square root NUM and return it in NUM with SCALE digits after the decimal place. */int bc_sqrt (num, scale) bc_num *num; int scale;{ int rscale, cmp_res, done; int cscale; bc_num guess, guess1, point5; /* Initial checks. */ cmp_res = bc_compare (*num, _zero_); if (cmp_res < 0) return 0; /* error */ else { if (cmp_res == 0) { free_num (num); *num = copy_num (_zero_); return 1; } } cmp_res = bc_compare (*num, _one_); if (cmp_res == 0) { free_num (num); *num = copy_num (_one_); return 1; } /* Initialize the variables. */ rscale = MAX (scale, (*num)->n_scale); cscale = rscale + 2; init_num (&guess); init_num (&guess1); point5 = 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 = copy_num (_one_); else { /* The number is greater than 1. Guess should start at 10^(exp/2). */ int2num (&guess,10); int2num (&guess1,(*num)->n_len); bc_multiply (guess1, point5, &guess1, rscale); guess1->n_scale = 0; bc_raise (guess, guess1, &guess, rscale); free_num (&guess1); } /* Find the square root using Newton's algorithm. */ done = FALSE; while (!done) { free_num (&guess1); guess1 = copy_num (guess); bc_divide (*num,guess,&guess,cscale); bc_add (guess,guess1,&guess); bc_multiply (guess,point5,&guess,cscale); cmp_res = _do_compare (guess,guess1,FALSE,TRUE); if (cmp_res == 0) done = TRUE; } /* Assign the number and clean up. */ free_num (num); bc_divide (guess,_one_,num,rscale); free_num (&guess); free_num (&guess1); free_num (&point5); return 1;}/* The following routines provide output for bcd numbers package using the rules of POSIX bc for output. *//* This structure is used for saving digits in the conversion process. */typedef struct stk_rec { long digit; struct stk_rec *next;} stk_rec;/* The reference string for digits. */char ref_str[] = "0123456789ABCDEF";/* A special output routine for "multi-character digits." Exactly SIZE characters must be output for the value VAL. If SPACE is non-zero, we must output one space before the number. OUT_CHAR is the actual routine for writing the characters. */voidout_long (val, size, space, out_char) long val; int size, space;#ifdef __STDC__ void (*out_char)(int);#else void (*out_char)();#endif{ char digits[40]; int len, ix; if (space) (*out_char) (' '); sprintf (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. */voidout_num (num, o_base, out_char) bc_num num; int o_base;#ifdef __STDC__ void (*out_char)(int);#else void (*out_char)();#endif{ char *nptr; int index, fdigit, 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) ('-'); /* Output the number. */ if (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++; /* Now the fraction. */ if (num->n_scale > 0) { (*out_char) ('.'); for (index=0; index<num->n_scale; index++) (*out_char) (BCD_CHAR(*nptr++)); } } else { /* The number is some other base. */ digits = NULL; init_num (&int_part); bc_divide (num, _one_, &int_part, 0); init_num (&frac_part); init_num (&cur_dig); init_num (&base); bc_sub (num, int_part, &frac_part); int2num (&base, o_base); init_num (&max_o_digit); int2num (&max_o_digit, o_base-1); /* Get the digits of the integer part and push them on a stack. */ while (!is_zero (int_part)) { bc_modulo (int_part, base, &cur_dig, 0); temp = (stk_rec *) malloc (sizeof(stk_rec)); if (temp == NULL) out_of_memory(); temp->digit = 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 out_long (temp->digit, max_o_digit->n_len, 1, out_char); free (temp); } } /* Get and print the digits of the fraction part. */ if (num->n_scale > 0) { (*out_char) ('.'); pre_space = 0; t_num = copy_num (_one_); while (t_num->n_len <= num->n_scale) { bc_multiply (frac_part, base, &frac_part, num->n_scale); fdigit = num2long (frac_part); int2num (&int_part, fdigit); bc_sub (frac_part, int_part, &frac_part); if (o_base <= 16) (*out_char) (ref_str[fdigit]); else { out_long (fdigit, max_o_digit->n_len, pre_space, out_char); pre_space = 1; } bc_multiply (t_num, base, &t_num, 0); } } /* Clean up. */ free_num (&int_part); free_num (&frac_part); free_num (&base); free_num (&cur_dig); }}#if DEBUG > 0/* Debugging procedures. Some are just so one can call them from the debugger. *//* p_n prints the number NUM in base 10. */voidp_n (num) bc_num num;{ out_num (num, 10, out_char); return 0;}/* p_b prints a character array as if it was a string of bcd digits. */voidp_v (name, num, len) char *name; unsigned char *num; int len;{ int i; printf ("%s=", name); for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i])); printf ("\n");}/* Convert strings to bc numbers. Base 10 only.*/voidstr2num (num, str, scale) bc_num *num; char *str; int scale;{ int digits, strscale; char *ptr, *nptr; char zero_int; /* Prepare num. */ 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 (isdigit(*ptr)) ptr++, digits++; /* digits */ if (*ptr == '.') ptr++; /* decimal point */ while (isdigit(*ptr)) ptr++, strscale++; /* digits */ if ((*ptr != '\0') || (digits+strscale == 0)) { *num = copy_num (_zero_); return; } /* Adjust numbers and allocate storage and initialize fields. */ strscale = MIN(strscale, scale); if (digits == 0) { zero_int = TRUE; digits = 1; } *num = 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++; } 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++); /* Build the fractional part. */ if (strscale > 0) { ptr++; /* skip the decimal point! */ for (;strscale > 0; strscale--) *nptr++ = CH_VAL(*ptr++); }}/* Convert a numbers to a string. Base 10 only.*/char*num2str (num) bc_num num;{ char *str, *sptr; char *nptr; int index, signch; /* Allocate the string memory. */ signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */ if (num->n_scale > 0) str = (char *) malloc (num->n_len + num->n_scale + 2 + signch); else str = (char *) malloc (num->n_len + 1 + signch); if (str == NULL) out_of_memory(); /* The negative sign if needed. */ sptr = str; if (signch) *sptr++ = '-'; /* Load the whole number. */ nptr = num->n_value; for (index=num->n_len; index>0; index--) *sptr++ = BCD_CHAR(*nptr++); /* Now the fraction. */ if (num->n_scale > 0) { *sptr++ = '.'; for (index=0; index<num->n_scale; index++) *sptr++ = BCD_CHAR(*nptr++); } /* Terminate the string and return it! */ *sptr = '\0'; return (str);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -