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