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;
45 public struct Double : IComparable, IFormattable, IConvertible
47 , IComparable <double>, IEquatable <double>
50 public const double Epsilon = 4.9406564584124650e-324;
51 public const double MaxValue = 1.7976931348623157e308;
52 public const double MinValue = -1.7976931348623157e308;
53 public const double NaN = 0.0d / 0.0d;
54 public const double NegativeInfinity = -1.0d / 0.0d;
55 public const double PositiveInfinity = 1.0d / 0.0d;
57 internal double m_value;
59 public int CompareTo (object v)
64 if (!(v is System.Double))
65 throw new ArgumentException (Locale.GetText ("Value is not a System.Double"));
67 double dv = (double)v;
69 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(dv))
72 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(dv))
87 if (m_value > dv) return 1;
88 else if (m_value < dv) return -1;
92 public override bool Equals (object o)
94 if (!(o is System.Double))
97 if (IsNaN ((double)o)) {
104 return ((double) o) == m_value;
108 public int CompareTo (double value)
110 if (IsPositiveInfinity(m_value) && IsPositiveInfinity(value))
113 if (IsNegativeInfinity(m_value) && IsNegativeInfinity(value))
128 if (m_value > value) return 1;
129 else if (m_value < value) return -1;
133 public bool Equals (double value)
142 return value == m_value;
146 public override unsafe int GetHashCode ()
149 return (*((long*)&d)).GetHashCode ();
152 public static bool IsInfinity (double d)
154 return (d == PositiveInfinity || d == NegativeInfinity);
158 [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.Success)]
160 public static bool IsNaN (double d)
162 #pragma warning disable 1718
164 #pragma warning restore
167 public static bool IsNegativeInfinity (double d)
169 return (d < 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
172 public static bool IsPositiveInfinity (double d)
174 return (d > 0.0d && (d == NegativeInfinity || d == PositiveInfinity));
177 public static double Parse (string s)
179 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), null);
182 public static double Parse (string s, IFormatProvider fp)
184 return Parse (s, (NumberStyles.Float | NumberStyles.AllowThousands), fp);
187 public static double Parse (string s, NumberStyles style)
189 return Parse (s, style, null);
192 // We're intentionally using constants here to avoid some bigger headaches in mcs.
193 // This struct must be compiled before System.Enum so we can't use enums here.
194 private const int State_AllowSign = 1;
195 private const int State_Digits = 2;
196 private const int State_Decimal = 3;
197 private const int State_ExponentSign = 4;
198 private const int State_Exponent = 5;
199 private const int State_ConsumeWhiteSpace = 6;
200 private const int State_Exit = 7;
202 public static double Parse (string s, NumberStyles style, IFormatProvider provider)
207 if (!Parse (s, style, provider, false, out result, out exc))
213 // FIXME: check if digits are group in correct numbers between the group separators
214 internal static bool Parse (string s, NumberStyles style, IFormatProvider provider, bool tryParse, out double result, out Exception exc)
221 exc = new ArgumentNullException ("s");
226 exc = new FormatException ();
230 // yes it's counter intuitive (buggy?) but even TryParse actually throws in this case
231 if ((style & NumberStyles.AllowHexSpecifier) != 0) {
232 string msg = Locale.GetText ("Double doesn't support parsing with '{0}'.", "AllowHexSpecifier");
233 throw new ArgumentException (msg);
236 if (style > NumberStyles.Any) {
238 exc = new ArgumentException();
242 NumberFormatInfo format = NumberFormatInfo.GetInstance(provider);
243 if (format == null) throw new Exception("How did this happen?");
245 if (s == format.NaNSymbol) {
249 if (s == format.PositiveInfinitySymbol) {
250 result = Double.PositiveInfinity;
253 if (s == format.NegativeInfinitySymbol) {
254 result = Double.NegativeInfinity;
259 // validate and prepare string for C
262 byte [] b = new byte [len + 1];
267 if ((style & NumberStyles.AllowLeadingWhite) != 0){
268 while (sidx < len && Char.IsWhiteSpace (c = s [sidx]))
273 exc = Int32.GetFormatException ();
278 bool allow_trailing_white = ((style & NumberStyles.AllowTrailingWhite) != 0);
283 int state = State_AllowSign;
288 string decimal_separator = null;
289 string group_separator = null;
290 string currency_symbol = null;
291 int decimal_separator_len = 0;
292 int group_separator_len = 0;
293 int currency_symbol_len = 0;
294 if ((style & NumberStyles.AllowDecimalPoint) != 0){
295 decimal_separator = format.NumberDecimalSeparator;
296 decimal_separator_len = decimal_separator.Length;
298 if ((style & NumberStyles.AllowThousands) != 0){
299 group_separator = format.NumberGroupSeparator;
300 group_separator_len = group_separator.Length;
302 if ((style & NumberStyles.AllowCurrencySymbol) != 0){
303 currency_symbol = format.CurrencySymbol;
304 currency_symbol_len = currency_symbol.Length;
306 string positive = format.PositiveSign;
307 string negative = format.NegativeSign;
309 for (; sidx < len; sidx++){
318 case State_AllowSign:
319 if ((style & NumberStyles.AllowLeadingSign) != 0){
320 if (c == positive [0] &&
321 s.Substring (sidx, positive.Length) == positive){
322 state = State_Digits;
323 sidx += positive.Length-1;
327 if (c == negative [0] &&
328 s.Substring (sidx, negative.Length) == negative){
329 state = State_Digits;
330 b [didx++] = (byte) '-';
331 sidx += negative.Length-1;
335 state = State_Digits;
336 goto case State_Digits;
339 if (Char.IsDigit (c)){
340 b [didx++] = (byte) c;
343 if (c == 'e' || c == 'E')
344 goto case State_Decimal;
346 if (decimal_separator != null &&
347 decimal_separator [0] == c) {
348 if (String.CompareOrdinal (s, sidx, decimal_separator, 0, decimal_separator_len) == 0) {
349 b [didx++] = (byte) '.';
350 sidx += decimal_separator_len-1;
351 state = State_Decimal;
355 if (group_separator != null &&
356 group_separator [0] == c){
357 if (s.Substring (sidx, group_separator_len) ==
359 sidx += group_separator_len-1;
360 state = State_Digits;
364 if (currency_symbol != null &&
365 currency_symbol [0] == c){
366 if (s.Substring (sidx, currency_symbol_len) ==
368 sidx += currency_symbol_len-1;
369 state = State_Digits;
374 if (Char.IsWhiteSpace (c))
375 goto case State_ConsumeWhiteSpace;
378 exc = new FormatException ("Unknown char: " + c);
382 if (Char.IsDigit (c)){
383 b [didx++] = (byte) c;
387 if (c == 'e' || c == 'E'){
388 if ((style & NumberStyles.AllowExponent) == 0) {
390 exc = new FormatException ("Unknown char: " + c);
393 b [didx++] = (byte) c;
394 state = State_ExponentSign;
398 if (Char.IsWhiteSpace (c))
399 goto case State_ConsumeWhiteSpace;
402 exc = new FormatException ("Unknown char: " + c);
405 case State_ExponentSign:
406 if (Char.IsDigit (c)){
407 state = State_Exponent;
408 goto case State_Exponent;
411 if (c == positive [0] &&
412 s.Substring (sidx, positive.Length) == positive){
413 state = State_Digits;
414 sidx += positive.Length-1;
418 if (c == negative [0] &&
419 s.Substring (sidx, negative.Length) == negative){
420 state = State_Digits;
421 b [didx++] = (byte) '-';
422 sidx += negative.Length-1;
426 if (Char.IsWhiteSpace (c))
427 goto case State_ConsumeWhiteSpace;
430 exc = new FormatException ("Unknown char: " + c);
434 if (Char.IsDigit (c)){
435 b [didx++] = (byte) c;
439 if (Char.IsWhiteSpace (c))
440 goto case State_ConsumeWhiteSpace;
443 exc = new FormatException ("Unknown char: " + c);
446 case State_ConsumeWhiteSpace:
447 if (allow_trailing_white && Char.IsWhiteSpace (c)) {
453 exc = new FormatException ("Unknown char");
457 if (state == State_Exit)
463 fixed (byte *p = &b [0]){
465 if (!ParseImpl (p, out retVal)) {
467 exc = Int32.GetFormatException ();
470 if (IsPositiveInfinity(retVal) || IsNegativeInfinity(retVal)) {
472 exc = new OverflowException ();
482 [MethodImplAttribute(MethodImplOptions.InternalCall)]
483 unsafe private static extern bool ParseImpl (byte *byte_ptr, out double value);
485 public static bool TryParse (string s,
487 IFormatProvider provider,
491 if (!Parse (s, style, provider, true, out result, out exc)) {
499 public static bool TryParse (string s, out double result)
501 return TryParse (s, NumberStyles.Any, null, out result);
504 public override string ToString ()
506 return ToString (null, null);
509 public string ToString (IFormatProvider fp)
511 return ToString (null, fp);
514 public string ToString (string format)
516 return ToString (format, null);
519 public string ToString (string format, IFormatProvider fp)
521 NumberFormatInfo nfi = NumberFormatInfo.GetInstance (fp);
522 return NumberFormatter.NumberToString (format, m_value, nfi);
525 // =========== IConvertible Methods =========== //
527 public TypeCode GetTypeCode ()
529 return TypeCode.Double;
532 object IConvertible.ToType (Type conversionType, IFormatProvider provider)
534 return System.Convert.ToType(m_value, conversionType, 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);
582 sbyte IConvertible.ToSByte (IFormatProvider provider)
584 return System.Convert.ToSByte(m_value);
587 float IConvertible.ToSingle (IFormatProvider provider)
589 return System.Convert.ToSingle(m_value);
593 string IConvertible.ToString (IFormatProvider provider)
595 return ToString(provider);
599 ushort IConvertible.ToUInt16 (IFormatProvider provider)
601 return System.Convert.ToUInt16(m_value);
604 uint IConvertible.ToUInt32 (IFormatProvider provider)
606 return System.Convert.ToUInt32(m_value);
609 ulong IConvertible.ToUInt64 (IFormatProvider provider)
611 return System.Convert.ToUInt64(m_value);