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
;
37 using System
.Runtime
.ConstrainedExecution
;
42 [System
.Runtime
.InteropServices
.ComVisible (true)]
43 public struct Double
: IComparable
, IFormattable
, IConvertible
, IComparable
<double>, IEquatable
<double>
45 public const double Epsilon
= 4.9406564584124650e-324;
46 public const double MaxValue
= 1.7976931348623157e308
;
47 public const double MinValue
= -1.7976931348623157e308
;
48 public const double NaN
= 0.0d
/ 0.0d
;
49 public const double NegativeInfinity
= -1.0d
/ 0.0d
;
50 public const double PositiveInfinity
= 1.0d
/ 0.0d
;
52 internal double m_value
;
54 public int CompareTo (object value)
59 if (!(value is System
.Double
))
60 throw new ArgumentException (Locale
.GetText ("Value is not a System.Double"));
62 double dv
= (double)value;
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 obj
)
89 if (!(obj
is System
.Double
))
92 double value = (double) obj
;
95 return IsNaN (m_value
);
97 return (value == m_value
);
100 public int CompareTo (double value)
102 if (IsPositiveInfinity(m_value
) && IsPositiveInfinity(value))
105 if (IsNegativeInfinity(m_value
) && IsNegativeInfinity(value))
120 if (m_value
> value) return 1;
121 else if (m_value
< value) return -1;
125 public bool Equals (double obj
)
134 return obj
== m_value
;
137 public override unsafe int GetHashCode ()
140 return (*((long*)&d
)).GetHashCode ();
144 public static bool operator==(double a
, double b
)
149 public static bool operator!=(double a
, double b
)
154 public static bool operator>(double a
, double b
)
159 public static bool operator>=(double a
, double b
)
164 public static bool operator<(double a
, double b
)
169 public static bool operator<=(double a
, double b
)
175 public static bool IsInfinity (double d
)
177 return (d
== PositiveInfinity
|| d
== NegativeInfinity
);
180 [ReliabilityContractAttribute (Consistency
.WillNotCorruptState
, Cer
.Success
)]
181 public static bool IsNaN (double d
)
183 #pragma warning disable 1718
185 #pragma warning restore
188 public static bool IsNegativeInfinity (double d
)
190 return (d
< 0.0d
&& (d
== NegativeInfinity
|| d
== PositiveInfinity
));
193 public static bool IsPositiveInfinity (double d
)
195 return (d
> 0.0d
&& (d
== NegativeInfinity
|| d
== PositiveInfinity
));
198 public static double Parse (string s
)
200 return Parse (s
, (NumberStyles
.Float
| NumberStyles
.AllowThousands
), null);
203 public static double Parse (string s
, IFormatProvider provider
)
205 return Parse (s
, (NumberStyles
.Float
| NumberStyles
.AllowThousands
), provider
);
208 public static double Parse (string s
, NumberStyles style
)
210 return Parse (s
, style
, null);
213 // We're intentionally using constants here to avoid some bigger headaches in mcs.
214 // This struct must be compiled before System.Enum so we can't use enums here.
215 private const int State_AllowSign
= 1;
216 private const int State_Digits
= 2;
217 private const int State_Decimal
= 3;
218 private const int State_ExponentSign
= 4;
219 private const int State_Exponent
= 5;
220 private const int State_ConsumeWhiteSpace
= 6;
221 private const int State_Exit
= 7;
223 public static double Parse (string s
, NumberStyles style
, IFormatProvider provider
)
228 if (!Parse (s
, style
, provider
, false, out result
, out exc
))
234 // FIXME: check if digits are group in correct numbers between the group separators
235 internal static bool Parse (string s
, NumberStyles style
, IFormatProvider provider
, bool tryParse
, out double result
, out Exception exc
)
242 exc
= new ArgumentNullException ("s");
247 exc
= new FormatException ();
250 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
251 if ((style
& NumberStyles
.AllowHexSpecifier
) != 0) {
252 string msg
= Locale
.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
253 throw new ArgumentException (msg
);
255 if (style
> NumberStyles
.Any
) {
257 exc
= new ArgumentException();
261 NumberFormatInfo format
= NumberFormatInfo
.GetInstance(provider
);
262 if (format
== null) throw new Exception("How did this happen?");
265 // validate and prepare string for C
271 bool allow_leading_white
= (style
& NumberStyles
.AllowLeadingWhite
) != 0;
272 bool allow_trailing_white
= ((style
& NumberStyles
.AllowTrailingWhite
) != 0);
274 if (allow_leading_white
) {
275 while (sidx
< len
&& Char
.IsWhiteSpace (s
[sidx
]))
280 exc
= Int32
.GetFormatException ();
284 int sEndPos
= s
.Length
- 1;
285 if (allow_trailing_white
)
286 while (Char
.IsWhiteSpace (s
[sEndPos
]))
289 if (TryParseStringConstant (format
.NaNSymbol
, s
, sidx
, sEndPos
)) {
293 if (TryParseStringConstant (format
.PositiveInfinitySymbol
, s
, sidx
, sEndPos
)) {
294 result
= double.PositiveInfinity
;
297 if (TryParseStringConstant (format
.NegativeInfinitySymbol
, s
, sidx
, sEndPos
)) {
298 result
= double.NegativeInfinity
;
302 byte [] b
= new byte [len
+ 1];
307 int state
= State_AllowSign
;
312 string decimal_separator
= null;
313 string group_separator
= null;
314 string currency_symbol
= null;
315 int decimal_separator_len
= 0;
316 int group_separator_len
= 0;
317 int currency_symbol_len
= 0;
318 if ((style
& NumberStyles
.AllowDecimalPoint
) != 0){
319 decimal_separator
= format
.NumberDecimalSeparator
;
320 decimal_separator_len
= decimal_separator
.Length
;
322 if ((style
& NumberStyles
.AllowThousands
) != 0){
323 group_separator
= format
.NumberGroupSeparator
;
324 group_separator_len
= group_separator
.Length
;
326 if ((style
& NumberStyles
.AllowCurrencySymbol
) != 0){
327 currency_symbol
= format
.CurrencySymbol
;
328 currency_symbol_len
= currency_symbol
.Length
;
330 string positive
= format
.PositiveSign
;
331 string negative
= format
.NegativeSign
;
333 for (; sidx
< len
; sidx
++){
342 case State_AllowSign
:
343 if ((style
& NumberStyles
.AllowLeadingSign
) != 0){
344 if (c
== positive
[0] &&
345 s
.Substring (sidx
, positive
.Length
) == positive
){
346 state
= State_Digits
;
347 sidx
+= positive
.Length
-1;
351 if (c
== negative
[0] &&
352 s
.Substring (sidx
, negative
.Length
) == negative
){
353 state
= State_Digits
;
354 b
[didx
++] = (byte) '-';
355 sidx
+= negative
.Length
-1;
359 state
= State_Digits
;
360 goto case State_Digits
;
363 if (Char
.IsDigit (c
)){
364 b
[didx
++] = (byte) c
;
367 if (c
== 'e' || c
== 'E')
368 goto case State_Decimal
;
370 if (decimal_separator_len
> 0 &&
371 decimal_separator
[0] == c
) {
372 if (String
.CompareOrdinal (s
, sidx
, decimal_separator
, 0, decimal_separator_len
) == 0) {
373 b
[didx
++] = (byte) '.';
374 sidx
+= decimal_separator_len
-1;
375 state
= State_Decimal
;
379 if (group_separator_len
> 0 &&
380 group_separator
[0] == c
){
381 if (s
.Substring (sidx
, group_separator_len
) ==
383 sidx
+= group_separator_len
-1;
384 state
= State_Digits
;
388 if (currency_symbol_len
> 0 &&
389 currency_symbol
[0] == c
){
390 if (s
.Substring (sidx
, currency_symbol_len
) ==
392 sidx
+= currency_symbol_len
-1;
393 state
= State_Digits
;
398 if (Char
.IsWhiteSpace (c
))
399 goto case State_ConsumeWhiteSpace
;
402 exc
= new FormatException ("Unknown char: " + c
);
406 if (Char
.IsDigit (c
)){
407 b
[didx
++] = (byte) c
;
411 if (c
== 'e' || c
== 'E'){
412 if ((style
& NumberStyles
.AllowExponent
) == 0) {
414 exc
= new FormatException ("Unknown char: " + c
);
417 b
[didx
++] = (byte) c
;
418 state
= State_ExponentSign
;
422 if (Char
.IsWhiteSpace (c
))
423 goto case State_ConsumeWhiteSpace
;
426 exc
= new FormatException ("Unknown char: " + c
);
429 case State_ExponentSign
:
430 if (Char
.IsDigit (c
)){
431 state
= State_Exponent
;
432 goto case State_Exponent
;
435 if (c
== positive
[0] &&
436 s
.Substring (sidx
, positive
.Length
) == positive
){
437 state
= State_Digits
;
438 sidx
+= positive
.Length
-1;
442 if (c
== negative
[0] &&
443 s
.Substring (sidx
, negative
.Length
) == negative
){
444 state
= State_Digits
;
445 b
[didx
++] = (byte) '-';
446 sidx
+= negative
.Length
-1;
450 if (Char
.IsWhiteSpace (c
))
451 goto case State_ConsumeWhiteSpace
;
454 exc
= new FormatException ("Unknown char: " + c
);
458 if (Char
.IsDigit (c
)){
459 b
[didx
++] = (byte) c
;
463 if (Char
.IsWhiteSpace (c
))
464 goto case State_ConsumeWhiteSpace
;
467 exc
= new FormatException ("Unknown char: " + c
);
470 case State_ConsumeWhiteSpace
:
471 if (allow_trailing_white
&& Char
.IsWhiteSpace (c
)) {
472 state
= State_ConsumeWhiteSpace
;
477 exc
= new FormatException ("Unknown char");
481 if (state
== State_Exit
)
487 fixed (byte *p
= &b
[0]){
489 if (!ParseImpl (p
, out retVal
)) {
491 exc
= Int32
.GetFormatException ();
494 if (IsPositiveInfinity(retVal
) || IsNegativeInfinity(retVal
)) {
496 exc
= new OverflowException ();
506 static bool TryParseStringConstant (string format
, string s
, int start
, int end
)
508 return end
- start
+ 1 == format
.Length
&& String
.CompareOrdinal (format
, 0, s
, start
, format
.Length
) == 0;
511 [MethodImplAttribute(MethodImplOptions
.InternalCall
)]
512 unsafe private static extern bool ParseImpl (byte *byte_ptr
, out double value);
514 public static bool TryParse (string s
,
516 IFormatProvider provider
,
520 if (!Parse (s
, style
, provider
, true, out result
, out exc
)) {
528 public static bool TryParse (string s
, out double result
)
530 return TryParse (s
, NumberStyles
.Any
, null, out result
);
533 public override string ToString ()
535 return NumberFormatter
.NumberToString (m_value
, null);
538 public string ToString (IFormatProvider provider
)
540 return NumberFormatter
.NumberToString (m_value
, provider
);
543 public string ToString (string format
)
545 return ToString (format
, null);
548 public string ToString (string format
, IFormatProvider provider
)
550 return NumberFormatter
.NumberToString (format
, m_value
, provider
);
553 // =========== IConvertible Methods =========== //
555 public TypeCode
GetTypeCode ()
557 return TypeCode
.Double
;
560 object IConvertible
.ToType (Type targetType
, IFormatProvider provider
)
562 if (targetType
== null)
563 throw new ArgumentNullException ("targetType");
564 return System
.Convert
.ToType (m_value
, targetType
, provider
, false);
567 bool IConvertible
.ToBoolean (IFormatProvider provider
)
569 return System
.Convert
.ToBoolean (m_value
);
572 byte IConvertible
.ToByte (IFormatProvider provider
)
574 return System
.Convert
.ToByte (m_value
);
577 char IConvertible
.ToChar (IFormatProvider provider
)
579 throw new InvalidCastException ();
582 DateTime IConvertible
.ToDateTime (IFormatProvider provider
)
584 throw new InvalidCastException ();
587 decimal IConvertible
.ToDecimal (IFormatProvider provider
)
589 return System
.Convert
.ToDecimal (m_value
);
592 double IConvertible
.ToDouble (IFormatProvider provider
)
594 return System
.Convert
.ToDouble (m_value
);
597 short IConvertible
.ToInt16 (IFormatProvider provider
)
599 return System
.Convert
.ToInt16 (m_value
);
602 int IConvertible
.ToInt32 (IFormatProvider provider
)
604 return System
.Convert
.ToInt32 (m_value
);
607 long IConvertible
.ToInt64 (IFormatProvider provider
)
609 return System
.Convert
.ToInt64 (m_value
);
612 sbyte IConvertible
.ToSByte (IFormatProvider provider
)
614 return System
.Convert
.ToSByte (m_value
);
617 float IConvertible
.ToSingle (IFormatProvider provider
)
619 return System
.Convert
.ToSingle (m_value
);
622 ushort IConvertible
.ToUInt16 (IFormatProvider provider
)
624 return System
.Convert
.ToUInt16 (m_value
);
626 uint IConvertible
.ToUInt32 (IFormatProvider provider
)
628 return System
.Convert
.ToUInt32 (m_value
);
630 ulong IConvertible
.ToUInt64 (IFormatProvider provider
)
632 return System
.Convert
.ToUInt64 (m_value
);