Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!sun-barr!newstop!sun!amdcad!mozart.amd.com!proton!tim From: tim@proton.amd.com (Tim Olson) Newsgroups: comp.sys.m68k Subject: Re: ML FP Message-ID: <1990Jul12.224046.10673@mozart.amd.com> Date: 12 Jul 90 22:40:46 GMT References: <4739@munnari.oz.au> <11865@netcom.UUCP> Sender: usenet@mozart.amd.com (Usenet News) Reply-To: tim@amd.com (Tim Olson) Organization: Advanced Micro Devices, Inc., Austin, Texas Lines: 296 | In a previous article, krooglik@gondwana10.ecr.mu.oz (Alex KROOGLIK) writes: | > | > Can anyone help me. I have been programming in 68K on the Amiga for | >around 2 years now and I have finally taken the plunge and tried to write | >some FP software. However, I am finding this extremely diffcult. I have | >considered using BCD but I find it too slow. What I would like to know | >is if anyone has written FP software that is SUPER accurate. 128 bits ^^^^^^^^^^^^^^^ | > 1. How do I turn a decimal number (eg 1.23123484) into Binary. In article <11865@netcom.UUCP> mcmahan@netcom.UUCP (Dave Mc Mahan) writes: | float base10_to_float(input) | char *input; | { | int decimal_pt_seen; | float output_value, | scale_factor; | | decimal_pt_seen = FALSE; | output_value = 0.0; | scale_factor = 0.1; . . . The problem with this is that it uses floating point, and values that are not exactly representable in binary floating-point implementations (i.e. 0.1). Here is a more accurate way to do this conversion (taken from an assembler I wrote): ----------------------------------------------------------------------------- /* atoieee -- convert ascii to IEEE representation */ atoieee(type) int type; { int i, ch, /* character for conversion */ m_sign, /* mantissa sign */ e_sign, /* exponent sign */ decpt, /* decimal point */ d_exp, /* decimal exponent */ c_exp, /* calculated decimal exponent */ exp; /* binary exponent */ WORD mant1, /* mantissa word 1 */ mant2, /* mantissa word 2 */ tmp1, /* temporary mantissa */ tmp2; m_sign = e_sign = decpt = d_exp = c_exp = exp = 0; mant1 = mant2 = 0; /* skip optional white space */ if (!skipwhite()) { error(XPFLOAT); return (FALSE); } /* get optional mantissa sign */ ch = sgetc(); if (ch == '+') ch = sgetc(); /* skip over plus sign */ else if (ch == '-') { ch = sgetc(); ++m_sign; } /* convert mantissa */ if ((ch != '.') && (ch < '0' || ch > '9')) { error(XPFLOAT); return (FALSE); } while ((ch == '.') || (ch >= '0' && ch <= '9')) { if (ch == '.') { if (decpt) { error(XPFLOAT); return (FALSE); } else ++decpt; } else { if (mant2 < 214748364) { /* check for overflow */ /* multiply mant1, mant2 by 10 */ dplshift(&mant1,&mant2,1); tmp1 = mant1; tmp2 = mant2; dplshift(&mant1,&mant2,2); dpadd(&mant1,&mant2,tmp1,tmp2); /* add in the digit */ dpadd(&mant1,&mant2,(WORD)ch-'0',(WORD)0); } else /* ignore digit, bump exponent */ ++c_exp; if (decpt) --c_exp; } ch = sgetc(); } /* check for an exponent */ if (ch == 'e' || ch == 'E') { ch = sgetc(); /* get optional exponent sign */ if (ch == '+') ch = sgetc(); else if (ch == '-') { ++e_sign; ch = sgetc(); } if (ch < '0' || ch > '9') { error(XPFLOAT); return (FALSE); } while (ch >= '0' && ch <= '9') { if (d_exp < 214748364) d_exp = d_exp*10 + (ch - '0'); ch = sgetc(); } } /* put back last character so gettok() can use it */ sungetc(); if (e_sign) d_exp = -d_exp; d_exp += c_exp; /* add calculated exponent from decimal point */ /* calculate binary exponent */ if (mant1 || mant2) { /* no calculation if mantissa is zero */ if (d_exp >= 0) { /* scale up */ while (d_exp != 0) { --d_exp; while (mant2 > 429496729) { /* shift down */ dprshift(&mant1,&mant2,1); ++exp; } tmp1 = mant1; tmp2 = mant2; dplshift(&mant1,&mant2,2); dpadd(&mant1,&mant2,tmp1,tmp2); ++exp; } } else { /* scale down */ while (d_exp != 0) { ++d_exp; while ((mant2 & 0x80000000) == 0) { dplshift(&mant1,&mant2,1); --exp; } tmp1 = 0; /* set remainder to 0 */ tmp2 = 0; for (i=0; i<64; ++i) { /* do divide */ qplshift(&tmp1,&tmp2,&mant1,&mant2,1); dpsub(&tmp1,&tmp2,(WORD)5,(WORD)0); if (tmp2 & 0x80000000) dpadd(&tmp1,&tmp2,(WORD)5, (WORD)0); else mant1 |= 1; } --exp; } } while ((mant2 & 0x80000000) == 0) { /* now normalize value */ dplshift(&mant1,&mant2,1); --exp; } dplshift(&mant1,&mant2,1); /* shift one more time to get 1.f */ --exp; exp += 64; if (type == FLOAT) { Floatval1 = m_sign << 31; if (exp > 127 || exp < -128) error(EOOR); exp += 127; /* bias by 127 for float */ Floatval1 |= (exp & 0xff) << 23; Floatval1 |= (mant2 & 0xfffffe00) >> 9; } else { /* convert a double */ Floatval1 = m_sign << 31; if (exp > 1023 || exp < -1024) error(EOOR); exp += 1023; /* bias by 1023 for double */ Floatval1 |= (exp & 0xfff) << 20; Floatval1 |= mant2 >> 12; Floatval2 = (mant2 & 0xfff) << 20; Floatval2 |= mant1 >> 12; } } return (TRUE); } /* dplshift -- double precision left shift */ dplshift(value1,value2,amount) WORD *value1, *value2; int amount; { int carry; while (amount--) { carry = ((*value1 & 0x80000000) != 0); *value1 <<= 1; *value2 <<= 1; *value2 |= carry; } } /* dprshift -- double precision right shift */ dprshift(value1,value2,amount) WORD *value1, *value2; int amount; { int carry; while (amount--) { carry = ((*value2 & 0x1) != 0); *value2 = (*value2 >> 1) & 0x7fffffff; *value1 = (*value1 >> 1) & 0x7fffffff | (carry << 31); } } /* qplshift -- quad precision left shift */ qplshift(value1,value2,value3,value4,amount) WORD *value1, *value2, *value3, *value4; int amount; { int carry1, carry2, carry3; while (amount--) { carry1 = ((*value3 & 0x80000000) != 0); carry2 = ((*value4 & 0x80000000) != 0); carry3 = ((*value1 & 0x80000000) != 0); *value3 <<= 1; *value4 <<= 1; *value4 |= carry1; *value1 <<= 1; *value1 |= carry2; *value2 <<= 1; *value2 |= carry3; } } /* dpadd -- double precision add */ dpadd (dest1,dest2,src1,src2) WORD *dest1, *dest2, src1, src2; { int carry, cin31, a31, b31; cin31 = ((((*dest1&0x7fffffff) + (src1&0x7fffffff)) & 0x80000000) != 0); a31 = ((*dest1 & 0x80000000) != 0); b31 = ((src1 & 0x80000000) != 0); carry = ((a31 + b31 + cin31) > 1); *dest1 += src1; *dest2 += src2 + carry; } /* dpsub -- double precision subtraction */ dpsub (dest1,dest2,src1,src2) WORD *dest1, *dest2, src1, src2; { int borrow, bin31, a31, b31; bin31 = ((((*dest1&0x7fffffff) - (src1&0x7fffffff)) & 0x80000000) != 0); a31 = ((*dest1 & 0x80000000) != 0); b31 = ((src1 & 0x80000000) != 0); borrow = ((a31 - b31 - bin31) < 0); *dest1 -= src1; *dest2 -= src2 + borrow; } -- Tim Olson Advanced Micro Devices (tim@amd.com)