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;
39 using System.Runtime.ConstrainedExecution;
46 [System.Runtime.InteropServices.ComVisible (true)]
48 public struct Double : IComparable, IFormattable, IConvertible
50 , IComparable <double>, IEquatable <double>
53 public const double Epsilon = 4.9406564584124650e-324;
54 public const double MaxValue = 1.7976931348623157e308;
55 public const double MinValue = -1.7976931348623157e308;
56 public const double NaN = 0.0d / 0.0d;
57 public const double NegativeInfinity = -1.0d / 0.0d;
58 public const double PositiveInfinity = 1.0d / 0.0d;
60 internal double m_value;
62 public int CompareTo (object value)
67 if (!(value is System.Double))
68 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
70 double dv = (double)value;
72 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
75 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
90 if (m_value > dv) return 1;
91 else if (m_value < dv) return -1;
95 public override bool Equals (object obj)
97 if (!(obj is System.Double))
100 double value = (double) obj;
103 return IsNaN (m_value);
105 return (value == m_value);
109 public int CompareTo (double value)
111 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
114 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
129 if (m_value > value) return 1;
130 else if (m_value < value) return -1;
134 public bool Equals (double obj)
143 return obj == m_value;
147 public override unsafe int GetHashCode ()
150 return (*((long*)&d)).GetHashCode ();
153 public static bool IsInfinity (double d)
155 return (d == PositiveInfinity || d == NegativeInfinity);
159 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
161 public static bool IsNaN (double d)
163 #pragma warning disable 1718
165 #pragma warning restore
168 public static bool IsNegativeInfinity (double d)
170 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
173 public static bool IsPositiveInfinity (double d)
175 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
178 public static double Parse (string s)
180 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
183 public static double Parse (string s, IFormatProvider provider)
185 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), provider);
188 public static double Parse (string s, NumberStyles style)
190 return Parse (s, style, null);
193 // We're intentionally using constants here to avoid some bigger headaches in mcs.
194 // This struct must be compiled before System.Enum so we can't use enums here.
195 private const int State_AllowSign = 1;
196 private const int State_Digits = 2;
197 private const int State_Decimal = 3;
198 private const int State_ExponentSign = 4;
199 private const int State_Exponent = 5;
200 private const int State_ConsumeWhiteSpace = 6;
201 private const int State_Exit = 7;
203 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
208 if (!Parse (s, style, provider, false, out result, out exc))
214 // FIXME: check if digits are group in correct numbers between the group separators
215 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
222 exc = new ArgumentNullException ("s");
227 exc = new FormatException ();
231 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
232 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
233 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
234 throw new ArgumentException (msg);
237 if (style > NumberStyles.Any) {
239 exc = new ArgumentException();
243 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
244 if (format == null) throw new Exception("How did this happen?");
246 if (s == format.NaNSymbol) {
250 if (s == format.PositiveInfinitySymbol) {
251 result = Double.PositiveInfinity;
254 if (s == format.NegativeInfinitySymbol) {
255 result = Double.NegativeInfinity;
260 // validate and prepare string for C
263 byte [] b = new byte [len + 1];
268 if ((style & NumberStyles.AllowLeadingWhite) != 0){
269 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
274 exc = Int32.GetFormatException ();
279 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
284 int state = State_AllowSign;
289 string decimal_separator = null;
290 string group_separator = null;
291 string currency_symbol = null;
292 int decimal_separator_len = 0;
293 int group_separator_len = 0;
294 int currency_symbol_len = 0;
295 if ((style & NumberStyles.AllowDecimalPoint) != 0){
296 decimal_separator = format.NumberDecimalSeparator;
297 decimal_separator_len = decimal_separator.Length;
299 if ((style & NumberStyles.AllowThousands) != 0){
300 group_separator = format.NumberGroupSeparator;
301 group_separator_len = group_separator.Length;
303 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
304 currency_symbol = format.CurrencySymbol;
305 currency_symbol_len = currency_symbol.Length;
307 string positive = format.PositiveSign;
308 string negative = format.NegativeSign;
310 for (; sidx < len; sidx++){
319 case State_AllowSign:
320 if ((style & NumberStyles.AllowLeadingSign) != 0){
321 if (c == positive [0] &&
322 s.Substring (sidx, positive.Length) == positive){
323 state = State_Digits;
324 sidx += positive.Length-1;
328 if (c == negative [0] &&
329 s.Substring (sidx, negative.Length) == negative){
330 state = State_Digits;
331 b [didx++] = (byte) '-';
332 sidx += negative.Length-1;
336 state = State_Digits;
337 goto case State_Digits;
340 if (Char.IsDigit (c)){
341 b [didx++] = (byte) c;
344 if (c == 'e' || c == 'E')
345 goto case State_Decimal;
347 if (decimal_separator != null &&
348 decimal_separator [0] == c) {
349 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
350 b [didx++] = (byte) '.';
351 sidx += decimal_separator_len-1;
352 state = State_Decimal;
356 if (group_separator != null &&
357 group_separator [0] == c){
358 if (s.Substring (sidx, group_separator_len) ==
360 sidx += group_separator_len-1;
361 state = State_Digits;
365 if (currency_symbol != null &&
366 currency_symbol [0] == c){
367 if (s.Substring (sidx, currency_symbol_len) ==
369 sidx += currency_symbol_len-1;
370 state = State_Digits;
375 if (Char.IsWhiteSpace (c))
376 goto case State_ConsumeWhiteSpace;
379 exc = new FormatException ("Unknown char: " + c);
383 if (Char.IsDigit (c)){
384 b [didx++] = (byte) c;
388 if (c == 'e' || c == 'E'){
389 if ((style & NumberStyles.AllowExponent) == 0) {
391 exc = new FormatException ("Unknown char: " + c);
394 b [didx++] = (byte) c;
395 state = State_ExponentSign;
399 if (Char.IsWhiteSpace (c))
400 goto case State_ConsumeWhiteSpace;
403 exc = new FormatException ("Unknown char: " + c);
406 case State_ExponentSign:
407 if (Char.IsDigit (c)){
408 state = State_Exponent;
409 goto case State_Exponent;
412 if (c == positive [0] &&
413 s.Substring (sidx, positive.Length) == positive){
414 state = State_Digits;
415 sidx += positive.Length-1;
419 if (c == negative [0] &&
420 s.Substring (sidx, negative.Length) == negative){
421 state = State_Digits;
422 b [didx++] = (byte) '-';
423 sidx += negative.Length-1;
427 if (Char.IsWhiteSpace (c))
428 goto case State_ConsumeWhiteSpace;
431 exc = new FormatException ("Unknown char: " + c);
435 if (Char.IsDigit (c)){
436 b [didx++] = (byte) c;
440 if (Char.IsWhiteSpace (c))
441 goto case State_ConsumeWhiteSpace;
444 exc = new FormatException ("Unknown char: " + c);
447 case State_ConsumeWhiteSpace:
448 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
449 state = State_ConsumeWhiteSpace;
454 exc = new FormatException ("Unknown char");
458 if (state == State_Exit)
464 fixed (byte *p = &b [0]){
466 if (!ParseImpl (p, out retVal)) {
468 exc = Int32.GetFormatException ();
471 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
473 exc = new OverflowException ();
483 [MethodImplAttribute(MethodImplOptions.InternalCall)]
484 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
486 public static bool TryParse (string s,
488 IFormatProvider provider,
492 if (!Parse (s, style, provider, true, out result, out exc)) {
500 public static bool TryParse (string s, out double result)
502 return TryParse (s, NumberStyles.Any, null, out result);
505 public override string ToString ()
507 return NumberFormatter.NumberToString (m_value, null);
510 public string ToString (IFormatProvider provider)
512 return NumberFormatter.NumberToString (m_value, provider);
515 public string ToString (string format)
517 return ToString (format, null);
520 public string ToString (string format, IFormatProvider provider)
522 return NumberFormatter.NumberToString (format, m_value, provider);
525 // =========== IConvertible Methods =========== //
527 public TypeCode GetTypeCode ()
529 return TypeCode.Double;
532 object IConvertible.ToType (Type type, IFormatProvider provider)
534 return System.Convert.ToType (m_value, type, provider);
537 bool IConvertible.ToBoolean (IFormatProvider provider)
539 return System.Convert.ToBoolean (m_value);
542 byte IConvertible.ToByte (IFormatProvider provider)
544 return System.Convert.ToByte (m_value);
547 char IConvertible.ToChar (IFormatProvider provider)
549 throw new InvalidCastException ();
552 DateTime IConvertible.ToDateTime (IFormatProvider provider)
554 throw new InvalidCastException ();
557 decimal IConvertible.ToDecimal (IFormatProvider provider)
559 return System.Convert.ToDecimal (m_value);
562 double IConvertible.ToDouble (IFormatProvider provider)
564 return System.Convert.ToDouble (m_value);
567 short IConvertible.ToInt16 (IFormatProvider provider)
569 return System.Convert.ToInt16 (m_value);
572 int IConvertible.ToInt32 (IFormatProvider provider)
574 return System.Convert.ToInt32 (m_value);
577 long IConvertible.ToInt64 (IFormatProvider provider)
579 return System.Convert.ToInt64 (m_value);
583 #pragma warning disable 3019
584 [CLSCompliant (false)]
586 sbyte IConvertible.ToSByte (IFormatProvider provider)
588 return System.Convert.ToSByte (m_value);
591 #pragma warning restore 3019
594 float IConvertible.ToSingle (IFormatProvider provider)
596 return System.Convert.ToSingle (m_value);
600 #pragma warning disable 3019
601 [CLSCompliant (false)]
603 ushort IConvertible.ToUInt16 (IFormatProvider provider)
605 return System.Convert.ToUInt16 (m_value);
608 #pragma warning restore 3019
612 #pragma warning disable 3019
613 [CLSCompliant (false)]
615 uint IConvertible.ToUInt32 (IFormatProvider provider)
617 return System.Convert.ToUInt32 (m_value);
620 #pragma warning restore 3019
624 #pragma warning disable 3019
625 [CLSCompliant (false)]
627 ulong IConvertible.ToUInt64 (IFormatProvider provider)
629 return System.Convert.ToUInt64 (m_value);
632 #pragma warning restore 3019