Newsgroups: comp.sys.apple2.programmer Path: blue.weeg.uiowa.edu!news.uiowa.edu!uunet!haven.umd.edu!ames!waikato!comp.vuw.ac.nz!actrix.gen.nz!dempson From: dempson@actrix.gen.nz (David Empson) Subject: Re: help for extended data format. Message-ID: Keywords: extended data format. Organization: Actrix Information Exchange References: <369lr5$ju6@news.doit.wisc.edu> Date: Tue, 4 Oct 1994 10:37:28 GMT Lines: 177 In article <369lr5$ju6@news.doit.wisc.edu>, Zhengran Li wrote: > > could anyone tell me how to convert an extended 80-bit data > to a decimal number? I assume you mean in assembly language, using ORCA/M. If not, the following information will be of limited use. I'm also assuming that by "decimal number" you actually mean "decimal string", as opposed to some kind of packed decimal format (though the conversion code does produce this as an intermediate result). There may already be functions to do this in SYSLIB, but I'm not aware of any off-hand, so I'll give an example of doing it using SANE. You must have the SANE toolset started up. It requires a single page of direct page space. Somewhere near the start of your program, allocate enough memory for one page (preferably page aligned) - you could steal it from your direct page/stack segment, for example. ph2 DPAddr ; Push bank zero address of direct page space _SANEStartUp Before your program terminates, it must shut down SANE: _SANEShutDown Somewhere in the middle, you need to convert a SANE extended precision floating point number to a decimal string. The following code should give you a rough guide. Obtaining a decimal string is a two step process. You first need to convert the extended FP number to a decimal record, then to a string. Each step requires a data structure called a decform record, which specifies the format of the decimal numbers. The decform record is defined as follows: DecForm dc i2'style' ; style of number: 0 = floating point, 1 = fixed dc i2'digits' ; number of digits For a floating point number, 'digits' is the number of significant digits. For a fixed point number, 'digits' is the number of digits to the right of the decimal point, and may be negative. The decimal record is the intermediate format used in the conversion. It is defined as follows. Decimal ds 2 ; sign (0 = postive, 1 = negative) ds 2 ; exponent (power of ten) ds 19 ; Pascal string holding digits The pascal string begins with a length byte. Note that 18 digits is the maximum portable size of the string. The IIgs implementation can actually return up to 28 digits (if you ask for that many). The number represented is: (-1 ^ sign) * string * (10 ^ exponent) For example, sign of 1, exponent of -3 and string of '85' represents the number -0.085. Infinities are represented by a string of 'I'. NaNs (not-a-number) are represented by a string of 'N' or 'N' followed by a hex number in ASCII. If you are using floating format, the string need only hold the number of significant digits plus 1 for the length byte. If you are using fixed format, it is possible that the number will not fit in the output string, e.g. if it is too small or large in magnitude. In this case, SANE might return '?' in the string, or may truncate the result. To test for a truncated result, write code to implement the following: TooBig := (-Decimal.exponent <> DecForm.digits) OR (Decimal.string[1] = '?'); To convert from an extended number to a Decimal record, use the following code. ph4 #DecForm ; Address of DecForm record ph4 #Number ; Address of extended floating point number ph4 #Decimal ; Address of Decimal record FX2DEC To convert from the Decimal record to a string, use the following code: ph4 #DecForm ; Address of DecForm record ph4 #Decimal ; Address of Decimal record ph4 #String ; Address of output string FDEC2STR The FX2DEC and FDEC2STR macros are in M16.SANE. The output string is also a Pascal string (with leading length byte). You should normally use the same DecForm record for each stage of the conversion. The output string needs to be large enough to hold the converted string (length of the string in the DecForm record, possibly with the addition of a decimal point, leading zero, and/or exponent), plus the length byte. If you specify floating point style in the DecForm record, the string will be of the form [-| ]m[.nnn]e[+|-]dddd i.e. leading minus or space, single digit (0 only if the value is zero), optional decimal point and following digits (only if the "digits" field of the DecForm record was greater than 1), the letter 'e', plus or minus sign, then one to four exponent digits. Fixed output style is of the form [-]mmm[.nnn] i.e. optional leading minus sign, at least one digit (no leading zeros), optional decimal point and fraction (only if the "digits" field of the DecForm record was not zero). Special cases: - A negative value of "digits" in the decform record is treated as zero for string output, and is only meaningful for fixed point output (it forces zeros before the decimal point, if I read the documentation right). - If the DecForm record calls for more digits than are present in the string field of the Decimal record, zero padding will be used as required. - If the string needs to be longer than 80 characters, '?' will be returned. - NaNs are formatted as NAN(ddd) and infinities as INF. Both may be preceded by a leading sign or space, depending on fixed or floating format. Here is an example from the Apple Numerics Manual, in Pascal. Assume you have an exact amount of money, in units of pennies. This is stored in an extended-precision FP number. You want to output the result in dollars and cents. Simply dividing by 100 may produce an inexact answer, because hundredths are not exact in binary. To get around this, we convert to decimal, adjust the power of ten, and then convert to a string. This method is also faster, since you don't have to do a SANE division. VAR df: DecForm; pennies: extended; dPennies: decimal; { decimal record } dollars: DecStr; BEGIN df.style := FixedDecimal; df.digits := 0; { Fixed point, no digits after the decimal point } Num2Dec(df, pennies, dPennies); { FX2DEC in assembly language } dPennies.exp := dPennies.exp - 2; { Divide by 100 } df.digits := 2; { Request 2 digits after dec pt. } Dec2Str(df, dPennies, dollars); { FDEC2STR in assembly language } END; As I've typed all this in from the manual and haven't tried it myself, there may be typos. Try it out and let me know if it works! -- David Empson dempson@actrix.gen.nz Snail mail: P.O. Box 27-103, Wellington, New Zealand