home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue51 / Alfresco / CvtSingleUnit.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-10-03  |  4.9 KB  |  189 lines

  1. unit CvtSingleUnit;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Button1: TButton;
  12.     Label1: TLabel;
  13.     Label2: TLabel;
  14.     procedure Button1Click(Sender: TObject);
  15.   private
  16.     { Private declarations }
  17.   public
  18.     { Public declarations }
  19.   end;
  20.  
  21. var
  22.   Form1: TForm1;
  23.  
  24. implementation
  25.  
  26. {$R *.DFM}
  27.  
  28. function ConvertSingle(S : single) : string;
  29. const
  30.   RadixPoint = 40;
  31. var
  32.   L : longint absolute S;
  33.   i, Inx   : integer;
  34.   Carry    : integer;
  35.   Sign     : char;
  36.   FirstDigit, LastDigit : integer;
  37.   Exponent : integer;
  38.   MantStr  : string;
  39.   Value    : array [0..255] of byte;
  40. begin
  41.   {extract out the sign, exponent and mantissa}
  42.   if (L < 0) then
  43.     Sign := '-'
  44.   else
  45.     Sign := '+';
  46.   Exponent := (L shr 23) and $FF;
  47.   L := L and $007FFFFF;
  48.  
  49.   {check for the special cases first: inf, nan, zero, denormal}
  50.   if (Exponent = 0) then begin
  51.     if (L = 0) then begin
  52.       {it's zero}
  53.       Result := Sign + '0.0';
  54.       Exit;
  55.     end;
  56.     {it's a denormal}
  57.     Exponent := -126 - 23;
  58.   end
  59.   else if (Exponent = 255) then begin
  60.     if (L = 0) then begin
  61.       {it's an infinity}
  62.       Result := Sign + 'infinity';
  63.       Exit;
  64.     end;
  65.     {it's a NaN}
  66.     Result := 'NaN';
  67.     Exit;
  68.   end
  69.   else {0 < Exponent < 255} begin
  70.     {it's a normal value}
  71.     L := L or $00800000;
  72.     Exponent := Exponent - 127 - 23;
  73.   end;
  74.  
  75.   {convert the mantissa to ASCII, and thence to our multiprecision
  76.    array for multiplication with a suitable power of 2; the decimal
  77.    point is assumed to be between elements [39] and [40]}
  78.   MantStr := IntToStr(L);
  79.   FillChar(Value, sizeof(Value), 0);
  80.   Inx := RadixPoint;
  81.   for i := length(MantStr) downto 1 do begin
  82.     dec(Inx);
  83.     Value[Inx] := ord(MantStr[i]) - (ord('0'));
  84.   end;
  85.  
  86.   {if the exponent is less than 0, we have to multiply Value by a
  87.    negative power of 2, ie dividing by a power of 2}
  88.   if (Exponent < 0) then begin
  89.     for i := 1 to -Exponent do begin
  90.       for Inx := 0 to 255 do begin
  91.         if Odd(Value[Inx]) then
  92.           inc(Value[Inx+1], 10);
  93.         Value[Inx] := Value[Inx] div 2;
  94.       end;
  95.     end;
  96.   end
  97.  
  98.   {if the exponent is greater than 0, we have to multiply Value by a
  99.    power of 2}
  100.   else if (Exponent > 0) then begin
  101.     for i := 1 to Exponent do begin
  102.       Carry := 0;
  103.       for Inx := 255 downto 0 do begin
  104.         Value[Inx] := Value[Inx] * 2 + Carry;
  105.         if (Value[Inx] < 10) then
  106.           Carry := 0
  107.         else begin
  108.           Carry := 1;
  109.           Value[Inx] := Value[Inx] - 10;
  110.         end;
  111.       end;
  112.     end;
  113.   end;
  114.  
  115.   {we now have our answer in the Value array; find the first and the
  116.    last non-zero digits}
  117.   FirstDigit := 255;
  118.   for Inx := 0 to 255 do
  119.     if (Value[Inx] <> 0) then begin
  120.       FirstDigit := Inx;
  121.       Break;
  122.     end;
  123.  
  124.   LastDigit := 0;
  125.   for Inx := 255 downto 0 do
  126.     if (Value[Inx] <> 0) then begin
  127.       LastDigit := Inx;
  128.       Break;
  129.     end;
  130.  
  131.   {to make sure we include a decimal point, make sure that the first
  132.    digit index is prior to the decimal point, and the last digit index
  133.    is after the decimal point; that way we can show 0.nnn and nnn.0}
  134.   if (FirstDigit >= RadixPoint) then
  135.     FirstDigit := RadixPoint - 1;
  136.   if (LastDigit <= RadixPoint) then
  137.     LastDigit := RadixPoint;
  138.  
  139.   {now convert the digits in the Value array to a string; note that
  140.    the string will have LastDigit - FirstDigit + 1 digits, plus a
  141.    sign, plus a decimal point}
  142.   {$IFDEF Windows}
  143.   Result[0] := char(LastDigit - FirstDigit + 3);
  144.   {$ELSE}
  145.   SetLength(Result, LastDigit - FirstDigit + 3);
  146.   {$ENDIF}
  147.   Result[1] := Sign;
  148.   i := 2;
  149.   for Inx := FirstDigit to LastDigit do begin
  150.     if Inx = RadixPoint then begin
  151.       Result[i] := '.';
  152.       inc(i);
  153.     end;
  154.     Result[i] := char(Value[Inx] + ord('0'));
  155.     inc(i);
  156.   end;
  157. end;
  158.  
  159. const
  160.   LargestSingle = $7F7FFFFF;
  161.   SmallestSingle = $00800000;
  162.   SmallestDenormalSingle = $00000001;
  163.  
  164. procedure TForm1.Button1Click(Sender: TObject);
  165. var
  166.   s : single;
  167.   l : longint absolute s;
  168. begin
  169.   l := SmallestDenormalSingle;
  170.   Label1.Caption := ConvertSingle(s);
  171.   Label2.Caption := FloattoStr(s);
  172.  
  173.   writeln('1         ', ConvertSingle(1.0));
  174.   writeln('12        ', ConvertSingle(12.0));
  175.   writeln('123       ', ConvertSingle(123.0));
  176.   writeln('1234      ', ConvertSingle(1234.0));
  177.   writeln('12345     ', ConvertSingle(12345.0));
  178.   writeln('123456    ', ConvertSingle(123456.0));
  179.   writeln('1234567   ', ConvertSingle(1234567.0));
  180.   writeln('12345678  ', ConvertSingle(12345678.0));
  181.   writeln('123456789 ', ConvertSingle(123456789.0));
  182.   writeln('1/2       ', ConvertSingle(1.0/2.0));
  183.   writeln('1/3       ', ConvertSingle(1.0/3.0));
  184.   writeln('1/4       ', ConvertSingle(1.0/4.0));
  185.   writeln('1/5       ', ConvertSingle(1.0/5.0));
  186. end;
  187.  
  188. end.
  189.