5 // Miguel de Icaza (miguel@ximian.com)
6 // Bob Smith (bob@thestuff.net)
8 // (C) Ximian, Inc. http://www.ximian.com
9 // (C) Bob Smith. http://www.thestuff.net
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System
.Globalization
;
36 using System
.Runtime
.CompilerServices
;
41 public struct Double
: IComparable
, IFormattable
, IConvertible
{
42 public const double Epsilon
= 4.9406564584124650e-324;
43 public const double MaxValue
= 1.7976931348623157e308
;
44 public const double MinValue
= -1.7976931348623157e308
;
45 public const double NaN
= 0.0d
/ 0.0d
;
46 public const double NegativeInfinity
= -1.0d
/ 0.0d
;
47 public const double PositiveInfinity
= 1.0d
/ 0.0d
;
49 internal double m_value
;
51 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
52 extern internal static void AssertEndianity (out double value);
54 public int CompareTo (object v
)
59 if (!(v
is System
.Double
))
60 throw new ArgumentException (Locale
.GetText ("Value is not a System.Double"));
62 double dv
= (double)v
;
64 if (IsPositiveInfinity(m_value
) && IsPositiveInfinity(dv
))
67 if (IsNegativeInfinity(m_value
) && IsNegativeInfinity(dv
))
82 if (m_value
> dv
) return 1;
83 else if (m_value
< dv
) return -1;
87 public override bool Equals (object o
)
89 if (!(o
is System
.Double
))
92 if (IsNaN ((double)o
)) {
99 return ((double) o
) == m_value
;
102 public override unsafe int GetHashCode ()
105 return (*((long*)&d
)).GetHashCode ();
108 public static bool IsInfinity (double d
)
110 return (d
== PositiveInfinity
|| d
== NegativeInfinity
);
113 public static bool IsNaN (double d
)
118 public static bool IsNegativeInfinity (double d
)
120 return (d
< 0.0d
&& (d
== NegativeInfinity
|| d
== PositiveInfinity
));
123 public static bool IsPositiveInfinity (double d
)
125 return (d
> 0.0d
&& (d
== NegativeInfinity
|| d
== PositiveInfinity
));
128 public static double Parse (string s
)
130 return Parse (s
, (NumberStyles
.Float
| NumberStyles
.AllowThousands
), null);
133 public static double Parse (string s
, IFormatProvider fp
)
135 return Parse (s
, (NumberStyles
.Float
| NumberStyles
.AllowThousands
), fp
);
138 public static double Parse (string s
, NumberStyles style
)
140 return Parse (s
, style
, null);
143 // We're intentionally using constants here to avoid some bigger headaches in mcs.
144 // This struct must be compiled before System.Enum so we can't use enums here.
145 private const int State_AllowSign
= 1;
146 private const int State_Digits
= 2;
147 private const int State_Decimal
= 3;
148 private const int State_ExponentSign
= 4;
149 private const int State_Exponent
= 5;
150 private const int State_ConsumeWhiteSpace
= 6;
152 [MonoTODO("check if digits are group in correct numbers between the group separators")]
153 public static double Parse (string s
, NumberStyles style
, IFormatProvider provider
)
155 if (s
== null) throw new ArgumentNullException();
156 if (style
> NumberStyles
.Any
)
158 throw new ArgumentException();
160 NumberFormatInfo format
= NumberFormatInfo
.GetInstance(provider
);
161 if (format
== null) throw new Exception("How did this happen?");
162 if (s
== format
.NaNSymbol
) return Double
.NaN
;
163 if (s
== format
.PositiveInfinitySymbol
) return Double
.PositiveInfinity
;
164 if (s
== format
.NegativeInfinitySymbol
) return Double
.NegativeInfinity
;
167 // validate and prepare string for C
170 byte [] b
= new byte [len
+ 1];
175 if ((style
& NumberStyles
.AllowLeadingWhite
) != 0){
176 while (sidx
< len
&& Char
.IsWhiteSpace (c
= s
[sidx
]))
180 throw new FormatException();
183 bool allow_trailing_white
= ((style
& NumberStyles
.AllowTrailingWhite
) != 0);
188 int state
= State_AllowSign
;
193 string decimal_separator
= null;
194 string group_separator
= null;
195 int decimal_separator_len
= 0;
196 int group_separator_len
= 0;
197 if ((style
& NumberStyles
.AllowDecimalPoint
) != 0){
198 decimal_separator
= format
.NumberDecimalSeparator
;
199 decimal_separator_len
= decimal_separator
.Length
;
201 if ((style
& NumberStyles
.AllowThousands
) != 0){
202 group_separator
= format
.NumberGroupSeparator
;
203 group_separator_len
= group_separator
.Length
;
205 string positive
= format
.PositiveSign
;
206 string negative
= format
.NegativeSign
;
208 for (; sidx
< len
; sidx
++){
216 case State_AllowSign
:
217 if ((style
& NumberStyles
.AllowLeadingSign
) != 0){
218 if (c
== positive
[0] &&
219 s
.Substring (sidx
, positive
.Length
) == positive
){
220 state
= State_Digits
;
221 sidx
+= positive
.Length
-1;
225 if (c
== negative
[0] &&
226 s
.Substring (sidx
, negative
.Length
) == negative
){
227 state
= State_Digits
;
228 b
[didx
++] = (byte) '-';
229 sidx
+= negative
.Length
-1;
233 state
= State_Digits
;
234 goto case State_Digits
;
237 if (Char
.IsDigit (c
)){
238 b
[didx
++] = (byte) c
;
241 if (c
== 'e' || c
== 'E')
242 goto case State_Decimal
;
244 if (decimal_separator
!= null &&
245 decimal_separator
[0] == c
){
246 if (s
.Substring (sidx
, decimal_separator_len
) ==
248 b
[didx
++] = (byte) '.';
249 sidx
+= decimal_separator_len
-1;
250 state
= State_Decimal
;
254 if (group_separator
!= null &&
255 group_separator
[0] == c
){
256 if (s
.Substring (sidx
, group_separator_len
) ==
258 sidx
+= group_separator_len
-1;
259 state
= State_Digits
;
264 if (Char
.IsWhiteSpace (c
))
265 goto case State_ConsumeWhiteSpace
;
267 throw new FormatException ("Unknown char: " + c
);
270 if (Char
.IsDigit (c
)){
271 b
[didx
++] = (byte) c
;
275 if (c
== 'e' || c
== 'E'){
276 if ((style
& NumberStyles
.AllowExponent
) == 0)
277 throw new FormatException ("Unknown char: " + c
);
278 b
[didx
++] = (byte) c
;
279 state
= State_ExponentSign
;
283 if (Char
.IsWhiteSpace (c
))
284 goto case State_ConsumeWhiteSpace
;
285 throw new FormatException ("Unknown char: " + c
);
287 case State_ExponentSign
:
288 if (Char
.IsDigit (c
)){
289 state
= State_Exponent
;
290 goto case State_Exponent
;
293 if (c
== positive
[0] &&
294 s
.Substring (sidx
, positive
.Length
) == positive
){
295 state
= State_Digits
;
296 sidx
+= positive
.Length
-1;
300 if (c
== negative
[0] &&
301 s
.Substring (sidx
, negative
.Length
) == negative
){
302 state
= State_Digits
;
303 b
[didx
++] = (byte) '-';
304 sidx
+= negative
.Length
-1;
308 if (Char
.IsWhiteSpace (c
))
309 goto case State_ConsumeWhiteSpace
;
311 throw new FormatException ("Unknown char: " + c
);
314 if (Char
.IsDigit (c
)){
315 b
[didx
++] = (byte) c
;
319 if (Char
.IsWhiteSpace (c
))
320 goto case State_ConsumeWhiteSpace
;
321 throw new FormatException ("Unknown char: " + c
);
323 case State_ConsumeWhiteSpace
:
324 if (allow_trailing_white
&& Char
.IsWhiteSpace (c
))
326 throw new FormatException ("Unknown char");
332 fixed (byte *p
= &b
[0]){
333 double retVal
= ParseImpl (p
);
334 if (IsPositiveInfinity(retVal
) || IsNegativeInfinity(retVal
))
335 throw new OverflowException();
342 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
343 unsafe private static extern double ParseImpl (byte *byte_ptr
);
345 public static bool TryParse (string s
,
347 IFormatProvider provider
,
351 result
= Parse (s
, style
, provider
);
359 public override string ToString ()
361 return ToString (null, null);
364 public string ToString (IFormatProvider fp
)
366 return ToString (null, fp
);
369 public string ToString (string format
)
371 return ToString (format
, null);
374 public string ToString (string format
, IFormatProvider fp
)
376 NumberFormatInfo nfi
= fp
!= null ? fp
.GetFormat (typeof (NumberFormatInfo
)) as NumberFormatInfo
: null;
377 return DoubleFormatter
.NumberToString (format
, nfi
, m_value
);
380 // =========== IConvertible Methods =========== //
382 public TypeCode
GetTypeCode ()
384 return TypeCode
.Double
;
387 object IConvertible
.ToType (Type conversionType
, IFormatProvider provider
)
389 return System
.Convert
.ToType(m_value
, conversionType
, provider
);
392 bool IConvertible
.ToBoolean (IFormatProvider provider
)
394 return System
.Convert
.ToBoolean(m_value
);
397 byte IConvertible
.ToByte (IFormatProvider provider
)
399 return System
.Convert
.ToByte(m_value
);
402 char IConvertible
.ToChar (IFormatProvider provider
)
404 throw new InvalidCastException();
407 DateTime IConvertible
.ToDateTime (IFormatProvider provider
)
409 throw new InvalidCastException();
412 decimal IConvertible
.ToDecimal (IFormatProvider provider
)
414 return System
.Convert
.ToDecimal(m_value
);
417 double IConvertible
.ToDouble (IFormatProvider provider
)
419 return System
.Convert
.ToDouble(m_value
);
422 short IConvertible
.ToInt16 (IFormatProvider provider
)
424 return System
.Convert
.ToInt16(m_value
);
427 int IConvertible
.ToInt32 (IFormatProvider provider
)
429 return System
.Convert
.ToInt32(m_value
);
432 long IConvertible
.ToInt64 (IFormatProvider provider
)
434 return System
.Convert
.ToInt64(m_value
);
437 sbyte IConvertible
.ToSByte (IFormatProvider provider
)
439 return System
.Convert
.ToSByte(m_value
);
442 float IConvertible
.ToSingle (IFormatProvider provider
)
444 return System
.Convert
.ToSingle(m_value
);
448 string IConvertible.ToString (IFormatProvider provider)
450 return ToString(provider);
454 ushort IConvertible
.ToUInt16 (IFormatProvider provider
)
456 return System
.Convert
.ToUInt16(m_value
);
459 uint IConvertible
.ToUInt32 (IFormatProvider provider
)
461 return System
.Convert
.ToUInt32(m_value
);
464 ulong IConvertible
.ToUInt64 (IFormatProvider provider
)
466 return System
.Convert
.ToUInt64(m_value
);