home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-14 | 11.5 KB | 325 lines | [TEXT/PJMM] |
- (**********************************************************************************)
- (* Unit to convert Fixed-point numbers to double-precision floating-point numbers.*)
- (* Also converts single-precision floatin-point numbers to fixed-point numbers. *)
- (* One routine illustrates the breakdown of a floating-point number. *)
- (* Last modified: 1995-11-13 *)
- (* *)
- (* send comments & suggestions to: *)
- (* Daniel W. Rickey *)
- (* Department of Medical Physics *)
- (* Manitoba Cancer Treatment and Research Foundation *)
- (* 100 Olivia Street *)
- (* Winnipeg, Manitoba *)
- (* R3E 0V9 CANADA *)
- (* daniel@kaon.mctrf.mb.ca or physics@escape.ca *)
- (**********************************************************************************)
- (* *)
- (* These routines are for programmes that use Fixed point calculations. Conversions *)
- (* between floating-point and fixed-point numbers have been performed with the *)
- (* toolbox routines: *)
- (* Function Fix2X (X: Fixed): Extended; *)
- (* Function X2Fix (X: Extended): Fixed; *)
- (* However the the type Extended is not supported by the PowerPC. Thus, there is *)
- (* a need for conversion routines between Fixed point and single/double-precision *)
- (* numbers. This unit contains four routines: *)
- (* *)
- (* Procedure SplitReal (X: Real); *)
- (* This routine does not do anything useful; its purpose is to illustrate how the *)
- (* bits of a 4-byte floating point number are used to form the number. *)
- (* *)
- (* Function ConvertIntToDouble (X: LongInt): Double; *)
- (* This routine converts a LongInt to a double-precision floating-point value. *)
- (* The algorithm for this is contained in the Inside Mac: PPC Numerics in the *)
- (* assembly languge section, Listing 13-1, page# 13-4 *)
- (* *)
- (* Function ConvertFixedToDouble (X: Fixed): Double; *)
- (* This routine converts a Fixed-point number to a double floating-point value. *)
- (* Note that this routine performs a double precision add or subtraction and thus *)
- (* is very slow on 680x0 machines that do not have a 68881/68882 FPU. *)
- (* *)
- (* Function ConvertRealToFixed (X: Real): Fixed; *)
- (* This routine converts a floating-point number to a fixed-point number. Note *)
- (* this routine uses a number of if - then statements and is probably not as *)
- (* efficient as it could be. This routine does not perform any range checking. *)
- (**********************************************************************************)
-
- (* Note that these conversions have not been tested on a PowerPC. *)
-
- (* Note!!! Double precision numbers are assumed to be 8 bytes long *)
- (* For the Metrowerks compiler, make sure 8-byte Doubles are selected under compiler options *)
-
- Unit FixedPointConversions;
- Interface
-
- Uses
- FixMath, NoCoprocessorMath;
-
- Function ConvertIntToDouble (X: LongInt): Double;
- Procedure SplitReal (X: Real);
- Function ConvertFixedToDouble (X: Fixed): Double;
- Function ConvertRealToFixed (X: Real): Fixed;
-
- Implementation
-
- (**** split a real number into its components ****)
- (* this routine does not do anything useful; its purpose is to illustrate how *)
- (* the bits of a 4-byte floating point number are used to form the number *)
- Procedure SplitReal (X: Real);
- Const
- kSignBit = $80000000;
- kExponentBits = $7F800000;
- kSignificandBits = $007FFFFF;
- k2ToMinus126 = 1.175494351E-38;
-
- Type
- LongPtr = ^LongInt;
-
- Var
- Signed: Real;
- BiasedExponent: LongInt;
- Fraction: Real;
- Value: Real;
-
- Begin
- (* sign of the real number is contained in the top bit *)
- If Boolean(BSR(BAND(LongPtr(@X)^, kSignBit), 31)) Then
- Signed := -1
- Else
- Signed := +1;
-
- {get the biased exponent of the 4-byte real number}
- BiasedExponent := BSR(BAND(LongPtr(@X)^, kExponentBits), 23);
-
- {get fractional part of real number}
- Fraction := BAND(LongPtr(@X)^, kSignificandBits);
- Fraction := Fraction / $800000;
-
- (* decode BiasedExponent & Fraction parts of number to obtain its value *)
- (* values of 0 and 255 have special meanings *)
- If (BiasedExponent = 0) Then
- Begin
- If (Fraction = 0) Then
- Begin
- (* If BiasedExponent = 0 AND Fraction = 0; value is Zero *)
- Value := 0;
- End
- Else
- Begin
- (* If BiasedExponent = 0 AND Fraction ≠ 0; value is denormalised real number *)
- (* sign * 2^-126 * Fraction; The number is VERY small about ±2^(-126) *)
- Value := Signed * k2ToMinus126 * Fraction;
- End; {If (Fraction = 0)}
- End
- Else If (BiasedExponent = 255) Then
- Begin
- If (Fraction = 0) Then
- Begin
- (* If BiasedExponent = 255 AND Fraction = 0; value is an infinity *)
- Value := Signed * Inf;
- End
- Else
- Begin
- (* BiasedExponent = 255 AND Fraction ≠ 0; value is NaN *)
- (* A NaN code is contained in bits 8 through 15 of the fraction field *)
- Value := X;
- End;
- End
- Else
- Begin
- (* If 0 < BiasedExponent < 255; value is a normalised real number *)
- (* =sign * 2^ (BiasedExponent-127) * (1+Fraction) *)
- Value := Signed * Exp2(BiasedExponent - 127) * (1 + Fraction);
- End;
-
- Writeln('Value: ', Value : 1 : 8);
- End; {SplitReal}
-
-
- (**** convert a LongInt to a double floating-point value ****)
- (* The algorithm for this is contained in the Inside Mac: PPC Numerics*)
- (* in the assembly languge section, Listing 13-1, page# 13-4 *)
- Function ConvertIntToDouble (X: LongInt): Double;
- Const
- kExponent = $43300000;
- kInteger = $80000000;
-
- Type
- LongPtr = ^LongInt;
-
- Var
- TempReal, Value: Double;
- aLongPtr: LongPtr;
-
- Begin
- {place $43300000 in top 32 bits of double floating point number}
- aLongPtr := @Value;
- aLongPtr^ := kExponent;
-
- {invert sign of integer}
- X := BXOR(X, $80000000);
-
- {place the longInt in bottom 32 bits of double floating-point value}
- aLongPtr := LongPtr(Ord(@Value) + 4);
- aLongPtr^ := X;
-
- {need to subtract real value of $4330000080000000 from value}
- {first place $43300000 in top 32 bits of a temporary double}
- aLongPtr := @TempReal;
- aLongPtr^ := kExponent;
-
- {next place $80000000 in bottom 32 bits of a temporary double}
- aLongPtr := LongPtr(Ord(@TempReal) + 4);
- aLongPtr^ := kInteger;
-
- {subtract double value of $4330000080000000 from value}
- ConvertIntToDouble := Value - TempReal;
- End; {ConvertIntToDouble}
-
-
- (**** convert a Fixed-point number to a double floating-point value ****)
- Function ConvertFixedToDouble (X: Fixed): Double;
- Const
- kPositiveExponent = $42300000;
- kNegativeExponent = $C2300000;
-
- kFixedOne = $10000; {Fixed-point value of one}
-
- Type
- LongPtr = ^LongInt;
-
- Var
- TempReal, Value: Double;
- aLongPtr: LongPtr;
-
- Begin
- {need to subtract or add real value of $4230000080000000 from value}
- {first place $42300000 in top 32 bits of a temporary double}
- aLongPtr := @TempReal;
- aLongPtr^ := kPositiveExponent;
-
- {next place $80000000 in bottom 32 bits of a temporary double}
- aLongPtr := LongPtr(Ord(@TempReal) + 4);
- aLongPtr^ := kFixedOne;
-
- {get pointer to top 4 bytes of a double floating point number}
- aLongPtr := @Value;
-
- {have to handle things a bit differently for negative numbers}
- {Negative numbers of type Fixed are the two's complement}
- If X >= 0 Then
- Begin
- {place exponent with sign bit set to 0 in top of double}
- aLongPtr^ := kPositiveExponent;
-
- {place the Fixed number in bottom 32 bits of double floating-point value}
- aLongPtr := LongPtr(Ord(@Value) + 4);
- aLongPtr^ := X + kFixedOne;
-
- {double is encoded as exponent*(1 + BSR(X,16)), therefore need to}
- {subtract double value of $4230000080000000 from value}
- {to give exponent*(1 + BSR(X,16)) - exponent*1 = exponent*BSR(X,16)}
- ConvertFixedToDouble := Value - TempReal;
- End
- Else
- Begin
- {place exponent with sign bit set to 1 in top of double}
- aLongPtr^ := kNegativeExponent;
-
- {place the fixed-point number in bottom 32 bits of double floating-point value}
- aLongPtr := LongPtr(Ord(@Value) + 4);
-
- {because it is negative, we need to convert from two's complement}
- {use the built in bnot or Bitnot routines}
- {$IFC UNDEFINED THINK_Pascal}
- aLongPtr^ := Bnot(X) + 1 + kFixedOne;
- {$ELSEC}
- aLongPtr^ := Bitnot(X) + 1 + kFixedOne;
- {$ENDC}
-
-
- {because value is negative, add double value of $4230000080000000 to value}
- {double is encoded as -exponent*(1 + BSR(X,16)), therefore need to}
- {subtract double value of $4230000080000000 from value}
- {to give -exponent*(1 + BSR(X,16)) + exponent*1 = -exponent*BSR(X,16)}
-
- ConvertFixedToDouble := Value + TempReal;
- End;
- End; {ConvertFixedToDouble}
-
-
- (**** converts a floating-point number to a fixed-point number ****)
- Function ConvertRealToFixed (X: Real): Fixed;
- Const
- kSignBit = $80000000;
- kExponentBits = $7F800000;
- kSignificandBits = $007FFFFF;
- k2ToMinus126 = 1.175494351E-38;
- kMaxFixedPoint = $7FFFFFFF;
- kFixedOne = $00010000;
-
- Type
- LongPtr = ^LongInt;
-
- Var
- theSign: LongInt;
- Exponent: LongInt;
- Fraction: LongInt;
- TempFixed: Fixed;
-
- Begin
- (* sign of real number *)
- If Boolean(BSR(BAND(LongPtr(@X)^, kSignBit), 31)) Then
- theSign := -1
- Else
- theSign := +1;
-
- Exponent := BSR(BAND(LongPtr(@X)^, kExponentBits), 23) - 127;
- Fraction := BAND(LongPtr(@X)^, kSignificandBits);
-
- If (Exponent = -127) Then
- Begin
- (* If Exponent = -127 AND Fraction = 0; floating-point number is Zero *)
- (* Else If Exponent = -127 AND Fraction ≠ 0; loating-point number is *)
- (* denormalised real number and = sign * 2^-126 * Fraction *)
- (* denormalised is too small to represent with fixed-point numbers *)
- TempFixed := 0;
- End
- Else If (Exponent = 128) Then
- Begin
- If (Fraction = 0) Then
- Begin
- (* Exponent = 128 AND Fraction = 0; value is an infinity *)
- TempFixed := theSign * kMaxFixedPoint;
- End
- Else
- Begin
- (* Exponent = 128 AND Fraction ≠ 0; value is NaN *)
- TempFixed := 0;
- End;
- End
- Else
- Begin
- (* -127 < Exponent < 128; value is normalised real number *)
- (* sign * 2^(Exponent) * (1+Fraction) *)
-
- {first calculate 2^(Exponent); use a fixed-point value one as start point}
- If Exponent > 0 Then
- TempFixed := BSL(kFixedOne, Exponent)
- Else
- TempFixed := BSR(kFixedOne, -Exponent);
-
- {now add 2^(Exponent)*Fraction to the fixed-point number}
- {subtract 7 from exponent to place fraction at bit 16 instead of bit 23}
- Exponent := Exponent - 7;
- If Exponent > 0 Then
- TempFixed := TempFixed + BSL(Fraction, Exponent) + BSL(1, Exponent)
- Else
- TempFixed := TempFixed + BSR(Fraction, -Exponent) + BSL(1, Exponent);
-
- End;
-
- {now multiply by sign}
- ConvertRealToFixed := theSign * TempFixed;
- End; {ConvertRealToFixed}
-
- End.