📄 formatfp1.c
字号:
/* FormatFP_1.c 09/09/2002 to develop Imagecraft formatting function
09/12/2002
09/13/2002
09/14/2002
09/15/2002
09/28/2002
09/29/2002
10/25/2002
10/28/2002
10/29/2002
10/30/2002
11/01/2002
11/09/2002
11/10/2002
by Tom Digby for Imagecraft
*/
// debug in Windows 32 environment, use in Imagecraft environment
#ifdef _WIN32
#include "stdlib_ForWin32.h"
#endif
#ifdef __IMAGECRAFT__
#include <stdlib.h>
#include <string.h>
#endif
#include "_stdio.h"
#include "formatfp1.h"
// maximum size of exponent: "e", minus sign, two digits, null, guard
#define MAX_EXP_WIDTH 6
static char *FtoaError(char *buf, int code)
{
static FLASH char err0[] = { "ftoa error: number too big" };
static FLASH char err1[] = { "ftoa error: number too small" };
static FLASH char err2[] = { "ftoa error: unexpected error" };
FLASH char *cs;
if (code == _FTOA_TOO_LARGE)
cs = err0;
else if (code == _FTOA_TOO_SMALL)
cs = err1;
else
cs = err2;
#if defined(_AVR)
cstrcpy(buf, cs);
return buf;
#else
return (char *)cs;
#endif
}
char *_FormatFP_1(char *my_buffer,
int format, float f, unsigned flag, int field_width, int prec)
{
char * my_ascii_float;
int ftoa_status;
float test_number; // add to f to round decimals
float f_abs; // abs value of f for magnitude checks
int last_digit_position_found = -1;
int dp_position_found = -1, dp_position_assumed = -1;
int first_non_z_position_before_dp = -1;
int first_non_z_position_found = -1;
int last_non_z_position_after_dp = -1;
int num_sig_figs_before_dp = 0;
int end_of_string;
int first_result_digit_position;
int number_width;
int exponent = 0xFF; // want to know if it's not initialized
int is_minus = 0;
int want_eform = 0;
int i, j, k;
char lpad_char = ' ', rpad_char = ' ';
char exp_char = 'e';
char this_char, sign_char;
// sanity checks on some parameters
if(field_width > F_FP_BFR_SIZE) field_width = F_FP_BFR_SIZE;
if(prec > F_FP_BFR_SIZE) prec = F_FP_BFR_SIZE;
switch(format){ // what format do we want?
case FMT_NORMAL: // default
break;
case FMT_SCIENTIFIC_BIG_E: // want exponential with upper case "E"
exp_char = 'E';
// fall into
case FMT_SCIENTIFIC: // want exponential notation
want_eform = 1;
break;
case FMT_OPTIMUM_BIG_E: // may want exponential with upper case "E"
exp_char = 'E';
// fall into
case FMT_OPTIMUM: // may want exponential notation, test for it
f_abs = f;
if(f < 0) f_abs = (f * -1);
test_number = (float) 1; // test for size vs precision
for(i = 0; i < prec; i++) test_number *= 10;
if((f_abs < (float) .0001) || (f_abs > test_number))
want_eform = 1;
break;
} // switch
// some preliminaries
if (flag & F_ZEROPADD) lpad_char = '0';
sign_char = lpad_char; // will test for this equality later
if (flag & F_ADDSIGN) sign_char = '+';
// get the ASCII string to reformat
if(want_eform){
my_ascii_float = ftoa(f, &ftoa_status); // will round later
} // want exponential form
else{// don't want exponential format, round by addition
test_number = (float) 0.5; // add to f to round decimals, want one place beyond last
for(i = 0; i < prec; i++) test_number /= 10;
if(f < 0)
my_ascii_float = ftoa(f - test_number, &ftoa_status);
else
my_ascii_float = ftoa(f + test_number, &ftoa_status);
} // don't want exponential format
if (ftoa_status != 0)
return FtoaError(my_buffer, ftoa_status);
// analyze the number and the parameters
for(i = 0; i < F_FP_BFR_SIZE; i++){
// do we have enough digits past the decimal yet(non-exp only)?
if((want_eform == 0) && (dp_position_found >= 0) && ((i - dp_position_found) > prec))
break;
this_char = *(my_ascii_float + i); // get a character
// see if this character is a digit, and keep count of significant figures
if((this_char >= '0') && (this_char <= '9')){ // is a digit
last_digit_position_found = i;
if(this_char > '0') // non-zero digit found
if(first_non_z_position_found < 0) first_non_z_position_found = i;
if(dp_position_found < 0) { // before decimal (if any)
if((first_non_z_position_before_dp < 0) && (this_char > '0')){
first_non_z_position_before_dp = i;
} // first non-zero before decimal
if(first_non_z_position_before_dp >= 0) num_sig_figs_before_dp++;
// digits after first non-zero
} // before decimal
if(dp_position_found >= 0){ // after decimal
if (this_char > '0'){ // sig figs after decimal
last_non_z_position_after_dp = i;
// last non-zero after decimal
} // sig figs after decimal
} // after decimal
} // is a digit
// is this character the decimal point?
if(this_char == '.'){
dp_position_found = i;
} // decimal found
// is the number negative?
if(this_char == '-'){
is_minus = 1;
sign_char = '-';
} // minus
// stop at end of string
if(this_char == 0) break; // terminating null
} // for
// if no decimal found, assume it's right after last digit
// for consistency in later checks
if(dp_position_found < 0){
dp_position_assumed = last_digit_position_found + 1;
end_of_string = dp_position_assumed + 1;
} // no decimal
else { // decimal
dp_position_assumed = dp_position_found;
if(last_non_z_position_after_dp < 0){ // no non-zero digits after decimal
end_of_string = dp_position_assumed + 1;
} // no non-zero digits after decimal
else { // non-zero digits after decimal
end_of_string = last_non_z_position_after_dp + 1;
} // non-zero digits after decimal
} // decimal
// any non-zero digits before the decimal?
if(first_non_z_position_before_dp < 0) // no non-zero before decimal
first_non_z_position_before_dp = dp_position_assumed - 1;
if(want_eform){ // exponential format
// build the string from the left
// if don't want left-justified, move it over later
// sign plus leading digit plus decimal
i = 0;
if(sign_char != lpad_char){ // minus or want plus sign
my_buffer[i++] = sign_char;
} // if
my_buffer[i++] = *(my_ascii_float + first_non_z_position_found);
my_buffer[i] = '.'; // decimal point
if(prec > 0) i++; // don't overwrite decimal point later with E char
/* if(prec > 0) my_buffer[i++] = '.'; // decimal point */
j = first_non_z_position_found + 1;
k = 0;
while((k < prec) && (i < (F_FP_BFR_SIZE - MAX_EXP_WIDTH))){ // digits
if(j != dp_position_assumed){ // digits, skip the decimal point
if(j < end_of_string) // still in string
my_buffer[i++] = *(my_ascii_float + j);
else{ // past end of found digits, check for alt form or X.[nothing]
if((flag & F_ALTFORM) || (0 == k)) my_buffer[i++] = '0';
else break;
} // past end of found digits
k++;
} // digits, skip the decimal point
j++;
} // while digits
k = i - 1; // last output digit position, for use in rounding later
if(0 == prec) k = i; // point to decimal if zero precision (needed for testing)
/* my_buffer[i++] = exp_char; // "e" or "E" */
// now for the exponent
// what power of ten depends on where first non-zero digit was
// rounding assumes we have exponent value, so do it now, not later
exponent = (dp_position_assumed - first_non_z_position_found - 1);
if((j < end_of_string) && (*(my_ascii_float + j) == '.')) j++;
if((j < end_of_string) // digits left for rounding
&& (*(my_ascii_float + j) >= '5') && (*(my_ascii_float + j) <= '9')){ // round up
while(k >= 0){ // more digits need adjusting
if((my_buffer[k] >= '0') && (my_buffer[k] <= '8')){ // round up digit, no carry
my_buffer[k]++; // round up digit, no carry
break; // done rounding
} // round up digit, no carry
if((my_buffer[k] == '.')
/* || (0 == prec) && ((my_buffer[k] == 'e') || (my_buffer[k] == 'E'))*/
)
{ // skip the decimal point, only one more digit
k--;
if((my_buffer[k] >= '0') && (my_buffer[k] <= '8')){ // round up digit, no carry
my_buffer[k]++; // round up digit, no carry
break; // done rounding
} // round up digit, no carry
if(my_buffer[k] == '9'){ // special case
my_buffer[k] = '1'; // was a string of 9's, will be 1 and a string of zeros
exponent++;
break;
} // special case
}// skip the decimal point, only one more digit
if(my_buffer[k] == '9'){ // propagate carry
my_buffer[k] = '0';
} // propagate carry
// fall into
k--; // next digit
} // more digits need adjusting
} // rounding
my_buffer[i++] = exp_char; // "e" or "E"
// convert the exponent to ASCII
if(exponent < 0){ // negative exponent
my_buffer[i++] = '-';
exponent = ~exponent; // unsigned itoa()
} // negative exponent
#ifdef _WIN32
itoa_W32(&my_buffer[i], exponent, 10); // for tests in Win32 environment
#endif
#ifdef __IMAGECRAFT__
itoa(&my_buffer[i], exponent, 10); // for real ICC environment
#endif
// now align and pad as needed
for(i = 0; i < F_FP_BFR_SIZE; i++){ // how long is our output string?
if(0 == my_buffer[i]){
number_width = i; break;
} // found terminating null
} // for
// left or right align?
if(flag & F_LEFTALIGN){ // pad on right
if(number_width < field_width){ // need padding, including overwriting null
for(j = number_width; j < field_width; j++){
my_buffer[j] = rpad_char;
} // for
my_buffer[field_width - 1] = 0; // new terminating null
} // need padding
} // pad on right
//if not want left align, find length of string, shift to right
else{ // right align, pad on left
if(number_width < field_width){ // room to shift to right
for(j = number_width; j >= 0; j--){
my_buffer[j + field_width - number_width] = my_buffer[j];
} // for
for(j = field_width - number_width - 1; j >= 0; j--){ // padding
my_buffer[j] = lpad_char;
} // for padding
// move sign character?
if((flag & F_ZEROPADD) && (sign_char != lpad_char)){ // move sign to left
my_buffer[0] = sign_char;
my_buffer[field_width - number_width] = lpad_char;
} // move sign
} // room to shift to right
} // right align
} // exponential format
else
{ // normal format
// do we want trailing zeros?
if(flag & F_ALTFORM){
if(end_of_string <= (dp_position_assumed + prec))
end_of_string = dp_position_assumed + prec + 1;
} // space for trailing zeros
else {
// if no digits after decimal, drop decimal
if(end_of_string == dp_position_assumed + 1) end_of_string = dp_position_assumed;
} // don't want trailing zeros
// buffer size check
if(end_of_string > F_FP_BFR_SIZE) end_of_string = F_FP_BFR_SIZE;
// width of number, not counting sign
number_width = end_of_string - first_non_z_position_before_dp;
// now include the sign
if(sign_char != lpad_char) number_width++;
// allow it to overflow the specified field width
if(field_width < number_width) field_width = number_width;
// buffer size check
if(field_width > F_FP_BFR_SIZE) field_width = F_FP_BFR_SIZE;
if(number_width > F_FP_BFR_SIZE) number_width = F_FP_BFR_SIZE;
// do left or right alignment
if((flag & F_LEFTALIGN) || (field_width == number_width)){ // no empty space to the left
first_result_digit_position = 0; // left alignment
if(sign_char != lpad_char){
my_buffer[0] = sign_char;
first_result_digit_position = 1;
} // space for sign?
} // left alignment
else { // right alignment
first_result_digit_position = field_width - number_width;
// padding first, may overwrite one char with the sign
for(j = 0; j <= first_result_digit_position; j++)
my_buffer[j] = lpad_char;
if(sign_char != lpad_char){ // show the sign
if(flag & F_ZEROPADD)my_buffer[0] = sign_char;
else my_buffer[first_result_digit_position] = sign_char;
first_result_digit_position++; // point to first actual digit
} // show the sign
} // right alignment
// now start building the output string
j = first_result_digit_position;
if(num_sig_figs_before_dp == 0) {
my_buffer[j] = '0';
j++;
} // no leading non-zero digits
for(i = 0; i < num_sig_figs_before_dp; i++){ // copy digits before decimal
my_buffer[j] = *(my_ascii_float + i + first_non_z_position_before_dp);
j++;
} // copy digits before decimal
if(end_of_string > dp_position_assumed){ // want decimal point
my_buffer[j] = '.';
j++;
} // want decimal point
for(i = 0; (i < prec) && (j < F_FP_BFR_SIZE); i++){ // digits after decimal
if(i < (last_non_z_position_after_dp - dp_position_found)) // more digits
my_buffer[j] = *(my_ascii_float + i + dp_position_found + 1);
else{ // test for Alternate form
if(flag & F_ALTFORM) my_buffer[j] = '0';
else break;
} // test for Alternate form
j++;
} // digits after decimal
while(j < field_width){ // final padding
my_buffer[j] = rpad_char;
j++;
} // final padding
my_buffer[j] = 0; // terminating null
} // normal format
return &my_buffer[0];
} // FormatFP_1
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -