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 v)
67 if (!(v is System.Double))
68 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
70 double dv = (double)v;
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 o)
97 if (!(o is System.Double))
100 if (IsNaN ((double)o)) {
107 return ((double) o) == m_value;
111 public int CompareTo (double value)
113 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
116 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
131 if (m_value > value) return 1;
132 else if (m_value < value) return -1;
136 public bool Equals (double value)
145 return value == m_value;
149 public override unsafe int GetHashCode ()
152 return (*((long*)&d)).GetHashCode ();
155 public static bool IsInfinity (double d)
157 return (d == PositiveInfinity || d == NegativeInfinity);
161 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
163 public static bool IsNaN (double d)
165 #pragma warning disable 1718
167 #pragma warning restore
170 public static bool IsNegativeInfinity (double d)
172 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
175 public static bool IsPositiveInfinity (double d)
177 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
180 public static double Parse (string s)
182 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
185 public static double Parse (string s, IFormatProvider fp)
187 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
190 public static double Parse (string s, NumberStyles style)
192 return Parse (s, style, null);
195 // We're intentionally using constants here to avoid some bigger headaches in mcs.
196 // This struct must be compiled before System.Enum so we can't use enums here.
197 private const int State_AllowSign = 1;
198 private const int State_Digits = 2;
199 private const int State_Decimal = 3;
200 private const int State_ExponentSign = 4;
201 private const int State_Exponent = 5;
202 private const int State_ConsumeWhiteSpace = 6;
203 private const int State_Exit = 7;
205 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
210 if (!Parse (s, style, provider, false, out result, out exc))
216 // FIXME: check if digits are group in correct numbers between the group separators
217 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
224 exc = new ArgumentNullException ("s");
229 exc = new FormatException ();
233 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
234 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
235 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
236 throw new ArgumentException (msg);
239 if (style > NumberStyles.Any) {
241 exc = new ArgumentException();
245 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
246 if (format == null) throw new Exception("How did this happen?");
248 if (s == format.NaNSymbol) {
252 if (s == format.PositiveInfinitySymbol) {
253 result = Double.PositiveInfinity;
256 if (s == format.NegativeInfinitySymbol) {
257 result = Double.NegativeInfinity;
262 // validate and prepare string for C
265 byte [] b = new byte [len + 1];
270 if ((style & NumberStyles.AllowLeadingWhite) != 0){
271 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
276 exc = Int32.GetFormatException ();
281 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
286 int state = State_AllowSign;
291 string decimal_separator = null;
292 string group_separator = null;
293 string currency_symbol = null;
294 int decimal_separator_len = 0;
295 int group_separator_len = 0;
296 int currency_symbol_len = 0;
297 if ((style & NumberStyles.AllowDecimalPoint) != 0){
298 decimal_separator = format.NumberDecimalSeparator;
299 decimal_separator_len = decimal_separator.Length;
301 if ((style & NumberStyles.AllowThousands) != 0){
302 group_separator = format.NumberGroupSeparator;
303 group_separator_len = group_separator.Length;
305 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
306 currency_symbol = format.CurrencySymbol;
307 currency_symbol_len = currency_symbol.Length;
309 string positive = format.PositiveSign;
310 string negative = format.NegativeSign;
312 for (; sidx < len; sidx++){
321 case State_AllowSign:
322 if ((style & NumberStyles.AllowLeadingSign) != 0){
323 if (c == positive [0] &&
324 s.Substring (sidx, positive.Length) == positive){
325 state = State_Digits;
326 sidx += positive.Length-1;
330 if (c == negative [0] &&
331 s.Substring (sidx, negative.Length) == negative){
332 state = State_Digits;
333 b [didx++] = (byte) '-';
334 sidx += negative.Length-1;
338 state = State_Digits;
339 goto case State_Digits;
342 if (Char.IsDigit (c)){
343 b [didx++] = (byte) c;
346 if (c == 'e' || c == 'E')
347 goto case State_Decimal;
349 if (decimal_separator != null &&
350 decimal_separator [0] == c) {
351 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
352 b [didx++] = (byte) '.';
353 sidx += decimal_separator_len-1;
354 state = State_Decimal;
358 if (group_separator != null &&
359 group_separator [0] == c){
360 if (s.Substring (sidx, group_separator_len) ==
362 sidx += group_separator_len-1;
363 state = State_Digits;
367 if (currency_symbol != null &&
368 currency_symbol [0] == c){
369 if (s.Substring (sidx, currency_symbol_len) ==
371 sidx += currency_symbol_len-1;
372 state = State_Digits;
377 if (Char.IsWhiteSpace (c))
378 goto case State_ConsumeWhiteSpace;
381 exc = new FormatException ("Unknown char: " + c);
385 if (Char.IsDigit (c)){
386 b [didx++] = (byte) c;
390 if (c == 'e' || c == 'E'){
391 if ((style & NumberStyles.AllowExponent) == 0) {
393 exc = new FormatException ("Unknown char: " + c);
396 b [didx++] = (byte) c;
397 state = State_ExponentSign;
401 if (Char.IsWhiteSpace (c))
402 goto case State_ConsumeWhiteSpace;
405 exc = new FormatException ("Unknown char: " + c);
408 case State_ExponentSign:
409 if (Char.IsDigit (c)){
410 state = State_Exponent;
411 goto case State_Exponent;
414 if (c == positive [0] &&
415 s.Substring (sidx, positive.Length) == positive){
416 state = State_Digits;
417 sidx += positive.Length-1;
421 if (c == negative [0] &&
422 s.Substring (sidx, negative.Length) == negative){
423 state = State_Digits;
424 b [didx++] = (byte) '-';
425 sidx += negative.Length-1;
429 if (Char.IsWhiteSpace (c))
430 goto case State_ConsumeWhiteSpace;
433 exc = new FormatException ("Unknown char: " + c);
437 if (Char.IsDigit (c)){
438 b [didx++] = (byte) c;
442 if (Char.IsWhiteSpace (c))
443 goto case State_ConsumeWhiteSpace;
446 exc = new FormatException ("Unknown char: " + c);
449 case State_ConsumeWhiteSpace:
450 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
451 state = State_ConsumeWhiteSpace;
456 exc = new FormatException ("Unknown char");
460 if (state == State_Exit)
466 fixed (byte *p = &b [0]){
468 if (!ParseImpl (p, out retVal)) {
470 exc = Int32.GetFormatException ();
473 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
475 exc = new OverflowException ();
485 [MethodImplAttribute(MethodImplOptions.InternalCall)]
486 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
488 public static bool TryParse (string s,
490 IFormatProvider provider,
494 if (!Parse (s, style, provider, true, out result, out exc)) {
502 public static bool TryParse (string s, out double result)
504 return TryParse (s, NumberStyles.Any, null, out result);
507 public override string ToString ()
509 return ToString (null, null);
512 public string ToString (IFormatProvider fp)
514 return ToString (null, fp);
517 public string ToString (string format)
519 return ToString (format, null);
522 public string ToString (string format, IFormatProvider fp)
524 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
525 return NumberFormatter.NumberToString (format, m_value, nfi);
528 // =========== IConvertible Methods =========== //
530 public TypeCode GetTypeCode ()
532 return TypeCode.Double;
535 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
537 return System.Convert.ToType(m_value, conversionType, provider);
540 bool IConvertible.ToBoolean (IFormatProvider provider)
542 return System.Convert.ToBoolean(m_value);
545 byte IConvertible.ToByte (IFormatProvider provider)
547 return System.Convert.ToByte(m_value);
550 char IConvertible.ToChar (IFormatProvider provider)
552 throw new InvalidCastException();
555 DateTime IConvertible.ToDateTime (IFormatProvider provider)
557 throw new InvalidCastException();
560 decimal IConvertible.ToDecimal (IFormatProvider provider)
562 return System.Convert.ToDecimal(m_value);
565 double IConvertible.ToDouble (IFormatProvider provider)
567 return System.Convert.ToDouble(m_value);
570 short IConvertible.ToInt16 (IFormatProvider provider)
572 return System.Convert.ToInt16(m_value);
575 int IConvertible.ToInt32 (IFormatProvider provider)
577 return System.Convert.ToInt32(m_value);
580 long IConvertible.ToInt64 (IFormatProvider provider)
582 return System.Convert.ToInt64(m_value);
585 sbyte IConvertible.ToSByte (IFormatProvider provider)
587 return System.Convert.ToSByte(m_value);
590 float IConvertible.ToSingle (IFormatProvider provider)
592 return System.Convert.ToSingle(m_value);
596 string IConvertible.ToString (IFormatProvider provider)
598 return ToString(provider);
602 ushort IConvertible.ToUInt16 (IFormatProvider provider)
604 return System.Convert.ToUInt16(m_value);
607 uint IConvertible.ToUInt32 (IFormatProvider provider)
609 return System.Convert.ToUInt32(m_value);
612 ulong IConvertible.ToUInt64 (IFormatProvider provider)
614 return System.Convert.ToUInt64(m_value);