Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/RTL/Delphi/Math Unit    [ Add a report in this area ]  
Report #:  36965   Status: Closed
Inexact floating-point constants in Math
Project:  Delphi Build #:  7.0.8.1
Version:    7.0 Submitted By:   Gerd Thieme
Report Type:  Minor failure / Design problem Date Reported:  11/24/2006 5:24:22 AM
Severity:    Extreme corner case Last Updated: 3/20/2012 2:24:39 AM
Platform:    All platforms Internal Tracking #:   243354
Resolution: Fixed (Resolution Comments) Resolved in Build: : 16.0.4077.37232
Duplicate of:  None
Voting and Rating
Overall Rating: (5 Total Ratings)
5.00 out of 5
Total Votes: None
Description
One should expect that definitions

    const   { Ranges of the IEEE floating point types, including denormals }
      MinSingle   =  1.5e-45;
      MaxSingle   =  3.4e+38;
      MinDouble   =  5.0e-324;
      MaxDouble   =  1.7e+308;
      MinExtended =  3.4e-4932;
      MaxExtended =  1.1e+4932;

just from the beginning of unit Math would ensure that any finite, positive Single value would fall in range MinSingle through MaxSingle, and same for types Double and Extended.

See Details on how to get numbers smaller than the pretended minimums and larger than the maximums shown above.

Of course, there is a gigantic number of other floating point values that fall outside unit Math's Min-Max ranges. My examples just show the most extreme ones, i.e., these are the actual minimums and maximums.

Since floating-point constants in Delphi always are Extended, the definitions for Single and Double values need 20 significant digits (not just 6, 14, or 18) in order to get the exact Extended equivalent of the extreme Single and Double values. In a typed constant definition one could do with fewer digits. However, typed constants are no constant expressions to the compiler.
Steps to Reproduce:
program FloatConstBug;

uses Math;

  const          // decimal approximations                 // exact values

    SmallSingle   = 1.4012984643248170709e-45;             // 2^(-149)
    LargeSingle   = 3.402823466385288598e38 + 1e19;        // 2^128 - 2^104
    SmallDouble   = 4.9406564584124654418e-324;            // 2^(-1074)
    LargeDouble   = 1.79769313486231570815e308;            // 2^1024 - 2^971
    SmallExtended = 4e-4951;                               // 2^(-16445)
    LargeExtended = 1.18973149535723e4932 + 176502e4912;   // 2^16384 - 2^16320
    
begin
  Randomize;                                    // let's play Russian roulette
  case Random (6) of                            // (unfortunately 6 bullets have been loaded)
    0: assert (MinSingle   <= SmallSingle);     // fails
    1: assert (MaxSingle   >= LargeSingle);     // fails
    2: assert (MinDouble   <= SmallDouble);     // fails
    3: assert (MaxDouble   >= LargeDouble);     // fails
    4: assert (MinExtended <= SmallExtended);   // fails
    5: assert (MaxExtended >= LargeExtended);   // fails
  end;
end.
Workarounds
// Define your own constants as a replacement for the incorrect Math values.
// Delphi's careless decimal-to-floating point conversion requires splitting
// some of these constants in two parts to get the exact binary values.

  const        // decimal approximations                 // exact values

    MinSingle   = 1.4012984643248170709e-45;             // 2^(-149)
    MaxSingle   = 3.402823466385288598e38 + 1e19;        // 2^128 - 2^104
    MinDouble   = 4.9406564584124654418e-324;            // 2^(-1074)
    MaxDouble   = 1.79769313486231570815e308;            // 2^1024 - 2^971
    MinExtended = 4e-4951;                               // 2^(-16445)
    MaxExtended = 1.18973149535723e4932 + 176502e4912;   // 2^16384 - 2^16320
Attachment
None
Comments

None

Server Response from: ETNACODE01