int pvsnfmt_double(pvsnfmt_vars *info, double d) { char *digits; int sign = 0; int dec; double value = d; int len; int pad = 0; //int signwidth = 0; int totallen; char signchar = 0; int leadingzeros = 0; int printdigits; /* temporary var used in different contexts */ int flags = info->flags; int width = info->width; const char fmt = *(info->fmt); int precision = info->precision; /* Check for special values first */ char *special = 0; if(ISSNAN(value)) { special = "NaN"; } else if(ISQNAN(value)) { special = "NaN"; } else if(ISINF(value)) { if(value < 0) { sign = 1; } special = "Inf"; } if(special) { totallen = len = strlen(special); /* Sign (this is silly for NaN but conforming to printf */ if(flags & (FLAG_SIGNED | FLAG_SIGN_PAD) || sign) { if(sign) { signchar = '-'; } else if(flags & FLAG_SIGN_PAD) { signchar = ' '; } else { signchar = '+'; } totallen++; } /* Padding */ if(totallen < width) { pad = width - totallen; } else { pad = 0; } totallen += pad ; // haleyjd 05/07/08: this was forgotten! if(info->nmax <= 1) { return totallen; } /* Sign now if zeropad */ if(flags & FLAG_ZERO_PAD && signchar) { if(info->nmax > 1) { *(info->pinsertion) = signchar; info->pinsertion += 1; info->nmax -= 1; } } /* Right align */ if(!(flags & FLAG_LEFT_ALIGN)) { if(info->nmax <= 1) { pad = 0; } else if((int) info->nmax - 1 < pad) { pad = info->nmax - 1; } if(flags & FLAG_ZERO_PAD) { memset(info->pinsertion, '0', pad); } else { memset(info->pinsertion, ' ', pad); } info->pinsertion += pad ; info->nmax -= pad ; } /* Sign now if not zeropad */ if(!(flags & FLAG_ZERO_PAD) && signchar) { if(info->nmax > 1) { *(info->pinsertion) = signchar; info->pinsertion += 1; info->nmax -= 1; } } if(info->nmax <= 0) { len = 0; } else if((int) info->nmax - 1 < len) { len = info->nmax - 1; } memcpy(info->pinsertion, special, len); info->pinsertion += len; info->nmax -= len; /* Left align */ if(flags & FLAG_LEFT_ALIGN) { if(info->nmax <= 1) { pad = 0; } else if((int) info->nmax - 1 < pad) { pad = info->nmax - 1; } memset(info->pinsertion, ' ', pad); info->pinsertion += pad ; info->nmax -= pad ; } return totallen; } if(fmt == 'f') { if(precision == UNKNOWN_PRECISION) { precision = 6; } digits = FCVT(value, precision, &dec, &sign); len = strlen(digits); if(dec > 0) { totallen = dec; } else { totallen = 0; } /* plus 1 for decimal place */ if(dec <= 0) { totallen += 2; /* and trailing ".0" */ } else if(precision > 0 || flags & FLAG_HASH) { totallen += 1; } /* Determine sign width (0 or 1) */ if(flags & (FLAG_SIGNED | FLAG_SIGN_PAD) || sign) { if(sign) { signchar = '-'; } else if(flags & FLAG_SIGN_PAD) { signchar = ' '; } else { signchar = '+'; } totallen++; } /* Determine if leading zeros required */ if(dec <= 0) { leadingzeros = 1 - dec; /* add one for zero before decimal point (0.) */ } if(leadingzeros - 1 > precision) { totallen += precision; } else if(len - dec > 0) { totallen += precision; } else { totallen += leadingzeros; } /* Determine padding width */ if(totallen < width) { pad = width - totallen; } totallen += pad; if(info->nmax <= 1) { return totallen; } /* Now that the length has been calculated, print as much of it * as possible into the buffer */ /* Print sign now if padding with zeros */ if(flags & FLAG_ZERO_PAD && signchar != 0) { if(info->nmax > 1) { *(info->pinsertion) = signchar; info->pinsertion += 1; info->nmax -= 1; } } /* Print width padding if right-aligned */ if(!(flags & FLAG_LEFT_ALIGN)) { if(info->nmax <= 1) { pad = 0; } else if((int) info->nmax - 1 < pad) { pad = info->nmax - 1; } if(flags & FLAG_ZERO_PAD) { memset(info->pinsertion, '0', pad); } else { memset(info->pinsertion, ' ', pad); } info->pinsertion += pad; info->nmax -= pad; } /* Print sign now if padding was spaces */ if(!(flags & FLAG_ZERO_PAD) && signchar != 0) { *(info->pinsertion) = signchar; info->pinsertion += 1; info->nmax -= 1; } /* Print leading zeros */ if(leadingzeros) { /* Print "0.", then leadingzeros - 1 */ if(info->nmax > 1) { *(info->pinsertion) = '0'; info->pinsertion += 1; info->nmax -= 1; } if(precision > 0 || flags & FLAG_HASH) { if(info->nmax > 1) { *(info->pinsertion) = '.'; info->pinsertion += 1; info->nmax -= 1; } } /* WARNING not rounding here! * i.e. printf(".3f", 0.0007) gives "0.000" not "0.001" * * This whole function could do with a rewrite... */ if(leadingzeros - 1 > precision) { leadingzeros = precision + 1; len = 0; } /* END WARNING */ precision -= leadingzeros - 1; if(info->nmax <= 1) { leadingzeros = 0; } else if((int) info->nmax /* - 1 */ < leadingzeros /* -1 */) { leadingzeros = info->nmax; /* -1 */ } leadingzeros--; memset(info->pinsertion, '0', leadingzeros); info->pinsertion += leadingzeros; info->nmax -= leadingzeros; } /* Print digits before decimal place */ if(dec > 0) { if(info->nmax <= 1) { printdigits = 0; } else if((int) info->nmax - 1 < dec) { printdigits = info->nmax - 1; } else { printdigits = dec; } memcpy(info->pinsertion, digits, printdigits); info->pinsertion += printdigits; info->nmax -= printdigits; if(precision > 0 || flags & FLAG_HASH) { /* Print decimal place */ if(info->nmax > 1) { *(info->pinsertion) = '.'; info->pinsertion += 1; info->nmax -= 1; } /* Print trailing zero if no precision but hash given */ if(precision == 0 && info->nmax > 1) { *(info->pinsertion) = '0'; info->pinsertion += 1; info->nmax -= 1; } } /* Bypass the digits we've already printed */ len -= dec; digits += dec; } /* Print digits after decimal place */ if(len > precision) { len = precision; } if(info->nmax <= 1) { printdigits = 0; } else if((int) info->nmax - 1 < len) { printdigits = info->nmax - 1; } else { printdigits = len; } memcpy(info->pinsertion, digits, printdigits); info->pinsertion += printdigits; info->nmax -= printdigits; /* Print left-aligned pad */ if(flags & FLAG_LEFT_ALIGN) { if(info->nmax <= 1) { pad = 0; } else if((int) info->nmax - 1 < pad) { pad = info->nmax - 1; } memset(info->pinsertion, ' ', pad); info->pinsertion += pad; info->nmax -= pad; } return totallen; } return 0; }
/* * Perform a compare instruction (with or without unordered exception). * This updates the fcc field in the fsr. * * If either operand is NaN, the result is unordered. For ordered, this * causes an NV exception. Everything else is ordered: * |Inf| > |numbers| > |0|. * We already arranged for fp_class(Inf) > fp_class(numbers) > fp_class(0), * so we get this directly. Note, however, that two zeros compare equal * regardless of sign, while everything else depends on sign. * * Incidentally, two Infs of the same sign compare equal (per the 80387 * manual---it would be nice if the SPARC documentation were more * complete). */ void fpu_compare(struct fpemu *fe, int ordered) { struct fpn *a, *b, *r; int cc; a = &fe->fe_f1; b = &fe->fe_f2; r = &fe->fe_f3; if (ISNAN(a) || ISNAN(b)) { /* * In any case, we already got an exception for signalling * NaNs; here we may replace that one with an identical * exception, but so what?. */ cc = FPSCR_FU; if (ISSNAN(a) || ISSNAN(b)) cc |= FPSCR_VXSNAN; if (ordered) { if (fe->fe_fpscr & FPSCR_VE || ISQNAN(a) || ISQNAN(b)) cc |= FPSCR_VXVC; } goto done; } /* * Must handle both-zero early to avoid sign goofs. Otherwise, * at most one is 0, and if the signs differ we are done. */ if (ISZERO(a) && ISZERO(b)) { cc = FPSCR_FE; goto done; } if (a->fp_sign) { /* a < 0 (or -0) */ if (!b->fp_sign) { /* b >= 0 (or if a = -0, b > 0) */ cc = FPSCR_FL; goto done; } } else { /* a > 0 (or +0) */ if (b->fp_sign) { /* b <= -0 (or if a = +0, b < 0) */ cc = FPSCR_FG; goto done; } } /* * Now the signs are the same (but may both be negative). All * we have left are these cases: * * |a| < |b| [classes or values differ] * |a| > |b| [classes or values differ] * |a| == |b| [classes and values identical] * * We define `diff' here to expand these as: * * |a| < |b|, a,b >= 0: a < b => FSR_CC_LT * |a| < |b|, a,b < 0: a > b => FSR_CC_GT * |a| > |b|, a,b >= 0: a > b => FSR_CC_GT * |a| > |b|, a,b < 0: a < b => FSR_CC_LT */ #define opposite_cc(cc) ((cc) == FPSCR_FL ? FPSCR_FG : FPSCR_FL) #define diff(magnitude) (a->fp_sign ? opposite_cc(magnitude) : (magnitude)) if (a->fp_class < b->fp_class) { /* |a| < |b| */ cc = diff(FPSCR_FL); goto done; } if (a->fp_class > b->fp_class) { /* |a| > |b| */ cc = diff(FPSCR_FG); goto done; } /* now none can be 0: only Inf and numbers remain */ if (ISINF(a)) { /* |Inf| = |Inf| */ cc = FPSCR_FE; goto done; } fpu_sub(fe); if (ISZERO(r)) cc = FPSCR_FE; else if (r->fp_sign) cc = FPSCR_FL; else cc = FPSCR_FG; done: fe->fe_cx = cc; }