MathgeomGLS
316 строк · 10.6 Кб
1{---------------------------------------------------------------------------}
2{ }
3{ File: Velthuis.FloatUtils.pas }
4{ Function: Routines to extract or set the internals of Delphi's floating }
5{ point types Single, Double and Extended. }
6{ Language: Delphi version XE3 or later }
7{ Author: Rudy Velthuis }
8{ Copyright: (c) 2016 Rudy Velthuis }
9{ }
10{ License: Redistribution and use in source and binary forms, with or }
11{ without modification, are permitted provided that the }
12{ following conditions are met: }
13{ }
14{ * Redistributions of source code must retain the above }
15{ copyright notice, this list of conditions and the following }
16{ disclaimer. }
17{ * Redistributions in binary form must reproduce the above }
18{ copyright notice, this list of conditions and the following }
19{ disclaimer in the documentation and/or other materials }
20{ provided with the distribution. }
21{ }
22{ Disclaimer: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" }
23{ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT }
24{ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND }
25{ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO }
26{ EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE }
27{ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, }
28{ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
29{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, }
30{ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED }
31{ AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT }
32{ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) }
33{ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF }
34{ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. }
35{ }
36{---------------------------------------------------------------------------}
37
38unit Velthuis.FloatUtils;
39
40{ Note: in newer versions of Delphi, most of these functions are superceded by functions in the
41record helpers for floating point types. This unit is made to make provide the
42functions for several older versions as well.
43}
44
45interface
46
47uses
48System.Math;
49
50function IsNegativeInfinity(const AValue: Single): Boolean; overload;
51function IsNegativeInfinity(const AValue: Double): Boolean; overload;
52function IsNegativeInfinity(const AValue: Extended): Boolean; overload;
53
54function IsPositiveInfinity(const AValue: Single): Boolean; overload;
55function IsPositiveInfinity(const AValue: Double): Boolean; overload;
56function IsPositiveInfinity(const AValue: Extended): Boolean; overload;
57
58function GetSignificand(const AValue: Single): UInt32; overload;
59function GetSignificand(const AValue: Double): UInt64; overload;
60function GetSignificand(const AValue: Extended): UInt64; overload;
61function GetMantissa(const AValue: Single): UInt32; overload;
62function GetMantissa(const AValue: Double): UInt64; overload;
63function GetMantissa(const AValue: Extended): UInt64; overload;
64
65function GetExponent(const AValue: Single): Integer; overload;
66function GetExponent(const AValue: Double): Integer; overload;
67function GetExponent(const AValue: Extended): Integer; overload;
68
69function IsDenormal(const AValue: Single): Boolean; overload;
70function IsDenormal(const AValue: Double): Boolean; overload;
71function IsDenormal(const AValue: Extended): Boolean; overload;
72
73function MakeSingle(Sign: TValueSign; Significand: UInt32; Exponent: Integer): Single;
74function MakeDouble(Sign: TValueSign; Significand: UInt64; Exponent: Integer): Double;
75function MakeExtended(Sign: TValueSign; Significand: UInt64; Exponent: Integer): Extended;
76
77type
78PUInt8 = ^UInt8;
79PUInt16 = ^UInt16;
80PUInt32 = ^UInt32;
81PUInt64 = ^UInt64;
82
83PExt80Rec = ^TExt80Rec;
84TExt80Rec = packed record
85Significand: UInt64;
86ExponentAndSign: Word;
87end;
88
89const
90CSingleExponentShift = 23;
91CDoubleExponentShift = 52;
92CSingleExponentMask = $FF;
93CDoubleExponentMask = $7FF;
94CExtendedExponentMask = $7FFF;
95CSingleBias = CSingleExponentMask shr 1;
96CDoubleBias = CDoubleExponentMask shr 1;
97CExtendedBias = CExtendedExponentMask shr 1;
98CSingleSignificandMask = UInt32(1) shl CSingleExponentShift - 1;
99CDoubleSignificandMask = UInt64(1) shl CDoubleExponentShift - 1;
100CSingleSignMask = UInt32(1) shl 31;
101CDoubleSignMask = UInt64(1) shl 63;
102
103implementation
104
105uses
106System.SysUtils;
107
108{$IF CompilerVersion >= 24.0}
109{$LEGACYIFEND ON}
110{$IFEND}
111
112{$POINTERMATH ON}
113
114function GetRawSignificand(const AValue: Single): UInt32; overload; inline;
115begin
116Result := PUInt32(@AValue)^ and CSingleSignificandMask;
117end;
118
119function GetRawSignificand(const AValue: Double): UInt64; overload; inline;
120begin
121Result := PUInt64(@AValue)^ and CDoubleSignificandMask;
122end;
123
124function GetRawExponent(const AValue: Single): Integer; overload; inline;
125begin
126Result := PUInt32(@AValue)^ shr CSingleExponentShift and CSingleExponentMask;
127end;
128
129function GetRawExponent(const AValue: Double): Integer; overload; inline;
130begin
131Result := PUInt16(@AValue)[3] shr 4 and CDoubleExponentMask;
132end;
133
134function GetRawExponent(const AValue: Extended): Integer; overload; inline;
135begin
136Result := PUInt16(@AValue)[4] and CExtendedExponentMask;
137end;
138
139function IsNegativeInfinity(const AValue: Single): Boolean; overload;
140begin
141Result := System.Math.IsInfinite(AValue) and (System.Math.Sign(AValue) < 0);
142end;
143
144function IsNegativeInfinity(const AValue: Double): Boolean; overload;
145begin
146Result := System.Math.IsInfinite(AValue) and (Sign(AValue) < 0);
147end;
148
149function IsNegativeInfinity(const AValue: Extended): Boolean; overload;
150begin
151Result := System.Math.IsInfinite(AValue) and (Sign(AValue) < 0);
152end;
153
154function IsPositiveInfinity(const AValue: Single): Boolean; overload;
155begin
156Result := System.Math.IsInfinite(AValue) and (Sign(AValue) > 0);
157end;
158
159function IsPositiveInfinity(const AValue: Double): Boolean; overload;
160begin
161Result := System.Math.IsInfinite(AValue) and (Sign(AValue) > 0);
162end;
163
164function IsPositiveInfinity(const AValue: Extended): Boolean; overload;
165begin
166Result := System.Math.IsInfinite(AValue) and (Sign(AValue) > 0);
167end;
168
169function GetSignificand(const AValue: Single): UInt32; overload;
170var
171E: Integer;
172begin
173E := GetRawExponent(AValue);
174Result := GetRawSignificand(AValue);
175if (0 < E) and (E < CSingleExponentMask) then
176Result := Result or (UInt32(1) shl CSingleExponentShift);
177end;
178
179function GetSignificand(const AValue: Double): UInt64; overload;
180var
181E: Integer;
182begin
183E := GetRawExponent(AValue);
184Result := GetRawSignificand(AValue);
185if (0 < E) and (E < CDoubleExponentMask) then
186Result := Result or ((UInt64(1) shl CDoubleExponentShift));
187end;
188
189function GetSignificand(const AValue: Extended): UInt64; overload;
190begin
191Result := PUInt64(@AValue)^;
192end;
193
194function GetMantissa(const AValue: Single): UInt32; overload;
195begin
196Result := GetSignificand(AValue);
197end;
198
199function GetMantissa(const AValue: Double): UInt64; overload;
200begin
201Result := GetSignificand(AValue);
202end;
203
204function GetMantissa(const AValue: Extended): UInt64; overload;
205begin
206Result := GetSignificand(AValue);
207end;
208
209function GetExponent(const AValue: Single): Integer; overload;
210var
211M: UInt32;
212E: Int32;
213begin
214M := GetRawSignificand(AValue);
215E := GetRawExponent(AValue);
216if (0 < E) and (E < CSingleExponentMask) then
217Result := E - CSingleBias
218else if E = 0 then
219if M = 0 then
220// +/- Zero
221Result := 0
222else
223// Denormal
224Result := 1 - CSingleBias
225else
226// NaN or +/-Infinity
227Result := 0;
228end;
229
230function GetExponent(const AValue: Double): Integer; overload;
231var
232M: UInt64;
233E: Int32;
234begin
235M := GetRawSignificand(AValue);
236E := GetRawExponent(AValue);
237if (0 < E) and (E < CDoubleExponentMask) then
238Result := E - CDoubleBias
239else if E = 0 then
240if M = 0 then
241// +/-Zero
242Result := 0
243else
244// Denormal
245Result := 1 - CDoubleBias
246else
247// NaN or +/-Infinity
248Result := 0;
249end;
250
251function GetExponent(const AValue: Extended): Integer; overload;
252var
253M: UInt64;
254E: Int32;
255begin
256M := PUInt64(@AValue)^;
257E := GetRawExponent(AValue);
258if (0 < E) and (E < CExtendedExponentMask) then
259Result := E - CExtendedBias
260else if E = 0 then
261if M = 0 then
262// +/- Zero
263Result := 0
264else
265// Denormal
266Result := 1 - CExtendedBias
267else
268// NaN or +/-Infinity
269Result := 0;
270end;
271
272function IsDenormal(const AValue: Single): Boolean; overload;
273begin
274Result := ((PUInt32(@AValue)^ shr CSingleExponentShift and CSingleExponentMask) = 0) and (GetSignificand(AValue) <> 0);
275end;
276
277function IsDenormal(const AValue: Double): Boolean; overload;
278begin
279Result := ((PUInt64(@AValue)^ shr 52) = 0) and (GetSignificand(AValue) <> 0);
280end;
281
282function IsDenormal(const AValue: Extended): Boolean; overload;
283begin
284Result := ((PUInt16(@AValue)[4] and $7FFF) = 0) and (GetSignificand(AValue) <> 0);
285end;
286
287function MakeSingle(Sign: TValueSign; Significand: UInt32; Exponent: Integer): Single;
288var
289U: UInt32;
290begin
291U := (Sign and CSingleSignMask) or
292((UInt32(Exponent + CSingleBias) and CSingleExponentMask) shl CSingleExponentShift) or
293(Significand and CSingleSignificandMask);
294PUInt32(@Result)^ := U;
295end;
296
297function MakeDouble(Sign: TValueSign; Significand: UInt64; Exponent: Integer): Double;
298var
299U: UInt64;
300begin
301U := UInt64(Int64(Sign) and CDoubleSignMask) or
302(UInt64((Exponent + CDoubleBias) and CDoubleExponentMask) shl CDoubleExponentShift) or
303(Significand and CDoubleSignificandMask);
304PUInt64(@Result)^ := U;
305end;
306
307function MakeExtended(Sign: TValueSign; Significand: UInt64; Exponent: Integer): Extended;
308var
309E: TExt80Rec;
310begin
311E.Significand := Significand;
312E.ExponentAndSign := (Sign and $8000) or ((Exponent + CExtendedBias) and CExtendedExponentMask);
313PExt80Rec(@Result)^ := E;
314end;
315
316end.
317
318