home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 8 / CDASC08.ISO / NEWS / 552 / GSOB_FLP.PAS < prev    next >
Pascal/Delphi Source File  |  1993-10-07  |  16KB  |  499 lines

  1. unit GSOB_FlP;
  2. {------------------------------------------------------------------------------
  3.                            Floating Point Formatting
  4.  
  5.        GSOB_FLP Copyright (c)  Richard F. Griffin
  6.  
  7.        11 August 1992
  8.  
  9.        102 Molded Stone Pl
  10.        Warner Robins, GA  31088
  11.  
  12.        -------------------------------------------------------------
  13.        This unit handles the routines to create and compare floating
  14.        point types used in dBase indexes.  These routines save 10K of
  15.        memory over the $N,E option for numeric coprocessor emulation.
  16.        Note that no math or number to string conversion is required.
  17.        This allows for a far smaller unit.
  18.  
  19.        dBase III indexes use type double to store all numeric and date
  20.        field keys.
  21.  
  22.        dBase IV .MDX indexes use type double to store date fields.  A
  23.        BCD storage type is used to store Number and Float types.
  24.  
  25.        These routines will create both types for insertion into an index.
  26.        Comparison routines are also included to allow searches of indexes.
  27.  
  28.        changes:
  29.  
  30. ------------------------------------------------------------------------------}
  31. {$O+}
  32.  
  33. interface
  34.  
  35. type
  36.  
  37. {-----------------------------------------------------------------------------
  38.    gsDouble type simulates IEEE double precision type.
  39.    Memory layout is:
  40.  
  41.                                  gsDouble Bytes
  42.         ┌────────┬────────┬────────┬───┴────┬────────┬────────┬───────────┐
  43.        [7]      [6]      [5]      [4]      [3]      [2]      [1]      [0]
  44.     76543210 76543210 76543210 76543210 76543210 76543210 76543210 76543210
  45.     seeeeeee│eeeemmmm│mmmmmmmm│mmmmmmmm│mmmmmmmm│mmmmmmmm│mmmmmmmm│mmmmmmmm
  46.     │└┴┴┴┴┴┴─┴┴┴┘└┴┴┴─┴┴┴┴┴┴┴┴─┴┴┴┴┴┴┴┴─┴┴┴┴┴┴┴┴─┴┴┴┴┴┴┴┴─┴┴┴┴┴┴┴┴─┴┴┴┴┴┴┴┘
  47.     │  Exponent                        Mantissa
  48.     └─ Sign
  49.  
  50.     Note the value is stored opposite from its representation; that is, the
  51.     sign/(MSB exponent) byte is stored in gsDouble[7].  The next byte, with
  52.     the (LSB exponent)/ (MSB Mantissa) is gsDouble[6]; and so on.....
  53.  
  54. -----------------------------------------------------------------------------}
  55.  
  56.    gsDouble    = array[0..7] of byte;
  57.  
  58. {-----------------------------------------------------------------------------
  59.    gsFltBCD type simulates the type used by dBase IV to store .MDX numeric
  60.    values.  This routine uses 'best guess' estimates of how the field is
  61.    computed.  There are some inconsistencies.  For example, gsFltBCD[1]
  62.    contains the sign and number of used bits, but does not follow a logical
  63.    pattern since whole numbers with less than 6 digits show 41 bits used.
  64.    All other cases show actual bits used.
  65.  
  66.    Memory layout is:
  67.  
  68.                                  gsFltBCD Bytes
  69.         ┌────────┬───────┬───────┬───┴───┬───────┬───────┬────......────┐
  70.        [0]      [1]     [2]     [3]     [4]     [5]     [6]           [11]
  71.     76543210 76543210 7-4 3-0 7-4 3-0 7-4 3-0 7-4 3-0 7-4 3-0        7-4 3-0
  72.     pppppppp│seeeeeee│d00 d01│d02 d03│d04 d05│d06 d07│d08 d09│......│d19 d20│
  73.     └┴┴┼┴┴┴┘ │└┴┴┼┴┴┘ └┴┴─┴┴┴─┴┴┴─┴┴┴─┴┴┴┬┴┴┴─┴┴┴─┴┴┴─┴┴┴─┴┴┴─......─┴┴┴─┴┴┘
  74.     Digits   │   └───┐               BCD Digits
  75.     Left of  └ Sign  └ BCD Digits
  76.     Decimal            Used.  (In
  77.     ($34 = 0)          Bits (BCD
  78.                        digits * 4)
  79.                        + 1 for sign
  80.  
  81. -----------------------------------------------------------------------------}
  82.  
  83.    gsFltBCD    = array[0..11] of byte;
  84.  
  85. function CmprDouble(var val1, val2) : integer;
  86. function CmprFltBCD(var val1, val2) : integer;
  87. procedure MakeDouble(C_String: string;var dtype: gsDouble;var rcode : word);
  88. procedure MakeFltBCD(C_String: string;var btype: gsFltBCD;var rcode : word);
  89. function CnvrtDouble(var dtype) : string;
  90.  
  91. implementation
  92.  
  93. const
  94.    MaxNibble     = 64;
  95.    MaxBcdNibble  = 20;
  96.    EndNibble     = 63;
  97.  
  98. var
  99.    Index         : integer;
  100.    DecPlaces     : integer;
  101.    TotPlaces     : integer;
  102.    RndgFlag      : boolean;
  103.    InDecimals    : boolean;
  104.    InExponent    : boolean;
  105.    PositiveNum   : boolean;
  106.    PositiveExp   : boolean;
  107.  
  108.    Mantissa      : array[0..MaxNibble] of byte;
  109.    Exponent      : array[1..3] of byte;
  110.    DecExponent   : integer;
  111.  
  112.    BinExponent   : word;
  113.    GrtrZero      : boolean;
  114.    DumpBit       : byte;
  115.  
  116.    rmdr,
  117.    LSp,
  118.    i             : integer;
  119.  
  120.    DblAry        : array[1..16] of byte;
  121.    DblWrk        : gsDouble;
  122.  
  123.    BCDWrk        : gsFltBCD;
  124.  
  125. function CmprDouble(var val1, val2) : integer;
  126. var
  127.    v1       : gsDouble absolute val1;
  128.    v2       : gsDouble absolute val2;
  129.    val1neg,
  130.    val2neg  : boolean;
  131.    flg      : boolean;
  132.    rslt     : integer;
  133.    loop     : integer;
  134. begin
  135.    val1neg := v1[7] > 127;
  136.    val2neg := v2[7] > 127;
  137.    flg := val1neg = val2neg;
  138.    if not flg then
  139.    begin
  140.       if val1neg then CmprDouble := -1 else CmprDouble := 1;
  141.       exit;
  142.    end;
  143.    loop := 7;
  144.    rslt := 0;
  145.    while (rslt = 0) and (loop >= 0) do
  146.    begin
  147.       if v1[loop] < v2[loop] then rslt := -1
  148.          else if v1[loop] > v2[loop] then rslt := 1;
  149.       loop:= loop-1;
  150.    end;
  151.    if val1neg then rslt := rslt*(-1);
  152.    CmprDouble := rslt;
  153. end;
  154.  
  155. function CmprFltBCD(var val1, val2) : integer;
  156. var
  157.    v1       : gsFltBcd absolute val1;
  158.    v2       : gsFltBcd absolute val2;
  159.    val1neg,
  160.    val2neg  : boolean;
  161.    flg      : boolean;
  162.    rslt     : integer;
  163.    loop     : integer;
  164. begin
  165.    val1neg := v1[1] > 127;
  166.    val2neg := v2[1] > 127;
  167.    flg := val1neg = val2neg;
  168.    if not flg then
  169.    begin
  170.       if val1neg then CmprFltBCD := -1 else CmprFltBCD := 1;
  171.       exit;
  172.    end;
  173.    rslt := 0;
  174.    if v1[0] < v2[0] then rslt := -1
  175.       else if v1[0] > v2[0] then rslt := 1;
  176.    loop := 11;
  177.    while (rslt = 0) and (loop >= 2) do
  178.    begin
  179.       if v1[loop] < v2[loop] then rslt := -1
  180.          else if v1[loop] > v2[loop] then rslt := 1;
  181.       loop:= loop-1;
  182.    end;
  183.    if val1neg then rslt := rslt*(-1);
  184.    CmprFltBCD := rslt;
  185. end;
  186.  
  187. procedure MakeDouble(C_String: string;var dtype: gsDouble;var rcode : word);
  188.  
  189.    procedure AdjustMantissa;
  190.    begin
  191.       if DecExponent < 0 then
  192.       begin
  193.          while DecExponent < 0 do
  194.          begin
  195.             while Mantissa[1] = 0 do
  196.             begin
  197.                move(Mantissa[2], Mantissa[1], EndNibble);
  198.                dec(BinExponent,4);
  199.             end;
  200.             for i := 1 to pred(EndNibble) do
  201.             begin
  202.                Mantissa[succ(i)] := Mantissa[succ(i)] +
  203.                                     ((Mantissa[i] mod 10) * 16);
  204.                Mantissa[i] := Mantissa[i] div 10;
  205.             end;
  206.             Mantissa[EndNibble] := Mantissa[EndNibble] div 10;
  207.             inc(DecExponent);
  208.          end;
  209.       end
  210.       else
  211.                          {test for exponent > 0}
  212.          if DecExponent > 0 then
  213.          begin
  214.             while DecExponent > 0 do
  215.             begin
  216.                if Mantissa[1] <> 0 then
  217.                begin
  218.                   rmdr := Mantissa[EndNibble];
  219.                   move(Mantissa[1], Mantissa[2], pred(EndNibble));
  220.                   Mantissa[1] := 0;
  221.                   inc(BinExponent,4);
  222.                   if rmdr > 7 then
  223.                   begin
  224.                      inc(Mantissa[EndNibble]);
  225.                      i := EndNibble;
  226.                      while Mantissa[i] > 15 do
  227.                      begin
  228.                         Mantissa[i] := Mantissa[i] and $0F;
  229.                         dec(i);
  230.                         inc(Mantissa[i]);
  231.                      end;
  232.                   end;
  233.                end;
  234.                Mantissa[EndNibble] :=  (Mantissa[EndNibble] * 10);
  235.                for i := pred(EndNibble) downto 1 do
  236.                begin
  237.                   Mantissa[i] := (Mantissa[i] * 10) +
  238.                                  (Mantissa[succ(i)] shr 4);
  239.                   Mantissa[succ(i)] :=
  240.                                   Mantissa[succ(i)] and $0F;
  241.                end;
  242.                dec(DecExponent);
  243.             end;
  244.          end;
  245.    end;
  246.  
  247.  
  248.  
  249. begin
  250.    rcode := 0;
  251.    PositiveNum := true;
  252.    PositiveExp := true;
  253.    DecPlaces := 0;
  254.    DecExponent := 0;
  255.    RndgFlag  := true;
  256.    InDecimals := false;
  257.    InExponent := false;
  258.    FillChar(Mantissa,MaxNibble+1,#0);
  259.    FillChar(Exponent,3,#0);
  260.    if C_String <> '' then
  261.    begin
  262.       LSp := 1;
  263.       while (C_String[LSp] = ' ') and (LSp <= ord(C_String[0])) do
  264.          LSp := LSp+1;
  265.       for Index := LSp to length(C_String) do
  266.       begin
  267.          case C_String[Index] of
  268.  
  269.          '+'      : if InDecimals then PositiveExp := true
  270.                        else PositiveNum := true;
  271.  
  272.          '-'      : if InExponent then PositiveExp := false
  273.                        else PositiveNum := false;
  274.  
  275.          '0'..'9' : begin
  276.                        if InDecimals then inc(DecPlaces);
  277.                        if InExponent then
  278.                        begin
  279.                           DecExponent := (DecExponent * 10) +
  280.                                          byte(C_String[Index]) and $0F;
  281.                        end
  282.                        else
  283.                        begin
  284.                           if Mantissa[1] = 0 then
  285.                           begin
  286.                              Mantissa[EndNibble] :=
  287.                                              (Mantissa[EndNibble] * 10) +
  288.                                              (byte(C_String[Index]) and $0F);
  289.                              for i := pred(EndNibble) downto 1 do
  290.                              begin
  291.                                 Mantissa[i] := (Mantissa[i] * 10) +
  292.                                                (Mantissa[succ(i)] shr 4);
  293.                                 Mantissa[succ(i)] :=
  294.                                                 Mantissa[succ(i)] and $0F;
  295.                              end;
  296.                           end
  297.                           else
  298.                           begin
  299.                              if RndgFlag then
  300.                              begin
  301.                                 RndgFlag := false;
  302.                                 if C_String[Index] > '4' then
  303.                                                      inc(Mantissa[EndNibble]);
  304.                              end;
  305.                              if not InDecimals then dec(DecPlaces);
  306.                           end;
  307.                        end;
  308.                     end;
  309.  
  310.  
  311.          '.'      : InDecimals := true;
  312.  
  313.          'e',
  314.          'E'      : begin
  315.                        InExponent := true;
  316.                        InDecimals := false;
  317.                     end;
  318.  
  319.          else       begin
  320.                        rcode := Index;
  321.                     end;
  322.          end;
  323.       end;
  324.  
  325.       if not PositiveExp then DecExponent := DecExponent * -1;
  326.       DecExponent := DecExponent - DecPlaces;
  327.  
  328.       GrtrZero := false;
  329.       for i := 1 to EndNibble do if Mantissa[i] > 0 then GrtrZero := true;
  330.  
  331.       if GrtrZero then
  332.       begin
  333.  
  334.          BinExponent := EndNibble*4;
  335.          AdjustMantissa;
  336.          while Mantissa[1] = 0 do
  337.          begin
  338.             move(Mantissa[2], Mantissa[1], EndNibble);
  339.             dec(BinExponent,4);
  340.          end;
  341.  
  342.  
  343.          DumpBit := 0;
  344.          while DumpBit = 0 do
  345.          begin
  346.             dec(BinExponent);
  347.             for i := 1 to EndNibble do Mantissa[i] := Mantissa[i] shl 1;
  348.             DumpBit := Mantissa[1] and $10;
  349.             for i := 1 to EndNibble do
  350.             begin
  351.                if Mantissa[succ(i)] > 15 then inc(Mantissa[i]);
  352.                Mantissa[i] := Mantissa[i] and $0F;
  353.             end;
  354.          end;
  355.  
  356.          if Mantissa[14] > 7 then
  357.          begin
  358.             inc(Mantissa[13]);
  359.             i := 13;
  360.             while (Mantissa[i] > 15) and (i > 0) do
  361.             begin
  362.                Mantissa[i] := Mantissa[i] and $0F;
  363.                dec(i);
  364.                inc(Mantissa[i]);
  365.             end;
  366.          end;
  367.  
  368.          BinExponent := BinExponent + 1023;
  369.          for i := 3 downto 1 do
  370.          begin
  371.             Exponent[i] := BinExponent and $000F;
  372.             BinExponent := BinExponent shr 4;
  373.          end;
  374.  
  375.       end;
  376.       if not PositiveNum then Exponent[1] := Exponent[1] or $08;
  377.    end;
  378.  
  379.    DblWrk[7] := (Exponent[1] shl 4) + Exponent[2];
  380.    DblWrk[6] := (Exponent[3] shl 4) + Mantissa[1];
  381.    DblWrk[5] := (Mantissa[2] shl 4) + Mantissa[3];
  382.    DblWrk[4] := (Mantissa[4] shl 4) + Mantissa[5];
  383.    DblWrk[3] := (Mantissa[6] shl 4) + Mantissa[7];
  384.    DblWrk[2] := (Mantissa[8] shl 4) + Mantissa[9];
  385.    DblWrk[1] := (Mantissa[10] shl 4) + Mantissa[11];
  386.    DblWrk[0] := (Mantissa[12] shl 4) + Mantissa[13];
  387.    dtype := DblWrk;
  388. end;
  389.  
  390.  
  391.  
  392. procedure MakeFltBCD(C_String: string;var btype: gsFltBCD;var rcode : word);
  393. begin
  394.    rcode := 0;
  395.    PositiveNum := true;
  396.    PositiveExp := true;
  397.    DecPlaces := 0;
  398.    TotPlaces := 0;
  399.    DecExponent := 0;
  400.    InDecimals := false;
  401.    InExponent := false;
  402.    FillChar(Mantissa,MaxBCDNibble+1,#0);
  403.    if C_String <> '' then
  404.    begin
  405.       LSp := 1;
  406.       while (C_String[LSp] = ' ') and (LSp <= ord(C_String[0])) do
  407.          LSp := LSp+1;
  408.       for Index := LSp to length(C_String) do
  409.       begin
  410.          case C_String[Index] of
  411.  
  412.          '+'      : if InDecimals then PositiveExp := true
  413.                        else PositiveNum := true;
  414.  
  415.          '-'      : if InExponent then PositiveExp := false
  416.                        else PositiveNum := false;
  417.  
  418.          '0'..'9' : begin
  419.                        if InDecimals then inc(DecPlaces);
  420.                        if InExponent then
  421.                        begin
  422.                           DecExponent := (DecExponent * 10) +
  423.                                          byte(C_String[Index]) and $0F;
  424.                        end
  425.                        else
  426.                        begin
  427.                           Mantissa[TotPlaces] := byte(C_String[Index]) and $0F;
  428.                           inc(TotPlaces);
  429.                        end;
  430.                     end;
  431.  
  432.          '.'      : InDecimals := true;
  433.  
  434.          'e',
  435.          'E'      : begin
  436.                        InExponent := true;
  437.                        InDecimals := false;
  438.                     end;
  439.  
  440.          else       begin
  441.                        rcode := Index;
  442.                     end;
  443.          end;
  444.       end;
  445.  
  446.       if not PositiveExp then DecExponent := DecExponent * -1;
  447.       DecExponent := DecExponent - (TotPlaces - DecPlaces);
  448.  
  449.       GrtrZero := false;
  450.       for i := 0 to MaxNibble-1 do if Mantissa[i] > 0 then GrtrZero := true;
  451.  
  452.       if not GrtrZero then
  453.       begin
  454.          TotPlaces := 0;
  455.          DecExponent := 0;
  456.       end;
  457.       TotPlaces := TotPlaces * 4;
  458.       if not PositiveNum then TotPlaces := TotPlaces or $80;
  459.    end;
  460.  
  461.    BCDWrk[0] := DecExponent + $34;
  462.    BCDWrk[1] := TotPlaces + 1;
  463.    for i := 0 to 9 do
  464.       BCDWrk[i+2] := (Mantissa[i*2] shl 4) + Mantissa[(i*2)+1];
  465.    btype := BCDWrk;
  466. end;
  467.  
  468. function CnvrtDouble(var dtype) : string;
  469. var
  470.    dbl_in : gsDouble absolute dtype;
  471.    rnum   : real;
  472.    rpsudo : array[0..5] of byte absolute rnum;
  473.    st     : string;
  474. begin
  475.    PositiveNum := dbl_in[7] < $80;
  476.    Exponent[1] := (dbl_in[7] shr 4) and $07;
  477.    Exponent[2] := dbl_in[7] and $0F;
  478.    Exponent[3] := (dbl_in[6] shr 4) and $0F;
  479.    BinExponent := 0;
  480.    for i := 1 to 3 do
  481.       BinExponent := (BinExponent shl 4) or Exponent[i];
  482.    BinExponent := BinExponent - 1023;
  483.    rpsudo[0] := BinExponent + 129;
  484.    rpsudo[5] := (dbl_in[6] shl 3) and $78;
  485.    rpsudo[5] := (dbl_in[5] shr 5) or rpsudo[5];
  486.    if not PositiveNum then rpsudo[5] := rpsudo[5] or $80;
  487.    rpsudo[4] := (dbl_in[5] shl 3);
  488.    rpsudo[4] := (dbl_in[4] shr 5) or rpsudo[4];
  489.    rpsudo[3] := (dbl_in[4] shl 3);
  490.    rpsudo[3] := (dbl_in[3] shr 5) or rpsudo[3];
  491.    rpsudo[2] := (dbl_in[3] shl 3);
  492.    rpsudo[2] := (dbl_in[2] shr 5) or rpsudo[2];
  493.    rpsudo[1] := (dbl_in[2] shl 3);
  494.    rpsudo[1] := (dbl_in[1] shr 5) or rpsudo[1];
  495.    str(rnum,st);
  496.    CnvrtDouble := st;
  497. end;
  498.  
  499. end.