File indexing completed on 2024-05-12 05:55:12

0001 /* floatconvert.c: radix conversion, based on floatnum. */
0002 /*
0003     Copyright (C) 2007 - 2009 Wolf Lammen.
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License , or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; see the file COPYING.  If not, write to:
0017 
0018       The Free Software Foundation, Inc.
0019       59 Temple Place, Suite 330
0020       Boston, MA 02111-1307 USA.
0021 
0022 
0023     You may contact the author by:
0024        e-mail:  ookami1 <at> gmx <dot> de
0025        mail:  Wolf Lammen
0026               Oertzweg 45
0027               22307 Hamburg
0028               Germany
0029 
0030 *************************************************************************/
0031 
0032 #include "floatconvert.h"
0033 #include "floatcommon.h"
0034 #include "floatconst.h"
0035 #include "floatipower.h"
0036 #include <stdlib.h>
0037 
0038 typedef struct{
0039   t_number_desc n;
0040   t_longint l;
0041   floatnum f;
0042   int bitlength;
0043   int trailing0;
0044   int lgbase;
0045 }t_ext_number;
0046 typedef t_ext_number* p_ext_number;
0047 
0048 /************************   conversion to/from longint   *******************/
0049 
0050 static unsigned
0051 _digitblock(
0052   floatnum f,
0053   int ofs,
0054   int count)
0055 {
0056   unsigned result;
0057 
0058   result = 0;
0059   for (; --count >= 0;)
0060     result = 10 * result + float_getdigit(f, ofs++);
0061   return result;
0062 }
0063 
0064 Error
0065 _floatnum2longint(
0066   t_longint* longint,
0067   floatnum f)
0068 {
0069   int digits;
0070   int i;
0071   unsigned factor;
0072 
0073   longint->length = 0;
0074   digits = float_getexponent(f) + 1;
0075   i = digits % 9;
0076   _longintadd(longint, _digitblock(f, 0, i));
0077   factor = 1000000000;
0078   while (i < digits)
0079   {
0080     if (_longintmul(longint, factor)
0081         || _longintadd(longint, _digitblock(f, i, 9)))
0082       return IOConversionOverflow;
0083     i += 9;
0084   }
0085   /* extra element for floatlong operations */
0086   *(longint->value+longint->length) = 0;
0087   return Success;
0088 }
0089 
0090 static void
0091 _setunsigned(
0092   floatnum f,
0093   unsigned value)
0094 {
0095   float_setinteger(f, value);
0096   if ((int)value < 0)
0097     float_add(f, f, &cUnsignedBound, EXACT);
0098 }
0099 
0100 void
0101 _longint2floatnum(
0102   floatnum f,
0103   t_longint* longint)
0104 {
0105   floatstruct tmp;
0106   int idx;
0107 
0108   float_setzero(f);
0109   if(longint->length == 0)
0110     return;
0111   float_create(&tmp);
0112   idx = longint->length - 1;
0113   for (; idx >= 0; --idx)
0114   {
0115     _setunsigned(&tmp, longint->value[idx]);
0116     float_mul(f, f, &cUnsignedBound, EXACT);
0117     float_add(f, f, &tmp, EXACT);
0118   }
0119   float_free(&tmp);
0120 }
0121 
0122 /**************************   io routines   **************************/
0123 
0124 static int
0125 _max(
0126   int a,
0127   int b)
0128 {
0129   return a > b? a : b;
0130 }
0131 
0132 static char
0133 _validmode(
0134   char mode)
0135 {
0136   return mode >= IO_MODE_SCIENTIFIC && mode <= IO_MODE_COMPLEMENT;
0137 }
0138 
0139 static int
0140 lgbase(
0141   signed char base)
0142 {
0143   switch(base)
0144   {
0145     case 2:
0146       return 1;
0147     case 8:
0148       return 3;
0149     case 16:
0150       return 4;
0151   }
0152   return 0;
0153 }
0154 
0155 static char
0156 _getfnintdigit(
0157   int ofs,
0158   p_seq_desc n)
0159 {
0160   if (ofs <= n->digits)
0161     return float_getdigit((floatnum)(n->param), ofs);
0162   return 0;
0163 }
0164 
0165 static char
0166 _getfnfracdigit(
0167   int ofs,
0168   p_seq_desc n)
0169 {
0170   floatnum x;
0171   int exp;
0172 
0173   x = (floatnum)(n->param);
0174   exp = float_getexponent(x);
0175   if (ofs >= 0)
0176     return float_getdigit(x, ofs + exp + 1);
0177   return 0;
0178 }
0179 
0180 static void
0181 _setfndesc(
0182   p_number_desc n,
0183   floatnum x)
0184 {
0185   int digits;
0186 
0187   n->intpart.seq.base = 10;
0188   digits = _max(float_getexponent(x) + 1, 0);
0189   n->intpart.seq.digits = digits;
0190   n->intpart.seq.trailing0 = _max(digits - float_getlength(x), 0);
0191   n->intpart.seq.param = x;
0192   n->intpart.getdigit = _getfnintdigit;
0193   n->fracpart.seq.base = 10;
0194   n->fracpart.seq.leadingSignDigits = _max(-float_getexponent(x) - 1, 0);
0195   n->fracpart.seq.digits = float_getlength(x) - digits
0196                            + n->fracpart.seq.leadingSignDigits;
0197   n->fracpart.seq.param = x;
0198   n->fracpart.getdigit = _getfnfracdigit;
0199 }
0200 
0201 static Error
0202 _pack2longint(
0203   t_longint* l,
0204   p_ext_seq_desc n)
0205 {
0206   int bitofs;
0207   int ofs;
0208   int logbase;
0209 
0210   logbase = lgbase(n->seq.base);
0211   ofs = n->seq.leadingSignDigits;
0212   if (_significantdigits(&n->seq) == 0)
0213       /* can be true in complement case: 0xFF00 */
0214     --ofs;
0215   bitofs = (n->seq.digits - ofs) * logbase;
0216   if (!_longintsetsize(l, bitofs))
0217     return IOBufferOverflow;
0218   for (; bitofs > 0;)
0219   {
0220     bitofs -= logbase;
0221     _orsubstr(l->value, bitofs, n->getdigit(ofs++, &n->seq));
0222   }
0223   return Success;
0224 }
0225 
0226 static char
0227 _getlongintdigit(
0228   int ofs,
0229   p_seq_desc n)
0230 {
0231   if (ofs < 0 || ofs >= n->digits)
0232     return 0;
0233   return _bitsubstr(((t_longint*)(n->param))->value,
0234                     (n->digits - ofs - 1) * lgbase(n->base))
0235          & (n->base - 1);
0236 }
0237 
0238 static char
0239 _getlongintofsdigit(
0240   int ofs,
0241   p_seq_desc n)
0242 {
0243   p_number_desc nmb;
0244   int digits;
0245 
0246   nmb = (p_number_desc)(n->param);
0247   digits = n->digits;
0248   if (ofs < 0 || ofs >= digits)
0249     return 0;
0250   digits += nmb->fracpart.seq.digits;
0251   return _bitsubstr(((t_longint*)(nmb->fracpart.seq.param))->value,
0252                     (digits - ofs - 1) * lgbase(n->base))
0253          & (n->base - 1);
0254 }
0255 
0256 static void
0257 _setlongintdesc(
0258   p_ext_seq_desc n,
0259   t_longint* l,
0260   signed char base)
0261 {
0262   int lg;
0263 
0264   n->seq.base = base;
0265   lg = lgbase(base);
0266   n->seq.digits = (_bitlength(l) + lg - 1) / lg;
0267   n->seq.leadingSignDigits = 0;
0268   n->seq.trailing0 = _lastnonzerobit(l) / lg;
0269   n->seq.param = l;
0270   n->getdigit = _getlongintdigit;
0271 }
0272 
0273 static Error
0274 _packdec2int(
0275   floatnum x,
0276   p_ext_seq_desc n)
0277 {
0278   int ofs;
0279   int exp;
0280   int bufsz;
0281   int i;
0282   char buf[DECPRECISION];
0283 
0284   float_setnan(x);
0285   ofs = n->seq.leadingSignDigits;
0286   exp = n->seq.trailing0;
0287   bufsz = n->seq.digits - ofs - exp;
0288   if (bufsz > DECPRECISION)
0289     return IOBufferOverflow;
0290   if (bufsz == 0)
0291     float_setzero(x);
0292   else
0293     for (i = -1; ++i < bufsz;)
0294       buf[i] = n->getdigit(ofs++, &n->seq) + '0';
0295   float_setsignificand(x, NULL, buf, bufsz);
0296   float_setexponent(x, exp + bufsz - 1);
0297   return Success;
0298 }
0299 
0300 static Error
0301 _packbin2int(
0302   floatnum x,
0303   p_ext_seq_desc n)
0304 {
0305   t_longint l;
0306   Error result;
0307 
0308   float_setnan(x);
0309   if ((result = _pack2longint(&l, n)) != Success)
0310     return result;
0311   _longint2floatnum(x, &l);
0312   return Success;
0313 }
0314 
0315 static Error
0316 _pack2int(
0317   floatnum x,
0318   p_ext_seq_desc n)
0319 {
0320   switch(n->seq.base)
0321   {
0322   case IO_BASE_NAN:
0323     float_setnan(x);
0324     break;
0325   case IO_BASE_ZERO:
0326     float_setzero(x);
0327     break;
0328   case 10:
0329     return _packdec2int(x, n);
0330   default:
0331     return _packbin2int(x, n);
0332   }
0333   return Success;
0334 }
0335 
0336 static Error
0337 _pack2frac(
0338   floatnum x,
0339   p_ext_seq_desc n,
0340   int digits)
0341 {
0342   floatstruct tmp;
0343   int exp;
0344   Error result;
0345 
0346   n->seq.digits -= n->seq.trailing0;
0347   n->seq.trailing0 = 0;
0348   switch(n->seq.base)
0349   {
0350   case IO_BASE_NAN:
0351     float_setnan(x);
0352     break;
0353   case IO_BASE_ZERO:
0354     float_setzero(x);
0355     break;
0356   default:
0357     if ((result = _pack2int(x, n)) != Success)
0358       return result;
0359     float_create(&tmp);
0360     float_setinteger(&tmp, n->seq.base);
0361     _raiseposi(&tmp, &exp, n->seq.digits, digits+2);
0362     float_div(x, x, &tmp, digits + 2);
0363     float_setexponent(x, float_getexponent(x) - exp);
0364     float_free(&tmp);
0365   }
0366   n->seq.digits += n->seq.trailing0;
0367   return Success;
0368 }
0369 
0370 Error
0371 pack2floatnum(
0372   floatnum x,
0373   p_number_desc n)
0374 {
0375   floatstruct tmp;
0376   int digits;
0377   int saveerr;
0378   int saverange;
0379   Error result;
0380   signed char base;
0381 
0382   if ((result = _pack2int(x, &n->intpart)) != Success)
0383     return result;
0384   if (float_isnan(x))
0385     return Success;
0386   saveerr = float_geterror();
0387   saverange = float_setrange(MAXEXP);
0388   float_create(&tmp);
0389   float_move(&tmp, x);
0390   float_setzero(x);
0391   digits = DECPRECISION - float_getexponent(&tmp);
0392   if (digits <= 0
0393       || (result = _pack2frac(x, &n->fracpart, digits)) == Success)
0394     float_add(x, x, &tmp, DECPRECISION);
0395   if (result != Success)
0396     return result;
0397   if ((!float_getlength(x)) == 0) /* no zero, no NaN? */
0398   {
0399     base = n->prefix.base;
0400     float_setinteger(&tmp, base);
0401     if (n->exp >= 0)
0402     {
0403       _raiseposi_(&tmp, n->exp, DECPRECISION + 2);
0404       float_mul(x, x, &tmp, DECPRECISION + 2);
0405     }
0406     else
0407     {
0408       _raiseposi_(&tmp, -n->exp, DECPRECISION + 2);
0409       float_div(x, x, &tmp, DECPRECISION + 2);
0410     }
0411   }
0412   float_free(&tmp);
0413   float_setsign(x, n->prefix.sign == IO_SIGN_COMPLEMENT? -1 : n->prefix.sign);
0414   float_geterror();
0415   float_seterror(saveerr);
0416   float_setrange(saverange);
0417   if (!float_isvalidexp(float_getexponent(x)))
0418     float_setnan(x);
0419   return float_isnan(x)? IOExpOverflow : Success;
0420 }
0421 
0422 static Error
0423 _outscidec(
0424   p_otokens tokens,
0425   floatnum x,
0426   p_number_desc n,
0427   int scale)
0428 {
0429   float_checkedround(x, scale + 1);
0430   n->exp = float_getexponent(x);
0431   float_setexponent(x, 0);
0432   _setfndesc(n, x);
0433   return desc2str(tokens, n, scale);
0434 }
0435 
0436 static int
0437 _checkbounds(
0438   floatnum x,
0439   int digits,
0440   signed char base)
0441 {
0442   if (float_getexponent(x) < 0)
0443   {
0444     float_muli(x, x, base, digits);
0445     return -1;
0446   }
0447   else if (float_asinteger(x) >= base)
0448   {
0449     float_divi(x, x, base, digits);
0450     return 1;
0451   }
0452   return 0;
0453 }
0454 
0455 static void
0456 _scale2int(
0457   floatnum x,
0458   int scale,
0459   signed char base)
0460 {
0461   floatstruct pwr;
0462   int pwrexp;
0463 
0464   (void)scale;
0465 
0466   if (scale != 0)
0467   {
0468     float_create(&pwr);
0469     float_setinteger(&pwr, base);
0470     _raiseposi(&pwr, &pwrexp, scale, DECPRECISION+4);
0471     float_mul(x, x, &pwr, DECPRECISION+4);
0472     float_addexp(x, pwrexp);
0473     float_free(&pwr);
0474   }
0475   float_roundtoint(x, TONEAREST);
0476 }
0477 
0478 static Error
0479 _fixp2longint(
0480   p_number_desc n,
0481   t_longint* l,
0482   floatnum x,
0483   int scale)
0484 {
0485   Error result;
0486   _scale2int(x, scale, n->prefix.base);
0487   result = _floatnum2longint(l, x);
0488   if (result != Success)
0489     return result;
0490   _setlongintdesc(&n->fracpart, l, n->prefix.base);
0491   return Success;
0492 }
0493 
0494 static int
0495 _extractexp(
0496   floatnum x,
0497   int scale,
0498   signed char base)
0499 {
0500   floatstruct pwr;
0501   floatstruct fbase;
0502   int decprec;
0503   int pwrexp;
0504   int exp;
0505   int logbase;
0506 
0507   (void)scale;
0508 
0509   logbase = lgbase(base);
0510   decprec = DECPRECISION + 3;
0511   exp = (int)(aprxlog10fn(x) * 3.321928095f);
0512   if (float_getexponent(x) < 0)
0513     exp -= 3;
0514   exp /= logbase;
0515   if (exp != 0)
0516   {
0517     float_create(&fbase);
0518     float_setinteger(&fbase, base);
0519     float_create(&pwr);
0520     float_copy(&pwr, &fbase, EXACT);
0521     _raiseposi(&pwr, &pwrexp, exp < 0? -exp : exp, decprec);
0522     if (float_getexponent(x) < 0)
0523     {
0524       float_addexp(x, pwrexp);
0525       float_mul(x, x, &pwr, decprec);
0526     }
0527     else
0528     {
0529       float_addexp(x, -pwrexp);
0530       float_div(x, x, &pwr, decprec);
0531     }
0532     float_free(&pwr);
0533     float_free(&fbase);
0534   }
0535   exp += _checkbounds(x, decprec, base);
0536   return exp;
0537 }
0538 
0539 static void
0540 _setscale(
0541   p_number_desc n,
0542   t_longint* l,
0543   int scale)
0544 {
0545   (void)l;
0546 
0547   n->intpart.seq.leadingSignDigits = 0;
0548   n->intpart.seq.trailing0 = n->fracpart.seq.trailing0 - scale;
0549   if (n->intpart.seq.trailing0 < 0)
0550     n->intpart.seq.trailing0 = 0;
0551   n->intpart.seq.base = n->fracpart.seq.base;
0552   n->intpart.seq.digits = n->fracpart.seq.digits - scale;
0553   n->intpart.getdigit = _getlongintofsdigit;
0554   n->intpart.seq.param = n;
0555 
0556   n->fracpart.seq.digits = scale;
0557   if (n->fracpart.seq.trailing0 >= scale)
0558   {
0559     n->fracpart.seq.base = IO_BASE_ZERO;
0560     n->fracpart.seq.trailing0 = scale;
0561   }
0562 }
0563 
0564 static Error
0565 _outscihex(
0566   p_otokens tokens,
0567   floatnum x,
0568   p_number_desc n,
0569   int scale)
0570 {
0571   t_longint l;
0572   Error result;
0573 
0574   n->exp = _extractexp(x, scale, n->prefix.base);
0575   result = _fixp2longint(n, &l, x, scale);
0576   if (result != Success)
0577     return result;
0578   /* rounding in _fixp2longint may have increased the exponent */
0579   n->exp += n->fracpart.seq.digits - 1 - scale;
0580   _setscale(n, &l, n->fracpart.seq.digits - 1);
0581   return desc2str(tokens, n, scale);
0582 }
0583 
0584 static char
0585 _isvalidbase(
0586   signed char base)
0587 {
0588   return base == 10 || lgbase(base) != 0;
0589 }
0590 
0591 static Error
0592 _outsci(
0593   p_otokens tokens,
0594   floatnum x,
0595   p_number_desc n,
0596   int scale)
0597 {
0598   if (n->prefix.base == 10)
0599     return _outscidec(tokens, x, n, scale);
0600   return _outscihex(tokens, x, n, scale);
0601 }
0602 
0603 static Error
0604 _outfixpdec(
0605   p_otokens tokens,
0606   floatnum x,
0607   p_number_desc n,
0608   int scale)
0609 {
0610   int digits;
0611 
0612   digits = float_getexponent(x) + scale + 1;
0613   if (digits <= 0)
0614     /* underflow */
0615     return IOConversionUnderflow;
0616   if (float_round(x, x, digits, TONEAREST) != TRUE)
0617     /* float_round() can err if the number contains too many digits */
0618     return float_geterror();
0619   _setfndesc(n, x);
0620   return desc2str(tokens, n, scale);
0621 }
0622 
0623 static Error
0624 _outfixphex(
0625   p_otokens tokens,
0626   floatnum x,
0627   p_number_desc n,
0628   int scale)
0629 {
0630   t_longint l;
0631   Error result;
0632 
0633   float_copy(x, x, DECPRECISION+1);
0634   result = _fixp2longint(n, &l, x, scale);
0635   if (result != Success)
0636     return result;
0637   if (l.length == 0) {
0638     result = float_geterror();
0639     return result != Success ? result : IOConversionUnderflow;
0640   }
0641   _setscale(n, &l, scale);
0642   return desc2str(tokens, n, scale);
0643 }
0644 
0645 static Error
0646 _outfixp(
0647   p_otokens tokens,
0648   floatnum x,
0649   p_number_desc n,
0650   int scale)
0651 {
0652   if (n->prefix.base == 10)
0653     return _outfixpdec(tokens, x, n, scale);
0654   return _outfixphex(tokens, x, n, scale);
0655 }
0656 
0657 static Error
0658 _outengdec(
0659   p_otokens tokens,
0660   floatnum x,
0661   p_number_desc n,
0662   int scale)
0663 {
0664   int shift;
0665 
0666   float_checkedround(x, scale + 1);
0667   n->exp = float_getexponent(x);
0668   if (n->exp < 0)
0669     shift = 2 - (-n->exp-1) % 3;
0670   else
0671     shift = n->exp % 3;
0672   float_setexponent(x, shift);
0673   n->exp -= shift;
0674   _setfndesc(n, x);
0675   return desc2str(tokens, n, scale - shift);
0676 }
0677 
0678 static Error
0679 _outeng(
0680   p_otokens tokens,
0681   floatnum x,
0682   p_number_desc n,
0683   int scale)
0684 {
0685   if (n->prefix.base != 10 || scale < 2)
0686     return InvalidParam;
0687   return _outengdec(tokens, x, n, scale);
0688 }
0689 
0690 static Error
0691 _outcompl(
0692   p_otokens tokens,
0693   floatnum x,
0694   p_number_desc n,
0695   int scale)
0696 {
0697   (void)scale;
0698 
0699   if (!float_isinteger(x))
0700     return IOInvalidComplement;
0701   if (n->prefix.sign == IO_SIGN_MINUS)
0702     n->prefix.sign = IO_SIGN_COMPLEMENT;
0703   else
0704     n->prefix.sign = IO_SIGN_NONE;
0705   return _outfixphex(tokens, x, n, 0);
0706 }
0707 
0708 static void
0709 _emptybuffer(
0710   p_buffer token)
0711 {
0712   if (token->sz > 0)
0713     *(token->buf) = '\0';
0714   else
0715     token->buf = NULL;
0716 }
0717 
0718 static void
0719 _emptytokens(
0720   p_otokens tokens)
0721 {
0722   _emptybuffer(&tokens->intpart);
0723   _emptybuffer(&tokens->fracpart);
0724   tokens->sign = IO_SIGN_NONE;
0725   tokens->base = IO_BASE_NAN;
0726   tokens->exp = 0;
0727 }
0728 
0729 Error float_out(
0730   p_otokens tokens,
0731   floatnum x,
0732   int scale,
0733   signed char base,
0734   char outmode)
0735 {
0736   t_number_desc n;
0737 
0738   _emptytokens(tokens);
0739   /* do some sanity checks first */
0740   if (!_validmode(outmode) || scale < 0 || !_isvalidbase(base))
0741     return InvalidParam;
0742   _clearnumber(&n);
0743   if (float_iszero(x))
0744     n.prefix.base = IO_BASE_ZERO;
0745   else if (!float_isnan(x))
0746     n.prefix.base = base;
0747   if (!_isvalidbase(n.prefix.base))
0748     /* NaN and 0 are handled here */
0749     return desc2str(tokens, &n, 0);
0750   n.prefix.sign = float_getsign(x);
0751   float_abs(x);
0752   switch (outmode)
0753   {
0754   case IO_MODE_FIXPOINT:
0755     return _outfixp(tokens, x, &n, scale);
0756   case IO_MODE_ENG:
0757     return _outeng(tokens, x, &n, scale);
0758   case IO_MODE_COMPLEMENT:
0759     return _outcompl(tokens, x, &n, 0);
0760   default:
0761     return _outsci(tokens, x, &n, scale);
0762   }
0763 }
0764 
0765 Error
0766 float_in(
0767   floatnum x,
0768   p_itokens tokens)
0769 {
0770   t_number_desc n;
0771   Error result;
0772 
0773   if ((result = str2desc(&n, tokens)) == Success)
0774     result = pack2floatnum(x, &n);
0775   if (result != Success)
0776   {
0777     _seterror(x, BadLiteral);
0778     float_setnan(x);
0779   }
0780   return result;
0781 }